* 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
This commit is contained in:
SomeTroglodyte 2021-10-09 19:45:59 +02:00 committed by GitHub
parent 69e1792fa9
commit 7bbcb8db1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 755 additions and 313 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 KiB

After

Width:  |  Height:  |  Size: 704 KiB

View File

@ -51,6 +51,17 @@
"requiredTech": "Pottery",
"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",
"culture": 1,

View File

@ -932,6 +932,48 @@
"Nekemte","Asella","Dila","Adigrat","Debre Markos","Kombolcha","Debre Tabor","Sebeta",
"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
{

View File

@ -124,6 +124,20 @@
"promotions": ["Slinger Withdraw"],
"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",

View File

@ -195,7 +195,7 @@
"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.",
"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 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.",
"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.",
"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 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.",
"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."
],
"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!"
]
}

View File

@ -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 =
Your city [cityName] was converted to [religionName]! =
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
@ -715,6 +718,13 @@ Do you want to exit the game? =
Start bias: =
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
Exit city =

View File

@ -18,10 +18,8 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.audio.MusicMood
import com.unciv.ui.audio.MusicTrackChooserFlags
import com.unciv.models.ruleset.unit.BaseUnit
import java.util.*
import kotlin.math.min
import kotlin.math.pow
class UncivShowableException(missingMods: String) : Exception(missingMods)
@ -150,6 +148,48 @@ class GameInfo {
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
//region State changing functions

View File

@ -1,6 +1,7 @@
package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException
@ -25,6 +26,7 @@ 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.utils.MayaCalendar
import com.unciv.ui.utils.toPercent
import com.unciv.ui.victoryscreen.RankingType
import java.util.*
@ -172,6 +174,9 @@ class CivilizationInfo {
var totalCultureForContests = 0
var totalFaithForContests = 0
@Transient
var hasLongCountDisplayUnique = false
constructor()
constructor(civName: String) {
@ -623,8 +628,10 @@ class CivilizationInfo {
fun getGreatPeople(): HashSet<BaseUnit> {
val greatPeople = gameInfo.ruleSet.units.values.asSequence()
.filter { it.isGreatPerson() }.map { getEquivalentUnit(it.name) }
return if (!gameInfo.isReligionEnabled()) greatPeople.filter { !it.uniques.contains("Hidden when religion is disabled")}.toHashSet()
.filter { it.isGreatPerson() }
.map { getEquivalentUnit(it.name) }
return if (!gameInfo.isReligionEnabled())
greatPeople.filter { !it.hasUnique(Constants.hiddenWithoutReligionUnique) }.toHashSet()
else greatPeople.toHashSet()
}
@ -634,6 +641,13 @@ class CivilizationInfo {
fun isMinorCivAggressor() = numMinorCivsAttacked >= 2
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
//region state-changing functions
@ -701,6 +715,8 @@ class CivilizationInfo {
if (lastEraForUnit != null)
lastEraResourceUsedForUnit[resource] = lastEraForUnit
}
hasLongCountDisplayUnique = hasUnique(UniqueType.MayanCalendarDisplay)
}
fun updateSightAndResources() {
@ -729,6 +745,8 @@ class CivilizationInfo {
val greatPerson = greatPeople.getNewGreatPerson()
if (greatPerson != null && gameInfo.ruleSet.units.containsKey(greatPerson)) addUnit(greatPerson)
religionManager.startTurn()
if (isLongCountActive())
MayaCalendar.startTurnForMaya(this)
}
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better

View File

@ -1,8 +1,11 @@
package com.unciv.logic.civilization
import com.unciv.models.Counter
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import java.util.HashSet
// 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 {
var pointsForNextGreatPerson = 100
@ -11,7 +14,10 @@ class GreatPersonManager {
var greatPersonPointsCounter = Counter<String>()
var greatGeneralPoints = 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 {
val toReturn = GreatPersonManager()
@ -20,12 +26,12 @@ class GreatPersonManager {
toReturn.pointsForNextGreatPerson = pointsForNextGreatPerson
toReturn.pointsForNextGreatGeneral = pointsForNextGreatGeneral
toReturn.greatGeneralPoints = greatGeneralPoints
toReturn.mayaLimitedFreeGP = mayaLimitedFreeGP
toReturn.longCountGPPool = longCountGPPool.toHashSet()
return toReturn
}
fun getNewGreatPerson(): String? {
val greatPerson: String? = null
if (greatGeneralPoints > pointsForNextGreatGeneral) {
greatGeneralPoints -= pointsForNextGreatGeneral
pointsForNextGreatGeneral += 50
@ -39,7 +45,7 @@ class GreatPersonManager {
return key
}
}
return greatPerson
return null
}
fun addGreatPersonPoints(greatPersonPointsForTurn: Counter<String>) {

View File

@ -3,11 +3,14 @@ package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2
import com.unciv.models.stats.Stat
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.pickerscreens.PolicyPickerScreen
import com.unciv.ui.pickerscreens.TechPickerScreen
import com.unciv.ui.trade.DiplomacyScreen
import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.worldscreen.WorldScreen
object NotificationIcon {
// Remember: The typical white-on-transparency icon will not be visible on Notifications
const val Culture = "StatIcons/Culture"
const val Construction = "StatIcons/Production"
const val Growth = "StatIcons/Population"
@ -21,7 +24,7 @@ object NotificationIcon {
const val Citadel = "ImprovementIcons/Citadel"
const val Happiness = "StatIcons/Happiness"
const val Population = "StatIcons/Population"
const val CityState = "NationIcons/CityState"
const val CityState = "OtherIcons/CityState"
const val Production = "StatIcons/Production"
const val Food = "StatIcons/Food"
const val Faith = "StatIcons/Faith"
@ -82,6 +85,7 @@ data class CityAction(val city: Vector2 = Vector2.Zero): NotificationAction {
}
}
/** enter diplomacy screen */
data class DiplomacyAction(val otherCivName: String = ""): NotificationAction {
override fun execute(worldScreen: WorldScreen) {
val screen = DiplomacyScreen(worldScreen.viewingCiv)
@ -89,3 +93,10 @@ data class DiplomacyAction(val otherCivName: String = ""): NotificationAction {
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())
}
}

View File

@ -7,7 +7,9 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.unique.UniqueMap
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.withItem
import java.util.*
@ -310,6 +312,10 @@ class TechManager {
if (unique.params[1] != techName) continue
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) {

View File

@ -42,6 +42,7 @@ enum class Tutorial(val value: String, val isCivilopedia: Boolean = !value.start
Beliefs("Beliefs"),
SpreadingReligion("Spreading_Religion"),
Inquisitors("Inquisitors"),
MayanCalendar("Maya_Long_Count_calendar_cycle"),
;
companion object {

View File

@ -178,6 +178,13 @@ enum class UniqueParameterType(val parameterName:String) {
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 */
Comment("comment") {
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):

View File

@ -11,6 +11,7 @@ import com.unciv.models.ruleset.VictoryType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.hasPlaceholderParameters
import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.worldscreen.unit.UnitActions
import kotlin.random.Random
@ -113,17 +114,29 @@ object UniqueTriggerActivation {
}
return true
}
OneTimeFreeGreatPerson -> {
OneTimeFreeGreatPerson, MayanGainGreatPerson -> {
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()) {
civInfo.greatPeople.freeGreatPeople++
if (unique.type == MayanGainGreatPerson) {
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
} else {
val greatPeople = civInfo.getGreatPeople()
if (unique.type == MayanGainGreatPerson)
greatPeople.removeAll { it.name !in civInfo.greatPeople.longCountGPPool }
if (greatPeople.isEmpty()) return false
var greatPerson = civInfo.getGreatPeople().random()
var greatPerson = greatPeople.random()
val preferredVictoryType = civInfo.victoryType()
if (preferredVictoryType == VictoryType.Cultural) {
@ -137,6 +150,8 @@ object UniqueTriggerActivation {
if (scientificGP != null) greatPerson = scientificGP
}
if (unique.type == MayanGainGreatPerson)
civInfo.greatPeople.longCountGPPool.remove(greatPerson.name)
return civInfo.addUnit(greatPerson.name, chosenCity) != null
}
}

View File

@ -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),
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 /////////////////////////////////////////
FoundCity("Founds a new city", UniqueTarget.Unit),

View File

@ -189,6 +189,7 @@ class FormattedLine (
result[it.second] = 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")
rulesetCachedInNameMap = ruleSet

View File

@ -7,6 +7,7 @@ import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.isEnabled
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
@ -14,23 +15,23 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() {
private var theChosenOne: BaseUnit? = null
init {
closeButton.isVisible=false
closeButton.isVisible = false
rightSideButton.setText("Choose a free great person".tr())
val greatPersonUnits = civInfo.getGreatPeople()
for (unit in greatPersonUnits)
{
val useMayaLongCount = civInfo.greatPeople.mayaLimitedFreeGP > 0
for (unit in greatPersonUnits) {
val button = Button(skin)
button.add(ImageGetter.getUnitIcon(unit.name)).size(30f).pad(10f)
button.add(unit.name.toLabel()).pad(10f)
button.pack()
button.onClick {
button.isEnabled = !useMayaLongCount || unit.name in civInfo.greatPeople.longCountGPPool
if (button.isEnabled) button.onClick {
theChosenOne = unit
val unitDescription=HashSet<String>()
unit.uniques.forEach { unitDescription.add(it.tr()) }
pick("Get [${unit.name}]".tr())
descriptionLabel.setText(unitDescription.joinToString())
descriptionLabel.setText(unit.getShortDescription())
}
topTable.add(button).pad(10f).row()
}
@ -38,6 +39,10 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() {
rightSideButton.onClick(UncivSound.Choir) {
civInfo.addUnit(theChosenOne!!.name, civInfo.getCapital())
civInfo.greatPeople.freeGreatPeople--
if (useMayaLongCount) {
civInfo.greatPeople.mayaLimitedFreeGP--
civInfo.greatPeople.longCountGPPool.remove(theChosenOne!!.name)
}
UncivGame.Current.setWorldScreen()
}

View File

@ -98,6 +98,10 @@ class NativeBitmapFontData(
Fonts.culture -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Culture").region)
Fonts.faith -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Faith").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)
}
}

View 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)
}
}

View File

@ -4,9 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.unciv.logic.GameInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
@ -64,7 +62,14 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
private fun getResourceTable(): Table {
val resourceTable = Table()
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)
val revealedStrategicResources = worldScreen.gameInfo.ruleSet.tileResources.values
.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())
}
val year = getYear(civInfo.gameInfo.gameParameters.gameSpeed, getEquivalentTurn(civInfo.gameInfo)).toInt()
val yearText = "[" + abs(year) + "] " + if (year < 0) "BC" else "AD"
val year = civInfo.gameInfo.getYear()
val yearText = if (civInfo.isLongCountDisplay()) MayaCalendar.yearToMayaDate(year)
else "[" + abs(year) + "] " + (if (year < 0) "BC" else "AD")
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns + " | " + yearText.tr())
val nextTurnStats = civInfo.statsForNextTurn
@ -275,40 +280,4 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
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)
}
}

View File

@ -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
* [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
* [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
* [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.
@ -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
* [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
* [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
@ -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
* [Spear](https://thenounproject.com/term/spear/3930020/) by Firza Alamsyah
* [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
@ -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
* [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
* [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