mirror of
https://github.com/yairm210/Unciv.git
synced 2025-08-01 15:49:46 +07:00
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
This commit is contained in:
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>) {
|
||||
|
@ -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,10 +85,18 @@ 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)
|
||||
screen.updateRightSide(worldScreen.gameInfo.getCivilization(otherCivName))
|
||||
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.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) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.unciv.models
|
||||
|
||||
enum class Tutorial(val value: String, val isCivilopedia: Boolean = !value.startsWith("_")) {
|
||||
|
||||
|
||||
Introduction("Introduction"),
|
||||
NewGame("New_Game"),
|
||||
SlowStart("_Slow_Start"),
|
||||
@ -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 {
|
||||
|
@ -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):
|
||||
|
@ -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 (notification != null)
|
||||
civInfo.addNotification(notification) // Anyone an idea for a good icon?
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
@ -166,7 +170,7 @@ 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
|
||||
|
86
core/src/com/unciv/ui/utils/MayaCalendar.kt
Normal file
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.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)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user