Mayas (#5408)
* The Maya - data and calendar * The Maya - completed * The Maya - notifications * The Maya - favoredReligion * The Maya - comments in GreatPersonManager * The Maya - clickable notifications * The Maya - templates * The Maya - atlas * The Maya - patch1
BIN
android/Images.Construction/BuildingIcons/Pyramid.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
android/Images.Construction/MayaCalendar/0.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
android/Images.Construction/MayaCalendar/1.png
Normal file
After Width: | Height: | Size: 215 B |
BIN
android/Images.Construction/MayaCalendar/10.png
Normal file
After Width: | Height: | Size: 185 B |
BIN
android/Images.Construction/MayaCalendar/11.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
android/Images.Construction/MayaCalendar/12.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
android/Images.Construction/MayaCalendar/13.png
Normal file
After Width: | Height: | Size: 398 B |
BIN
android/Images.Construction/MayaCalendar/14.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
android/Images.Construction/MayaCalendar/15.png
Normal file
After Width: | Height: | Size: 208 B |
BIN
android/Images.Construction/MayaCalendar/16.png
Normal file
After Width: | Height: | Size: 387 B |
BIN
android/Images.Construction/MayaCalendar/17.png
Normal file
After Width: | Height: | Size: 398 B |
BIN
android/Images.Construction/MayaCalendar/18.png
Normal file
After Width: | Height: | Size: 403 B |
BIN
android/Images.Construction/MayaCalendar/19.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
android/Images.Construction/MayaCalendar/2.png
Normal file
After Width: | Height: | Size: 224 B |
BIN
android/Images.Construction/MayaCalendar/3.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
android/Images.Construction/MayaCalendar/4.png
Normal file
After Width: | Height: | Size: 228 B |
BIN
android/Images.Construction/MayaCalendar/5.png
Normal file
After Width: | Height: | Size: 171 B |
BIN
android/Images.Construction/MayaCalendar/6.png
Normal file
After Width: | Height: | Size: 363 B |
BIN
android/Images.Construction/MayaCalendar/7.png
Normal file
After Width: | Height: | Size: 366 B |
BIN
android/Images.Construction/MayaCalendar/8.png
Normal file
After Width: | Height: | Size: 371 B |
BIN
android/Images.Construction/MayaCalendar/9.png
Normal file
After Width: | Height: | Size: 406 B |
BIN
android/Images.Construction/MayaCalendar/Baktun.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
android/Images.Construction/MayaCalendar/Katun.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/Images.Construction/MayaCalendar/Maya.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/Images.Construction/MayaCalendar/Tun.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
android/Images.Construction/UnitIcons/Atlatlist.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
android/Images/NationIcons/The Maya.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
android/Images/OtherIcons/CityState.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 672 KiB After Width: | Height: | Size: 704 KiB |
@ -51,6 +51,17 @@
|
|||||||
"requiredTech": "Pottery",
|
"requiredTech": "Pottery",
|
||||||
"uniques": ["Hidden when religion is disabled"]
|
"uniques": ["Hidden when religion is disabled"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Pyramid",
|
||||||
|
"replaces": "Shrine",
|
||||||
|
"uniqueTo": "The Maya",
|
||||||
|
"faith": 2,
|
||||||
|
"science": 2,
|
||||||
|
"cost": 40,
|
||||||
|
"maintenance": 1,
|
||||||
|
"requiredTech": "Pottery",
|
||||||
|
"uniques": ["Hidden when religion is disabled"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Temple of Artemis",
|
"name": "Temple of Artemis",
|
||||||
"culture": 1,
|
"culture": 1,
|
||||||
|
@ -932,6 +932,48 @@
|
|||||||
"Nekemte","Asella","Dila","Adigrat","Debre Markos","Kombolcha","Debre Tabor","Sebeta",
|
"Nekemte","Asella","Dila","Adigrat","Debre Markos","Kombolcha","Debre Tabor","Sebeta",
|
||||||
"Shire","Ambo","Negele Arsi","Gambela","Ziway","Weldiya"]
|
"Shire","Ambo","Negele Arsi","Gambela","Ziway","Weldiya"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "The Maya",
|
||||||
|
"leaderName": "Pacal",
|
||||||
|
"adjective": ["mayan"],
|
||||||
|
"startBias": ["Jungle"],
|
||||||
|
"preferredVictoryType": "Scientific",
|
||||||
|
|
||||||
|
"startIntroPart1": "Your people kneel before you, exalted King Pacal the Great, favored son of the gods and shield to the citizens of the Palenque domain. After years of strife at the hands of your neighboring rivals, you struck back at the enemies of your people, sacrificing their leaders in retribution for the insults dealt to your predecessors. The glory of Palenque was restored only by the guidance afforded by your wisdom, as you orchestrated vast reconstruction efforts within the city, creating some of the greatest monuments and architecture your people - and the world - have ever known.",
|
||||||
|
"startIntroPart2": "Illustrious King, your people once again look to you for leadership and counsel in the coming days. Will you channel the will of the gods and restore your once proud kingdom to its greatest heights? Will you build new monuments to forever enshrine the memories of your people? Can you build a civilization that will stand the test of time?",
|
||||||
|
|
||||||
|
"declaringWar": "A sacrifice unlike all others must be made!",
|
||||||
|
"attacked": "Muahahahahahaha!",
|
||||||
|
"defeated": "Today comes a great searing pain. With you comes the path to the black storm.",
|
||||||
|
"introduction": "Greetings, wayward one. I am known as Pacal.",
|
||||||
|
"tradeRequest": "Friend, I believe I may have found a way to save us all! Look, look and accept my offering!",
|
||||||
|
|
||||||
|
"neutralHello": "A fine day, it helps you.",
|
||||||
|
/* Not used by Unciv, and uncertain
|
||||||
|
"afterPeace": "",
|
||||||
|
|
||||||
|
"neutralLetsHearIt": ["If you must show me."],
|
||||||
|
"neutralNo": ["No no, too much trouble.","No!","Not good enough."],
|
||||||
|
"neutralYes": ["Okay.","Fine.","Accepted."],
|
||||||
|
|
||||||
|
"hateHello": "You.",
|
||||||
|
"hateLetsHearIt": ["Talk.","So?","Speak!"],
|
||||||
|
"hateNo": ["That's unacceptable!","A thousand times no!","Never!"],
|
||||||
|
"hateYes": ["Oh… Fine, okay."],
|
||||||
|
*/
|
||||||
|
"outerColor": [198,141,99], // color picker: cf9f75
|
||||||
|
"innerColor": [24,63,66], // color picker: 1f4a4d
|
||||||
|
"favoredReligion": "Christianity",
|
||||||
|
"uniqueName": "The Long Count",
|
||||||
|
"uniques": ["Receive a free Great Person at the end of every [Maya Long Count calendar cycle] (every 394 years), after researching [Theology]. Each bonus person can only be chosen once.",
|
||||||
|
"Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count."],
|
||||||
|
// Parameters: tech, comment, amount, comment. Compare "Free [Great General] appears" as used by policies
|
||||||
|
"cities": ["Palenque","Tikal","Chichen Itza","Uxmal","Tulum","Copan","Coba","El Mirador","Calakmul",
|
||||||
|
"Edzna","Lamanai","Izapa","Uaxactun","Comalcalco","Piedras Negras","Cancuen","Yaxha","Quirigua",
|
||||||
|
"Q'umarkaj","Nakbe","Cerros","Xunantunich","Takalik Abaj","Cival","San Bartolo","Altar de Sacrificios","Seibal",
|
||||||
|
"Caracol","Naranjo","Dos Pilas","Mayapan","Ixinche","Zaculeu","Kabah"]
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
// City-States sorted by cityStateType, name
|
// City-States sorted by cityStateType, name
|
||||||
{
|
{
|
||||||
|
@ -124,6 +124,20 @@
|
|||||||
"promotions": ["Slinger Withdraw"],
|
"promotions": ["Slinger Withdraw"],
|
||||||
"attackSound": "arrow"
|
"attackSound": "arrow"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Atlatlist",
|
||||||
|
"unitType": "Archery",
|
||||||
|
"movement": 2,
|
||||||
|
"strength": 5,
|
||||||
|
"rangedStrength": 7,
|
||||||
|
"cost": 36,
|
||||||
|
"requiredTech": "Agriculture",
|
||||||
|
"obsoleteTech": "Machinery",
|
||||||
|
"replaces": "Archer",
|
||||||
|
"uniqueTo": "The Maya",
|
||||||
|
"upgradesTo": "Composite Bowman",
|
||||||
|
"attackSound": "arrow"
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
"name": "Archer",
|
"name": "Archer",
|
||||||
|
@ -195,7 +195,7 @@
|
|||||||
"The religion a city follows depends on the total pressure each religion has within the city.",
|
"The religion a city follows depends on the total pressure each religion has within the city.",
|
||||||
"Followers are allocated in the same proportions as these pressures, and these followers can be viewed in the city screen.",
|
"Followers are allocated in the same proportions as these pressures, and these followers can be viewed in the city screen.",
|
||||||
"Based on this, you can get a feel for which religions have a lot of pressure built up in the city, and which have almost none.",
|
"Based on this, you can get a feel for which religions have a lot of pressure built up in the city, and which have almost none.",
|
||||||
"The city follows a religion if a majority of its population follows that religion, and will only then receive the effects of Follower and Pantheon beliefs of that religion.",
|
"The city follows a religion if a majority of its population follows that religion, and will only then receive the effects of Follower and Pantheon beliefs of that religion."
|
||||||
],
|
],
|
||||||
"Spreading_Religion": [
|
"Spreading_Religion": [
|
||||||
"Spreading religion happens naturally, but can be sped up using missionaries or great prophets.",
|
"Spreading religion happens naturally, but can be sped up using missionaries or great prophets.",
|
||||||
@ -213,8 +213,7 @@
|
|||||||
"This pressure can also be seen in the city screen, and gives you an idea of how religions in your cities will evolve if you don't do anything.",
|
"This pressure can also be seen in the city screen, and gives you an idea of how religions in your cities will evolve if you don't do anything.",
|
||||||
"Holy cities also provide +30 pressure of the religion founded there to themselves, making it very difficult to effectively convert a holy city.",
|
"Holy cities also provide +30 pressure of the religion founded there to themselves, making it very difficult to effectively convert a holy city.",
|
||||||
"Lastly, before founding a religion, new cities you settle will start with 200 pressure for your pantheon.",
|
"Lastly, before founding a religion, new cities you settle will start with 200 pressure for your pantheon.",
|
||||||
"This way, all your cities will starting following your pantheon as long as you haven't founded a religion yet.",
|
"This way, all your cities will starting following your pantheon as long as you haven't founded a religion yet."
|
||||||
|
|
||||||
],
|
],
|
||||||
"Inquisitors": [
|
"Inquisitors": [
|
||||||
"Inquisitors are the last religious unit, and their strength is removing other religions.",
|
"Inquisitors are the last religious unit, and their strength is removing other religions.",
|
||||||
@ -222,5 +221,12 @@
|
|||||||
"Great prophets also have this ability, and remove all other religions in the city when spreading their religion.",
|
"Great prophets also have this ability, and remove all other religions in the city when spreading their religion.",
|
||||||
"Often this results in the city immediately converting to their religion",
|
"Often this results in the city immediately converting to their religion",
|
||||||
"Additionally, when an inquisitor is stationed in or directly next to a city center, units of other religions cannot spread their faith there, though natural spread is uneffected."
|
"Additionally, when an inquisitor is stationed in or directly next to a city center, units of other religions cannot spread their faith there, though natural spread is uneffected."
|
||||||
|
],
|
||||||
|
"Maya_Long_Count_calendar_cycle": [
|
||||||
|
"The Mayan unique ability, 'The Long Count', comes with a side effect:",
|
||||||
|
"Once active, the game's year display will use mayan notation.",
|
||||||
|
"",
|
||||||
|
"The Maya measured time in days from what we would call 11th of August, 3114 BCE. A day is called K'in, 20 days are a Winal, 18 Winals are a Tun, 20 Tuns are a K'atun, 20 K'atuns are a B'ak'tun, 20 B'ak'tuns a Piktun, and so on.",
|
||||||
|
"Unciv only displays ය B'ak'tuns, ඹ K'atuns and ම Tuns (from left to right) since that is enough to approximate gregorian calendar years. The Maya numerals are pretty obvious to understand. Have fun deciphering them!"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -624,6 +624,9 @@ You gained [Stats] as your religion was spread to [cityName] =
|
|||||||
You gained [Stats] as your religion was spread to an unknown city =
|
You gained [Stats] as your religion was spread to an unknown city =
|
||||||
Your city [cityName] was converted to [religionName]! =
|
Your city [cityName] was converted to [religionName]! =
|
||||||
Your [unitName] lost its faith after spending too long inside enemy territory! =
|
Your [unitName] lost its faith after spending too long inside enemy territory! =
|
||||||
|
You have unlocked [ability] =
|
||||||
|
A new b'ak'tun has just begun! =
|
||||||
|
A Great Person joins you! =
|
||||||
|
|
||||||
|
|
||||||
# World Screen UI
|
# World Screen UI
|
||||||
@ -715,6 +718,13 @@ Do you want to exit the game? =
|
|||||||
Start bias: =
|
Start bias: =
|
||||||
Avoid [terrain] =
|
Avoid [terrain] =
|
||||||
|
|
||||||
|
# Maya calendar popup
|
||||||
|
|
||||||
|
The Mayan Long Count =
|
||||||
|
Your scientists and theologians have devised a systematic approach to measuring long time spans - the Long Count. During the festivities whenever the current b'ak'tun ends, a Great Person will join you. =
|
||||||
|
While the rest of the world calls the current year [year], in the Maya Calendar that is: =
|
||||||
|
"[amount] b'ak'tun, [amount2] k'atun, [amount3] tun =
|
||||||
|
|
||||||
# City screen
|
# City screen
|
||||||
|
|
||||||
Exit city =
|
Exit city =
|
||||||
|
@ -18,10 +18,8 @@ import com.unciv.models.ruleset.Ruleset
|
|||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
import com.unciv.ui.audio.MusicMood
|
import com.unciv.ui.audio.MusicMood
|
||||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.min
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
class UncivShowableException(missingMods: String) : Exception(missingMods)
|
class UncivShowableException(missingMods: String) : Exception(missingMods)
|
||||||
|
|
||||||
@ -150,6 +148,48 @@ class GameInfo {
|
|||||||
return gameParameters.religionEnabled
|
return gameParameters.religionEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getEquivalentTurn(): Int {
|
||||||
|
val totalTurns = 500f * gameParameters.gameSpeed.modifier
|
||||||
|
val startPercent = ruleSet.eras[gameParameters.startingEra]!!.startPercent
|
||||||
|
return turns + ((totalTurns * startPercent).toInt() / 100)
|
||||||
|
}
|
||||||
|
private class YearsToTurn(
|
||||||
|
// enum class with lists for each value group potentially more efficient?
|
||||||
|
val toTurn: Int,
|
||||||
|
val yearInterval: Float
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
// Best to initialize these once only
|
||||||
|
val marathon = listOf(YearsToTurn(100, 15f), YearsToTurn(400, 10f), YearsToTurn(570, 5f), YearsToTurn(771, 2f), YearsToTurn(900, 1f), YearsToTurn(1080, 0.5f), YearsToTurn(1344, 0.25f), YearsToTurn(1500, 0.083333f))
|
||||||
|
val epic = listOf(YearsToTurn(140, 25f), YearsToTurn(230, 15f), YearsToTurn(270, 10f), YearsToTurn(360, 5f), YearsToTurn(430, 2f), YearsToTurn(530, 1f), YearsToTurn(1500, 0.5f))
|
||||||
|
val standard = listOf(YearsToTurn(75, 40f), YearsToTurn(135, 25f), YearsToTurn(160, 20f), YearsToTurn(210, 10f), YearsToTurn(270, 5f), YearsToTurn(320, 2f), YearsToTurn(440, 1f), YearsToTurn(500, 0.5f))
|
||||||
|
val quick = listOf(YearsToTurn(50, 60f), YearsToTurn(80, 40f), YearsToTurn(100, 30f), YearsToTurn(130, 20f), YearsToTurn(155, 10f), YearsToTurn(195, 5f), YearsToTurn(260, 2f), YearsToTurn(310, 1f))
|
||||||
|
fun getList(gameSpeed: GameSpeed) = when (gameSpeed) {
|
||||||
|
GameSpeed.Marathon -> marathon
|
||||||
|
GameSpeed.Epic -> epic
|
||||||
|
GameSpeed.Standard -> standard
|
||||||
|
GameSpeed.Quick -> quick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getYear(turnOffset: Int = 0): Int {
|
||||||
|
val turn = getEquivalentTurn() + turnOffset
|
||||||
|
val yearToTurnList = YearsToTurn.getList(gameParameters.gameSpeed)
|
||||||
|
var year: Float = -4000f
|
||||||
|
var i = 0
|
||||||
|
var yearsPerTurn: Float
|
||||||
|
|
||||||
|
// if macros are ever added to kotlin, this is one hell of a place for em'
|
||||||
|
while (i < turn) {
|
||||||
|
yearsPerTurn = yearToTurnList.firstOrNull { i < it.toTurn }?.yearInterval ?: 0.5f
|
||||||
|
year += yearsPerTurn
|
||||||
|
++i
|
||||||
|
}
|
||||||
|
|
||||||
|
return year.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region State changing functions
|
//region State changing functions
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.logic.civilization
|
package com.unciv.logic.civilization
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.GameInfo
|
import com.unciv.logic.GameInfo
|
||||||
import com.unciv.logic.UncivShowableException
|
import com.unciv.logic.UncivShowableException
|
||||||
@ -25,6 +26,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
|
|||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.utils.MayaCalendar
|
||||||
import com.unciv.ui.utils.toPercent
|
import com.unciv.ui.utils.toPercent
|
||||||
import com.unciv.ui.victoryscreen.RankingType
|
import com.unciv.ui.victoryscreen.RankingType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -172,6 +174,9 @@ class CivilizationInfo {
|
|||||||
var totalCultureForContests = 0
|
var totalCultureForContests = 0
|
||||||
var totalFaithForContests = 0
|
var totalFaithForContests = 0
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
var hasLongCountDisplayUnique = false
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
|
|
||||||
constructor(civName: String) {
|
constructor(civName: String) {
|
||||||
@ -623,8 +628,10 @@ class CivilizationInfo {
|
|||||||
|
|
||||||
fun getGreatPeople(): HashSet<BaseUnit> {
|
fun getGreatPeople(): HashSet<BaseUnit> {
|
||||||
val greatPeople = gameInfo.ruleSet.units.values.asSequence()
|
val greatPeople = gameInfo.ruleSet.units.values.asSequence()
|
||||||
.filter { it.isGreatPerson() }.map { getEquivalentUnit(it.name) }
|
.filter { it.isGreatPerson() }
|
||||||
return if (!gameInfo.isReligionEnabled()) greatPeople.filter { !it.uniques.contains("Hidden when religion is disabled")}.toHashSet()
|
.map { getEquivalentUnit(it.name) }
|
||||||
|
return if (!gameInfo.isReligionEnabled())
|
||||||
|
greatPeople.filter { !it.hasUnique(Constants.hiddenWithoutReligionUnique) }.toHashSet()
|
||||||
else greatPeople.toHashSet()
|
else greatPeople.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +641,13 @@ class CivilizationInfo {
|
|||||||
fun isMinorCivAggressor() = numMinorCivsAttacked >= 2
|
fun isMinorCivAggressor() = numMinorCivsAttacked >= 2
|
||||||
fun isMinorCivWarmonger() = numMinorCivsAttacked >= 4
|
fun isMinorCivWarmonger() = numMinorCivsAttacked >= 4
|
||||||
|
|
||||||
|
fun isLongCountActive(): Boolean {
|
||||||
|
val unique = getMatchingUniques(UniqueType.MayanGainGreatPerson).firstOrNull()
|
||||||
|
?: return false
|
||||||
|
return tech.isResearched(unique.params[1])
|
||||||
|
}
|
||||||
|
fun isLongCountDisplay() = hasLongCountDisplayUnique && isLongCountActive()
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region state-changing functions
|
//region state-changing functions
|
||||||
@ -701,6 +715,8 @@ class CivilizationInfo {
|
|||||||
if (lastEraForUnit != null)
|
if (lastEraForUnit != null)
|
||||||
lastEraResourceUsedForUnit[resource] = lastEraForUnit
|
lastEraResourceUsedForUnit[resource] = lastEraForUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasLongCountDisplayUnique = hasUnique(UniqueType.MayanCalendarDisplay)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSightAndResources() {
|
fun updateSightAndResources() {
|
||||||
@ -729,6 +745,8 @@ class CivilizationInfo {
|
|||||||
val greatPerson = greatPeople.getNewGreatPerson()
|
val greatPerson = greatPeople.getNewGreatPerson()
|
||||||
if (greatPerson != null && gameInfo.ruleSet.units.containsKey(greatPerson)) addUnit(greatPerson)
|
if (greatPerson != null && gameInfo.ruleSet.units.containsKey(greatPerson)) addUnit(greatPerson)
|
||||||
religionManager.startTurn()
|
religionManager.startTurn()
|
||||||
|
if (isLongCountActive())
|
||||||
|
MayaCalendar.startTurnForMaya(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
|
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package com.unciv.logic.civilization
|
package com.unciv.logic.civilization
|
||||||
|
|
||||||
import com.unciv.models.Counter
|
import com.unciv.models.Counter
|
||||||
import com.unciv.models.stats.Stat
|
import java.util.HashSet
|
||||||
import com.unciv.models.stats.Stats
|
|
||||||
|
// todo: Great Admiral?
|
||||||
|
// todo: Free GP from policies and wonders should increase threshold according to the wiki
|
||||||
|
// todo: GP from Maya long count should increase threshold as well - implement together
|
||||||
|
|
||||||
class GreatPersonManager {
|
class GreatPersonManager {
|
||||||
var pointsForNextGreatPerson = 100
|
var pointsForNextGreatPerson = 100
|
||||||
@ -11,7 +14,10 @@ class GreatPersonManager {
|
|||||||
var greatPersonPointsCounter = Counter<String>()
|
var greatPersonPointsCounter = Counter<String>()
|
||||||
var greatGeneralPoints = 0
|
var greatGeneralPoints = 0
|
||||||
var freeGreatPeople = 0
|
var freeGreatPeople = 0
|
||||||
|
/** Marks subset of [freeGreatPeople] as subject to maya ability restrictions (each only once untill all used) */
|
||||||
|
var mayaLimitedFreeGP = 0
|
||||||
|
/** Remaining candidates for maya ability - whenever empty refilled from all GP, starts out empty */
|
||||||
|
var longCountGPPool = HashSet<String>()
|
||||||
|
|
||||||
fun clone(): GreatPersonManager {
|
fun clone(): GreatPersonManager {
|
||||||
val toReturn = GreatPersonManager()
|
val toReturn = GreatPersonManager()
|
||||||
@ -20,12 +26,12 @@ class GreatPersonManager {
|
|||||||
toReturn.pointsForNextGreatPerson = pointsForNextGreatPerson
|
toReturn.pointsForNextGreatPerson = pointsForNextGreatPerson
|
||||||
toReturn.pointsForNextGreatGeneral = pointsForNextGreatGeneral
|
toReturn.pointsForNextGreatGeneral = pointsForNextGreatGeneral
|
||||||
toReturn.greatGeneralPoints = greatGeneralPoints
|
toReturn.greatGeneralPoints = greatGeneralPoints
|
||||||
|
toReturn.mayaLimitedFreeGP = mayaLimitedFreeGP
|
||||||
|
toReturn.longCountGPPool = longCountGPPool.toHashSet()
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNewGreatPerson(): String? {
|
fun getNewGreatPerson(): String? {
|
||||||
val greatPerson: String? = null
|
|
||||||
|
|
||||||
if (greatGeneralPoints > pointsForNextGreatGeneral) {
|
if (greatGeneralPoints > pointsForNextGreatGeneral) {
|
||||||
greatGeneralPoints -= pointsForNextGreatGeneral
|
greatGeneralPoints -= pointsForNextGreatGeneral
|
||||||
pointsForNextGreatGeneral += 50
|
pointsForNextGreatGeneral += 50
|
||||||
@ -39,7 +45,7 @@ class GreatPersonManager {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return greatPerson
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addGreatPersonPoints(greatPersonPointsForTurn: Counter<String>) {
|
fun addGreatPersonPoints(greatPersonPointsForTurn: Counter<String>) {
|
||||||
|
@ -3,11 +3,14 @@ package com.unciv.logic.civilization
|
|||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.ui.cityscreen.CityScreen
|
import com.unciv.ui.cityscreen.CityScreen
|
||||||
|
import com.unciv.ui.pickerscreens.PolicyPickerScreen
|
||||||
import com.unciv.ui.pickerscreens.TechPickerScreen
|
import com.unciv.ui.pickerscreens.TechPickerScreen
|
||||||
import com.unciv.ui.trade.DiplomacyScreen
|
import com.unciv.ui.trade.DiplomacyScreen
|
||||||
|
import com.unciv.ui.utils.MayaCalendar
|
||||||
import com.unciv.ui.worldscreen.WorldScreen
|
import com.unciv.ui.worldscreen.WorldScreen
|
||||||
|
|
||||||
object NotificationIcon {
|
object NotificationIcon {
|
||||||
|
// Remember: The typical white-on-transparency icon will not be visible on Notifications
|
||||||
const val Culture = "StatIcons/Culture"
|
const val Culture = "StatIcons/Culture"
|
||||||
const val Construction = "StatIcons/Production"
|
const val Construction = "StatIcons/Production"
|
||||||
const val Growth = "StatIcons/Population"
|
const val Growth = "StatIcons/Population"
|
||||||
@ -21,7 +24,7 @@ object NotificationIcon {
|
|||||||
const val Citadel = "ImprovementIcons/Citadel"
|
const val Citadel = "ImprovementIcons/Citadel"
|
||||||
const val Happiness = "StatIcons/Happiness"
|
const val Happiness = "StatIcons/Happiness"
|
||||||
const val Population = "StatIcons/Population"
|
const val Population = "StatIcons/Population"
|
||||||
const val CityState = "NationIcons/CityState"
|
const val CityState = "OtherIcons/CityState"
|
||||||
const val Production = "StatIcons/Production"
|
const val Production = "StatIcons/Production"
|
||||||
const val Food = "StatIcons/Food"
|
const val Food = "StatIcons/Food"
|
||||||
const val Faith = "StatIcons/Faith"
|
const val Faith = "StatIcons/Faith"
|
||||||
@ -82,10 +85,18 @@ data class CityAction(val city: Vector2 = Vector2.Zero): NotificationAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** enter diplomacy screen */
|
||||||
data class DiplomacyAction(val otherCivName: String = ""): NotificationAction {
|
data class DiplomacyAction(val otherCivName: String = ""): NotificationAction {
|
||||||
override fun execute(worldScreen: WorldScreen) {
|
override fun execute(worldScreen: WorldScreen) {
|
||||||
val screen = DiplomacyScreen(worldScreen.viewingCiv)
|
val screen = DiplomacyScreen(worldScreen.viewingCiv)
|
||||||
screen.updateRightSide(worldScreen.gameInfo.getCivilization(otherCivName))
|
screen.updateRightSide(worldScreen.gameInfo.getCivilization(otherCivName))
|
||||||
worldScreen.game.setScreen(screen)
|
worldScreen.game.setScreen(screen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** enter Maya Long Count popup */
|
||||||
|
class MayaLongCountAction() : NotificationAction {
|
||||||
|
override fun execute(worldScreen: WorldScreen) {
|
||||||
|
MayaCalendar.openPopup(worldScreen, worldScreen.selectedCiv, worldScreen.gameInfo.getYear())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,7 +7,9 @@ import com.unciv.logic.map.TileInfo
|
|||||||
import com.unciv.models.ruleset.unique.UniqueMap
|
import com.unciv.models.ruleset.unique.UniqueMap
|
||||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||||
import com.unciv.models.ruleset.tech.Technology
|
import com.unciv.models.ruleset.tech.Technology
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
|
import com.unciv.ui.utils.MayaCalendar
|
||||||
import com.unciv.ui.utils.toPercent
|
import com.unciv.ui.utils.toPercent
|
||||||
import com.unciv.ui.utils.withItem
|
import com.unciv.ui.utils.withItem
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -310,6 +312,10 @@ class TechManager {
|
|||||||
if (unique.params[1] != techName) continue
|
if (unique.params[1] != techName) continue
|
||||||
civInfo.addUnit(unique.params[0])
|
civInfo.addUnit(unique.params[0])
|
||||||
}
|
}
|
||||||
|
for (unique in civInfo.getMatchingUniques(UniqueType.MayanGainGreatPerson)) {
|
||||||
|
if (unique.params[1] != techName) continue
|
||||||
|
civInfo.addNotification("You have unlocked [The Long Count]!", MayaLongCountAction(), MayaCalendar.notificationIcon)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addTechToTransients(tech: Technology) {
|
fun addTechToTransients(tech: Technology) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.unciv.models
|
package com.unciv.models
|
||||||
|
|
||||||
enum class Tutorial(val value: String, val isCivilopedia: Boolean = !value.startsWith("_")) {
|
enum class Tutorial(val value: String, val isCivilopedia: Boolean = !value.startsWith("_")) {
|
||||||
|
|
||||||
Introduction("Introduction"),
|
Introduction("Introduction"),
|
||||||
NewGame("New_Game"),
|
NewGame("New_Game"),
|
||||||
SlowStart("_Slow_Start"),
|
SlowStart("_Slow_Start"),
|
||||||
@ -42,6 +42,7 @@ enum class Tutorial(val value: String, val isCivilopedia: Boolean = !value.start
|
|||||||
Beliefs("Beliefs"),
|
Beliefs("Beliefs"),
|
||||||
SpreadingReligion("Spreading_Religion"),
|
SpreadingReligion("Spreading_Religion"),
|
||||||
Inquisitors("Inquisitors"),
|
Inquisitors("Inquisitors"),
|
||||||
|
MayanCalendar("Maya_Long_Count_calendar_cycle"),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -178,6 +178,13 @@ enum class UniqueParameterType(val parameterName:String) {
|
|||||||
else -> UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant
|
else -> UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Technology("tech") {
|
||||||
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
|
UniqueType.UniqueComplianceErrorSeverity? = when (parameterText) {
|
||||||
|
in ruleset.technologies -> null
|
||||||
|
else -> UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific
|
||||||
|
}
|
||||||
|
},
|
||||||
/** Behaves like [Unknown], but states explicitly the parameter is OK and its contents are ignored */
|
/** Behaves like [Unknown], but states explicitly the parameter is OK and its contents are ignored */
|
||||||
Comment("comment") {
|
Comment("comment") {
|
||||||
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
|
||||||
|
@ -11,6 +11,7 @@ import com.unciv.models.ruleset.VictoryType
|
|||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.translations.fillPlaceholders
|
import com.unciv.models.translations.fillPlaceholders
|
||||||
import com.unciv.models.translations.hasPlaceholderParameters
|
import com.unciv.models.translations.hasPlaceholderParameters
|
||||||
|
import com.unciv.ui.utils.MayaCalendar
|
||||||
import com.unciv.ui.worldscreen.unit.UnitActions
|
import com.unciv.ui.worldscreen.unit.UnitActions
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -113,17 +114,29 @@ object UniqueTriggerActivation {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
OneTimeFreeGreatPerson -> {
|
OneTimeFreeGreatPerson, MayanGainGreatPerson -> {
|
||||||
if (civInfo.isSpectator()) return false
|
if (civInfo.isSpectator()) return false
|
||||||
|
val greatPeople = civInfo.getGreatPeople()
|
||||||
|
if (unique.type == MayanGainGreatPerson) {
|
||||||
|
if (civInfo.greatPeople.longCountGPPool.isEmpty())
|
||||||
|
// replenish maya GP pool when dry
|
||||||
|
civInfo.greatPeople.longCountGPPool = greatPeople.map { it.name }.toHashSet()
|
||||||
|
}
|
||||||
if (civInfo.isPlayerCivilization()) {
|
if (civInfo.isPlayerCivilization()) {
|
||||||
civInfo.greatPeople.freeGreatPeople++
|
civInfo.greatPeople.freeGreatPeople++
|
||||||
if (notification != null)
|
if (unique.type == MayanGainGreatPerson) {
|
||||||
civInfo.addNotification(notification) // Anyone an idea for a good icon?
|
civInfo.greatPeople.mayaLimitedFreeGP++
|
||||||
|
civInfo.addNotification(notification!!, MayaLongCountAction(), MayaCalendar.notificationIcon)
|
||||||
|
} else {
|
||||||
|
if (notification != null)
|
||||||
|
civInfo.addNotification(notification) // Anyone an idea for a good icon?
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
val greatPeople = civInfo.getGreatPeople()
|
if (unique.type == MayanGainGreatPerson)
|
||||||
|
greatPeople.removeAll { it.name !in civInfo.greatPeople.longCountGPPool }
|
||||||
if (greatPeople.isEmpty()) return false
|
if (greatPeople.isEmpty()) return false
|
||||||
var greatPerson = civInfo.getGreatPeople().random()
|
var greatPerson = greatPeople.random()
|
||||||
|
|
||||||
val preferredVictoryType = civInfo.victoryType()
|
val preferredVictoryType = civInfo.victoryType()
|
||||||
if (preferredVictoryType == VictoryType.Cultural) {
|
if (preferredVictoryType == VictoryType.Cultural) {
|
||||||
@ -137,6 +150,8 @@ object UniqueTriggerActivation {
|
|||||||
if (scientificGP != null) greatPerson = scientificGP
|
if (scientificGP != null) greatPerson = scientificGP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unique.type == MayanGainGreatPerson)
|
||||||
|
civInfo.greatPeople.longCountGPPool.remove(greatPerson.name)
|
||||||
return civInfo.addUnit(greatPerson.name, chosenCity) != null
|
return civInfo.addUnit(greatPerson.name, chosenCity) != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,9 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) {
|
|||||||
FreeExtraBeliefs("May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion", UniqueTarget.Global),
|
FreeExtraBeliefs("May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion", UniqueTarget.Global),
|
||||||
FreeExtraAnyBeliefs("May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global),
|
FreeExtraAnyBeliefs("May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global),
|
||||||
|
|
||||||
|
MayanGainGreatPerson("Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once.", UniqueTarget.Nation),
|
||||||
|
MayanCalendarDisplay("Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count.", UniqueTarget.Nation),
|
||||||
|
|
||||||
///////////////////////////////////////// UNIT UNIQUES /////////////////////////////////////////
|
///////////////////////////////////////// UNIT UNIQUES /////////////////////////////////////////
|
||||||
|
|
||||||
FoundCity("Founds a new city", UniqueTarget.Unit),
|
FoundCity("Founds a new city", UniqueTarget.Unit),
|
||||||
|
@ -189,6 +189,7 @@ class FormattedLine (
|
|||||||
result[it.second] = it.first
|
result[it.second] = it.first
|
||||||
//println(" ${it.second} is a ${it.first}")
|
//println(" ${it.second} is a ${it.first}")
|
||||||
}
|
}
|
||||||
|
result["Maya Long Count calendar cycle"] = CivilopediaCategories.Tutorial
|
||||||
|
|
||||||
//println("allObjectNamesCategoryMap took ${System.nanoTime()-startTime}ns to initialize")
|
//println("allObjectNamesCategoryMap took ${System.nanoTime()-startTime}ns to initialize")
|
||||||
rulesetCachedInNameMap = ruleSet
|
rulesetCachedInNameMap = ruleSet
|
||||||
|
@ -7,6 +7,7 @@ import com.unciv.models.UncivSound
|
|||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.utils.ImageGetter
|
import com.unciv.ui.utils.ImageGetter
|
||||||
|
import com.unciv.ui.utils.isEnabled
|
||||||
import com.unciv.ui.utils.onClick
|
import com.unciv.ui.utils.onClick
|
||||||
import com.unciv.ui.utils.toLabel
|
import com.unciv.ui.utils.toLabel
|
||||||
|
|
||||||
@ -14,23 +15,23 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() {
|
|||||||
private var theChosenOne: BaseUnit? = null
|
private var theChosenOne: BaseUnit? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
closeButton.isVisible=false
|
closeButton.isVisible = false
|
||||||
rightSideButton.setText("Choose a free great person".tr())
|
rightSideButton.setText("Choose a free great person".tr())
|
||||||
|
|
||||||
val greatPersonUnits = civInfo.getGreatPeople()
|
val greatPersonUnits = civInfo.getGreatPeople()
|
||||||
for (unit in greatPersonUnits)
|
val useMayaLongCount = civInfo.greatPeople.mayaLimitedFreeGP > 0
|
||||||
{
|
|
||||||
|
for (unit in greatPersonUnits) {
|
||||||
val button = Button(skin)
|
val button = Button(skin)
|
||||||
|
|
||||||
button.add(ImageGetter.getUnitIcon(unit.name)).size(30f).pad(10f)
|
button.add(ImageGetter.getUnitIcon(unit.name)).size(30f).pad(10f)
|
||||||
button.add(unit.name.toLabel()).pad(10f)
|
button.add(unit.name.toLabel()).pad(10f)
|
||||||
button.pack()
|
button.pack()
|
||||||
button.onClick {
|
button.isEnabled = !useMayaLongCount || unit.name in civInfo.greatPeople.longCountGPPool
|
||||||
|
if (button.isEnabled) button.onClick {
|
||||||
theChosenOne = unit
|
theChosenOne = unit
|
||||||
val unitDescription=HashSet<String>()
|
|
||||||
unit.uniques.forEach { unitDescription.add(it.tr()) }
|
|
||||||
pick("Get [${unit.name}]".tr())
|
pick("Get [${unit.name}]".tr())
|
||||||
descriptionLabel.setText(unitDescription.joinToString())
|
descriptionLabel.setText(unit.getShortDescription())
|
||||||
}
|
}
|
||||||
topTable.add(button).pad(10f).row()
|
topTable.add(button).pad(10f).row()
|
||||||
}
|
}
|
||||||
@ -38,6 +39,10 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() {
|
|||||||
rightSideButton.onClick(UncivSound.Choir) {
|
rightSideButton.onClick(UncivSound.Choir) {
|
||||||
civInfo.addUnit(theChosenOne!!.name, civInfo.getCapital())
|
civInfo.addUnit(theChosenOne!!.name, civInfo.getCapital())
|
||||||
civInfo.greatPeople.freeGreatPeople--
|
civInfo.greatPeople.freeGreatPeople--
|
||||||
|
if (useMayaLongCount) {
|
||||||
|
civInfo.greatPeople.mayaLimitedFreeGP--
|
||||||
|
civInfo.greatPeople.longCountGPPool.remove(theChosenOne!!.name)
|
||||||
|
}
|
||||||
UncivGame.Current.setWorldScreen()
|
UncivGame.Current.setWorldScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +98,10 @@ class NativeBitmapFontData(
|
|||||||
Fonts.culture -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Culture").region)
|
Fonts.culture -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Culture").region)
|
||||||
Fonts.faith -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Faith").region)
|
Fonts.faith -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Faith").region)
|
||||||
Fonts.happiness -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Happiness").region)
|
Fonts.happiness -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Happiness").region)
|
||||||
|
MayaCalendar.tun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.tunIcon).region)
|
||||||
|
MayaCalendar.katun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.katunIcon).region)
|
||||||
|
MayaCalendar.baktun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.baktunIcon).region)
|
||||||
|
in MayaCalendar.digits -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.digitIcon(ch)).region)
|
||||||
else -> fontImplementation.getCharPixmap(ch)
|
else -> fontImplementation.getCharPixmap(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +170,7 @@ object Fonts {
|
|||||||
const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note')
|
const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note')
|
||||||
const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face')
|
const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face')
|
||||||
const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace')
|
const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace')
|
||||||
|
|
||||||
fun statToChar(stat: Stat): Char {
|
fun statToChar(stat: Stat): Char {
|
||||||
return when (stat) {
|
return when (stat) {
|
||||||
Stat.Food -> food
|
Stat.Food -> food
|
||||||
|
86
core/src/com/unciv/ui/utils/MayaCalendar.kt
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package com.unciv.ui.utils
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
object MayaCalendar {
|
||||||
|
// Glyphs / icons
|
||||||
|
private const val iconFolder = "MayaCalendar/"
|
||||||
|
const val notificationIcon = "MayaCalendar/Maya"
|
||||||
|
const val tunIcon = "MayaCalendar/Tun"
|
||||||
|
const val katunIcon = "MayaCalendar/Katun"
|
||||||
|
const val baktunIcon = "MayaCalendar/Baktun"
|
||||||
|
const val tun = 'ම' // U+0DB8, no relation to maya, arbitrary choice (it's the sinhala letter 'mayanna')
|
||||||
|
const val katun = 'ඹ' // U+0DB9
|
||||||
|
const val baktun = 'ය' // U+0DBA
|
||||||
|
// The mayan numerals are actually unicode U+1D2E0 to U+1D2F3, but we can't do those
|
||||||
|
// so - I'm replacing the code points for small roman numerals U+2170 to U+2183
|
||||||
|
const val zero = 'ⅰ' // U+2170
|
||||||
|
const val nineteen = 'Ↄ' // U+2183
|
||||||
|
val digits = zero..nineteen
|
||||||
|
fun digitIcon(ch: Char) = iconFolder + (ch.code - zero.code).toString()
|
||||||
|
|
||||||
|
// Calculation
|
||||||
|
private const val daysOn30000101BCE = 36000 + 5040 + 240 + 11
|
||||||
|
|
||||||
|
private class MayaYear(year: Int) {
|
||||||
|
val baktuns: Int
|
||||||
|
val katuns: Int
|
||||||
|
val tuns: Int
|
||||||
|
|
||||||
|
init {
|
||||||
|
val mayaDays = (year + 3000) * 365 + (year + 3000) / 4 + daysOn30000101BCE
|
||||||
|
val totalTuns = if (mayaDays >= 0) mayaDays / 360 else 13 * 20 * 20 + mayaDays / 360
|
||||||
|
val totalKatuns = totalTuns / 20
|
||||||
|
baktuns = totalKatuns / 20
|
||||||
|
katuns = totalKatuns - baktuns * 20
|
||||||
|
tuns = totalTuns - totalKatuns * 20
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val baktunDigit = Char(zero.code + baktuns)
|
||||||
|
val katunDigit = Char(zero.code + katuns)
|
||||||
|
val tunDigit = Char(zero.code + tuns)
|
||||||
|
return "$baktunDigit$baktun$katunDigit$katun$tunDigit$tun"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun yearToMayaDate(year: Int) = MayaYear(year).toString()
|
||||||
|
|
||||||
|
// Maya ability implementation
|
||||||
|
private fun isNewCycle(year: Int, otherYear: Int) = MayaYear(year).baktuns != MayaYear(otherYear).baktuns
|
||||||
|
|
||||||
|
fun startTurnForMaya(civInfo: CivilizationInfo) {
|
||||||
|
val game = civInfo.gameInfo
|
||||||
|
val year = game.getYear()
|
||||||
|
if (!isNewCycle(year, game.getYear(-1))) return
|
||||||
|
for (unique in civInfo.getMatchingUniques(UniqueType.MayanGainGreatPerson)) {
|
||||||
|
UniqueTriggerActivation.triggerCivwideUnique(
|
||||||
|
unique, civInfo,
|
||||||
|
notification = "{A new b'ak'tun has just begun!}\n{A Great Person joins you!}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User interface to explain changed year display
|
||||||
|
fun openPopup(previousScreen: CameraStageBaseScreen, civInfo: CivilizationInfo, year: Int) {
|
||||||
|
Popup(previousScreen).apply {
|
||||||
|
name = "MayaCalendar"
|
||||||
|
addGoodSizedLabel("The Mayan Long Count", 24).apply {
|
||||||
|
actor.color = civInfo.nation.getOuterColor()
|
||||||
|
}.row()
|
||||||
|
addSeparator(color = Color.DARK_GRAY)
|
||||||
|
addGoodSizedLabel("Your scientists and theologians have devised a systematic approach to measuring long time spans - the Long Count. During the festivities whenever the current b'ak'tun ends, a Great Person will join you.").row()
|
||||||
|
val yearText = ("[" + abs(year) + "] " + (if (year < 0) "BC" else "AD")).tr()
|
||||||
|
addGoodSizedLabel("While the rest of the world calls the current year [$yearText], in the Maya Calendar that is:").padTop(10f).row()
|
||||||
|
val mayaYear = MayaYear(year)
|
||||||
|
addGoodSizedLabel(mayaYear.toString(), 42).row()
|
||||||
|
addGoodSizedLabel("[${mayaYear.baktuns}] b'ak'tun, [${mayaYear.katuns}] k'atun, [${mayaYear.tuns}] tun").padBottom(10f).row()
|
||||||
|
addCloseButton()
|
||||||
|
}.open(true)
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
|||||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
import com.badlogic.gdx.scenes.scene2d.Group
|
import com.badlogic.gdx.scenes.scene2d.Group
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||||
import com.unciv.logic.GameInfo
|
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
import com.unciv.models.metadata.GameSpeed
|
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
@ -64,7 +62,14 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
|||||||
private fun getResourceTable(): Table {
|
private fun getResourceTable(): Table {
|
||||||
val resourceTable = Table()
|
val resourceTable = Table()
|
||||||
resourceTable.defaults().pad(5f)
|
resourceTable.defaults().pad(5f)
|
||||||
turnsLabel.onClick { worldScreen.game.setScreen(VictoryScreen(worldScreen)) }
|
turnsLabel.onClick {
|
||||||
|
if (worldScreen.selectedCiv.isLongCountDisplay()) {
|
||||||
|
val gameInfo = worldScreen.selectedCiv.gameInfo
|
||||||
|
MayaCalendar.openPopup(worldScreen, worldScreen.selectedCiv, gameInfo.getYear())
|
||||||
|
} else {
|
||||||
|
worldScreen.game.setScreen(VictoryScreen(worldScreen))
|
||||||
|
}
|
||||||
|
}
|
||||||
resourceTable.add(turnsLabel).padRight(20f)
|
resourceTable.add(turnsLabel).padRight(20f)
|
||||||
val revealedStrategicResources = worldScreen.gameInfo.ruleSet.tileResources.values
|
val revealedStrategicResources = worldScreen.gameInfo.ruleSet.tileResources.values
|
||||||
.filter { it.resourceType == ResourceType.Strategic } // && currentPlayerCivInfo.tech.isResearched(it.revealedBy!!) }
|
.filter { it.resourceType == ResourceType.Strategic } // && currentPlayerCivInfo.tech.isResearched(it.revealedBy!!) }
|
||||||
@ -215,9 +220,9 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
|||||||
else resourceLabels[resource.name]!!.setText(civResources.first { it.resource == resource }.amount.toString())
|
else resourceLabels[resource.name]!!.setText(civResources.first { it.resource == resource }.amount.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
val year = getYear(civInfo.gameInfo.gameParameters.gameSpeed, getEquivalentTurn(civInfo.gameInfo)).toInt()
|
val year = civInfo.gameInfo.getYear()
|
||||||
|
val yearText = if (civInfo.isLongCountDisplay()) MayaCalendar.yearToMayaDate(year)
|
||||||
val yearText = "[" + abs(year) + "] " + if (year < 0) "BC" else "AD"
|
else "[" + abs(year) + "] " + (if (year < 0) "BC" else "AD")
|
||||||
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns + " | " + yearText.tr())
|
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns + " | " + yearText.tr())
|
||||||
|
|
||||||
val nextTurnStats = civInfo.statsForNextTurn
|
val nextTurnStats = civInfo.statsForNextTurn
|
||||||
@ -275,40 +280,4 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
|||||||
return happinessText
|
return happinessText
|
||||||
}
|
}
|
||||||
|
|
||||||
private class YearsToTurn(val toTurn: Int, val yearInterval: Double) // enum class with lists for each value group potentially more efficient?
|
|
||||||
|
|
||||||
|
|
||||||
// Best to initialize these once only
|
|
||||||
private val marathon = listOf(YearsToTurn(100, 15.0), YearsToTurn(400, 10.0), YearsToTurn(570, 5.0), YearsToTurn(771, 2.0), YearsToTurn(900, 1.0), YearsToTurn(1080, 0.5), YearsToTurn(1344, 0.25), YearsToTurn(1500, 0.083333))
|
|
||||||
private val epic = listOf(YearsToTurn(140, 25.0), YearsToTurn(230, 15.0), YearsToTurn(270, 10.0), YearsToTurn(360, 5.0), YearsToTurn(430, 2.0), YearsToTurn(530, 1.0), YearsToTurn(1500, 0.5))
|
|
||||||
private val standard = listOf(YearsToTurn(75, 40.0), YearsToTurn(135, 25.0), YearsToTurn(160, 20.0), YearsToTurn(210, 10.0), YearsToTurn(270, 5.0), YearsToTurn(320, 2.0), YearsToTurn(440, 1.0), YearsToTurn(500, 0.5))
|
|
||||||
private val quick = listOf(YearsToTurn(50, 60.0), YearsToTurn(80, 40.0), YearsToTurn(100, 30.0), YearsToTurn(130, 20.0), YearsToTurn(155, 10.0), YearsToTurn(195, 5.0), YearsToTurn(260, 2.0), YearsToTurn(310, 1.0))
|
|
||||||
|
|
||||||
private fun getYear(gameSpeed: GameSpeed, turn: Int): Float {
|
|
||||||
|
|
||||||
val yearToTurnList: List<YearsToTurn> = when (gameSpeed) {
|
|
||||||
GameSpeed.Marathon -> marathon
|
|
||||||
GameSpeed.Epic -> epic
|
|
||||||
GameSpeed.Standard -> standard
|
|
||||||
GameSpeed.Quick -> quick
|
|
||||||
}
|
|
||||||
|
|
||||||
var year: Float = -4000f
|
|
||||||
var i = 0
|
|
||||||
var yearsPerTurn: Float
|
|
||||||
// if macros are ever added to kotlin, this is one hell of a place for em'
|
|
||||||
while (i < turn) {
|
|
||||||
yearsPerTurn = yearToTurnList.firstOrNull { i < it.toTurn }?.yearInterval?.toFloat() ?: 0.5f
|
|
||||||
year += yearsPerTurn
|
|
||||||
++i
|
|
||||||
}
|
|
||||||
|
|
||||||
return year
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getEquivalentTurn(gameInfo: GameInfo): Int {
|
|
||||||
val totalTurns = 500f * gameInfo.gameParameters.gameSpeed.modifier
|
|
||||||
val startPercent = gameInfo.ruleSet.eras[gameInfo.gameParameters.startingEra]!!.startPercent
|
|
||||||
return gameInfo.turns + ((totalTurns * startPercent).toInt() / 100)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [Spiked Club](https://thenounproject.com/search/?q=spiked%20club&i=831793) by Hamish
|
* [Spiked Club](https://thenounproject.com/search/?q=spiked%20club&i=831793) by Hamish
|
||||||
* [Bow And Arrow](https://thenounproject.com/search/?q=Bow%20and%20Arrow&i=338261) By Viktor Ostrovsky for Archer
|
* [Bow And Arrow](https://thenounproject.com/search/?q=Bow%20and%20Arrow&i=338261) By Viktor Ostrovsky for Archer
|
||||||
* [Bow](https://thenounproject.com/search/?q=bow&i=101736) By Arthur Shlain for Bowman
|
* [Bow](https://thenounproject.com/search/?q=bow&i=101736) By Arthur Shlain for Bowman
|
||||||
|
* [Javelin](https://thenounproject.com/term/javelin-thrower/2118369/) By WEBTECHOPS LLP for Atlatlist
|
||||||
* [Fishing Vessel](https://thenounproject.com/term/fishing-vessel/23815/) By Luis Prado for Work Boats
|
* [Fishing Vessel](https://thenounproject.com/term/fishing-vessel/23815/) By Luis Prado for Work Boats
|
||||||
* [Greek Trireme](https://thenounproject.com/search/?q=ancient%20boat&i=1626303) By Zachary McCune for Trireme
|
* [Greek Trireme](https://thenounproject.com/search/?q=ancient%20boat&i=1626303) By Zachary McCune for Trireme
|
||||||
* [Greek Trireme](https://thenounproject.com/search/?q=ancient%20boat&i=1626303) By Zachary McCune for Quinquereme. The original work has been modified.
|
* [Greek Trireme](https://thenounproject.com/search/?q=ancient%20boat&i=1626303) By Zachary McCune for Quinquereme. The original work has been modified.
|
||||||
@ -213,6 +214,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
|
|
||||||
* [Storehouse](https://thenounproject.com/term/storehouse/966786/) By Pedro Santos for Granary
|
* [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
|
* [Shinto Gate](https://thenounproject.com/search/?q=shrine&i=253325) by Alexander Skowalsky for Shrine
|
||||||
|
* [Pyramid](https://thenounproject.com/term/pyramid/17225/) by Oscar Yáñez for Mayan Pyramid
|
||||||
* [Great Wall Of China](https://thenounproject.com/term/great-wall-of-china/146039/) By Arthur Shlain for Walls
|
* [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
|
* [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
|
* [Block](https://thenounproject.com/term/block/1711553/) By Monjin Friends for Stone Works
|
||||||
@ -571,6 +573,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [royal crown](https://thenounproject.com/term/royal-crown/2054222/) by Vectors Market
|
* [royal crown](https://thenounproject.com/term/royal-crown/2054222/) by Vectors Market
|
||||||
* [Spear](https://thenounproject.com/term/spear/3930020/) by Firza Alamsyah
|
* [Spear](https://thenounproject.com/term/spear/3930020/) by Firza Alamsyah
|
||||||
* [pennant](https://thenounproject.com/term/pennant/194797/) by Sara Jeffries
|
* [pennant](https://thenounproject.com/term/pennant/194797/) by Sara Jeffries
|
||||||
|
* [Maya civilization](https://thenounproject.com/term/maya-civilization/1715786/) by Olena Panasovska for The Maya
|
||||||
|
|
||||||
## Promotions
|
## Promotions
|
||||||
|
|
||||||
@ -662,6 +665,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [tick](https://thenounproject.com/term/tick/3968142/) by Adrien Coquet on Nation picker
|
* [tick](https://thenounproject.com/term/tick/3968142/) by Adrien Coquet on Nation picker
|
||||||
* [people](https://thenounproject.com/term/people/458671) by Wilson Joseph as base for Civilopedia category Nations
|
* [people](https://thenounproject.com/term/people/458671) by Wilson Joseph as base for Civilopedia category Nations
|
||||||
* [Mountains ](https://thenounproject.com/term/mountains/15616/) by Andrew J. Young as base for Civilopedia category Terrains
|
* [Mountains ](https://thenounproject.com/term/mountains/15616/) by Andrew J. Young as base for Civilopedia category Terrains
|
||||||
|
* [File:Maya.svg](https://en.wikipedia.org/wiki/File:Maya.svg) for Mayan numerals
|
||||||
|
* [East side of stela C, Quirigua](https://en.wikipedia.org/wiki/File:East_side_of_stela_C,_Quirigua.PNG) for Mayan calendar symbols
|
||||||
|
|
||||||
## Main menu
|
## Main menu
|
||||||
|
|
||||||
|