Victory illustrations (#9934)
* Victory Screen Illustrations page * Fix WorldReligion victory disclosing random player count * Victory screen icons and Victory types get their separately moddable path * Merge fix and nicer wiki text * VictoryScreenIllustrations debug run * Fix Image sizing and some polishing * Fix white squares on some Victory Screen Cultural milestone buttons
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/Demographics.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/Global.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/Illustration.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/OurStatus.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/Rankings.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
android/Images.NationIcons/VictoryScreenIcons/Replay.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
android/Images.NationIcons/VictoryTypeIcons/Cultural.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
android/Images.NationIcons/VictoryTypeIcons/Diplomatic.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
android/Images.NationIcons/VictoryTypeIcons/Domination.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
android/Images.NationIcons/VictoryTypeIcons/Scientific.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
android/Images.NationIcons/VictoryTypeIcons/Time.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
@ -6,266 +6,350 @@ filter: MipMapLinearLinear, MipMapLinearLinear
|
|||||||
repeat: none
|
repeat: none
|
||||||
NationIcons/America
|
NationIcons/America
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 328
|
xy: 4, 278
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Arabia
|
NationIcons/Arabia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 220
|
xy: 127, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Austria
|
NationIcons/Austria
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 112, 328
|
xy: 4, 170
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Aztecs
|
NationIcons/Aztecs
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 112
|
xy: 235, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Babylon
|
NationIcons/Babylon
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 112, 220
|
xy: 4, 62
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Barbarians
|
NationIcons/Barbarians
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 220, 328
|
xy: 343, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Byzantium
|
NationIcons/Byzantium
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 4
|
xy: 451, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Carthage
|
NationIcons/Carthage
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 112, 112
|
xy: 559, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Celts
|
NationIcons/Celts
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 220, 220
|
xy: 667, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/China
|
NationIcons/China
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 328, 328
|
xy: 883, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/CityState
|
NationIcons/CityState
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 112, 4
|
xy: 991, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Denmark
|
NationIcons/Denmark
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 220, 112
|
xy: 1315, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Egypt
|
NationIcons/Egypt
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 328, 220
|
xy: 1531, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/England
|
NationIcons/England
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 436, 328
|
xy: 1639, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Ethiopia
|
NationIcons/Ethiopia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 220, 4
|
xy: 1747, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/France
|
NationIcons/France
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 328, 112
|
xy: 1855, 401
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Germany
|
NationIcons/Germany
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 436, 220
|
xy: 112, 278
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Greece
|
NationIcons/Greece
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 544, 328
|
xy: 112, 170
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Inca
|
NationIcons/Inca
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 328, 4
|
xy: 220, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/India
|
NationIcons/India
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 436, 112
|
xy: 220, 185
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Iroquois
|
NationIcons/Iroquois
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 544, 220
|
xy: 328, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Japan
|
NationIcons/Japan
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 328
|
xy: 220, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Korea
|
NationIcons/Korea
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 436, 4
|
xy: 328, 185
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Mongolia
|
NationIcons/Mongolia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 544, 112
|
xy: 436, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Persia
|
NationIcons/Persia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 220
|
xy: 436, 185
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Polynesia
|
NationIcons/Polynesia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 328
|
xy: 544, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Random
|
NationIcons/Random
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 544, 4
|
xy: 436, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Rome
|
NationIcons/Rome
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 112
|
xy: 652, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Russia
|
NationIcons/Russia
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 220
|
xy: 544, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Siam
|
NationIcons/Siam
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 328
|
xy: 760, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Songhai
|
NationIcons/Songhai
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 652, 4
|
xy: 652, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Spain
|
NationIcons/Spain
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 112
|
xy: 760, 185
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Spectator
|
NationIcons/Spectator
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 220
|
xy: 868, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/Sweden
|
NationIcons/Sweden
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 976, 328
|
xy: 760, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/The Huns
|
NationIcons/The Huns
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 760, 4
|
xy: 868, 185
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/The Maya
|
NationIcons/The Maya
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 868, 112
|
xy: 976, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/The Netherlands
|
NationIcons/The Netherlands
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 976, 220
|
xy: 868, 77
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
NationIcons/The Ottomans
|
NationIcons/The Ottomans
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1084, 328
|
xy: 976, 185
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Charts
|
||||||
|
rotate: false
|
||||||
|
xy: 775, 401
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Demographics
|
||||||
|
rotate: false
|
||||||
|
xy: 1207, 401
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Rankings
|
||||||
|
rotate: false
|
||||||
|
xy: 1207, 401
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Global
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 4
|
||||||
|
size: 50, 50
|
||||||
|
orig: 50, 50
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Illustration
|
||||||
|
rotate: false
|
||||||
|
xy: 112, 62
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/OurStatus
|
||||||
|
rotate: false
|
||||||
|
xy: 328, 77
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryScreenIcons/Replay
|
||||||
|
rotate: false
|
||||||
|
xy: 544, 185
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryTypeIcons/Cultural
|
||||||
|
rotate: false
|
||||||
|
xy: 1099, 401
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryTypeIcons/Diplomatic
|
||||||
|
rotate: false
|
||||||
|
xy: 1423, 401
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryTypeIcons/Domination
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 386
|
||||||
|
size: 115, 115
|
||||||
|
orig: 115, 115
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryTypeIcons/Scientific
|
||||||
|
rotate: false
|
||||||
|
xy: 652, 185
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
VictoryTypeIcons/Time
|
||||||
|
rotate: false
|
||||||
|
xy: 1084, 293
|
||||||
size: 100, 100
|
size: 100, 100
|
||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 227 KiB |
Before Width: | Height: | Size: 519 KiB After Width: | Height: | Size: 514 KiB |
@ -1411,6 +1411,7 @@ Destroy [civName] =
|
|||||||
Capture [cityName] =
|
Capture [cityName] =
|
||||||
Destroy ? * [civName] =
|
Destroy ? * [civName] =
|
||||||
Capture ? * [cityName] =
|
Capture ? * [cityName] =
|
||||||
|
Majority religion of ? * [civName] =
|
||||||
Our status =
|
Our status =
|
||||||
Global status =
|
Global status =
|
||||||
Rankings =
|
Rankings =
|
||||||
|
@ -246,9 +246,11 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
|
|||||||
}
|
}
|
||||||
|
|
||||||
MilestoneType.WorldReligion -> {
|
MilestoneType.WorldReligion -> {
|
||||||
|
val hideCivCount = civInfo.hideCivCount()
|
||||||
val majorCivs = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it.isAlive() }
|
val majorCivs = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it.isAlive() }
|
||||||
val civReligion = civInfo.religionManager.religion
|
val civReligion = civInfo.religionManager.religion
|
||||||
for (civ in majorCivs) {
|
for (civ in majorCivs) {
|
||||||
|
if (hideCivCount && !civInfo.knows(civ)) continue
|
||||||
val milestoneText =
|
val milestoneText =
|
||||||
if (civInfo.knows(civ)) "Majority religion of [${civ.civName}]"
|
if (civInfo.knows(civ)) "Majority religion of [${civ.civName}]"
|
||||||
else "Majority religion of [${Constants.unknownNationName}]"
|
else "Majority religion of [${Constants.unknownNationName}]"
|
||||||
@ -257,6 +259,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
|
|||||||
&& civ.religionManager.isMajorityReligionForCiv(civReligion)
|
&& civ.religionManager.isMajorityReligionForCiv(civReligion)
|
||||||
buttons.add(getMilestoneButton(milestoneText, milestoneMet))
|
buttons.add(getMilestoneButton(milestoneText, milestoneMet))
|
||||||
}
|
}
|
||||||
|
if (hideCivCount) buttons.add(getMilestoneButton("Majority religion of ? * [${Constants.unknownCityName}]", false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buttons
|
return buttons
|
||||||
|
@ -228,18 +228,22 @@ object Fonts {
|
|||||||
val charToRulesetImageActor = HashMap<Char, Actor>()
|
val charToRulesetImageActor = HashMap<Char, Actor>()
|
||||||
// See https://en.wikipedia.org/wiki/Private_Use_Areas - char encodings 57344 63743 are not assigned
|
// See https://en.wikipedia.org/wiki/Private_Use_Areas - char encodings 57344 63743 are not assigned
|
||||||
private var nextUnusedCharacterNumber = 57344
|
private var nextUnusedCharacterNumber = 57344
|
||||||
fun addRulesetImages(ruleset:Ruleset) {
|
fun addRulesetImages(ruleset: Ruleset) {
|
||||||
rulesetObjectNameToChar.clear()
|
rulesetObjectNameToChar.clear()
|
||||||
charToRulesetImageActor.clear()
|
charToRulesetImageActor.clear()
|
||||||
nextUnusedCharacterNumber = 57344
|
nextUnusedCharacterNumber = 57344
|
||||||
|
|
||||||
fun addChar(objectName:String, objectActor: Actor){
|
fun addChar(objectName: String, objectActor: Actor) {
|
||||||
val char = Char(nextUnusedCharacterNumber)
|
val char = Char(nextUnusedCharacterNumber)
|
||||||
nextUnusedCharacterNumber++
|
nextUnusedCharacterNumber++
|
||||||
rulesetObjectNameToChar[objectName] = char
|
rulesetObjectNameToChar[objectName] = char
|
||||||
charToRulesetImageActor[char] = objectActor
|
charToRulesetImageActor[char] = objectActor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: If an image is missing, these will insert a white square in the font - acceptable in
|
||||||
|
// most cases as these white squares will be visible elsewhere anyway. "Policy branch Complete"
|
||||||
|
// is an exception, and therefore gets an existence test.
|
||||||
|
|
||||||
for (resourceName in ruleset.tileResources.keys)
|
for (resourceName in ruleset.tileResources.keys)
|
||||||
addChar(resourceName, ImageGetter.getResourcePortrait(resourceName, ORIGINAL_FONT_SIZE))
|
addChar(resourceName, ImageGetter.getResourcePortrait(resourceName, ORIGINAL_FONT_SIZE))
|
||||||
|
|
||||||
@ -264,6 +268,7 @@ object Fonts {
|
|||||||
for (policy in ruleset.policies.values) {
|
for (policy in ruleset.policies.values) {
|
||||||
val fileLocation = if (policy.name in ruleset.policyBranches)
|
val fileLocation = if (policy.name in ruleset.policyBranches)
|
||||||
"PolicyBranchIcons/" + policy.name else "PolicyIcons/" + policy.name
|
"PolicyBranchIcons/" + policy.name else "PolicyIcons/" + policy.name
|
||||||
|
if (!ImageGetter.imageExists(fileLocation)) continue
|
||||||
addChar(policy.name, ImageGetter.getImage(fileLocation).apply { setSize(ORIGINAL_FONT_SIZE) })
|
addChar(policy.name, ImageGetter.getImage(fileLocation).apply { setSize(ORIGINAL_FONT_SIZE) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,8 @@ open class TabbedPager(
|
|||||||
private val deferredSecretPages = ArrayDeque<PageState>(0)
|
private val deferredSecretPages = ArrayDeque<PageState>(0)
|
||||||
private var askPasswordLock = false
|
private var askPasswordLock = false
|
||||||
|
|
||||||
|
private var onSelectionCallback: ((Int, String, TabbedPager) -> Unit)? = null
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region Public Interfaces
|
//region Public Interfaces
|
||||||
|
|
||||||
@ -443,6 +445,7 @@ open class TabbedPager(
|
|||||||
headerScroll.run { scrollX = scrollX.coerceIn((page.buttonX + page.buttonW - scrollWidth)..page.buttonX) }
|
headerScroll.run { scrollX = scrollX.coerceIn((page.buttonX + page.buttonW - scrollWidth)..page.buttonX) }
|
||||||
|
|
||||||
(page.content as? IPageExtensions)?.activated(index, page.caption, this)
|
(page.content as? IPageExtensions)?.activated(index, page.caption, this)
|
||||||
|
onSelectionCallback?.invoke(index, page.caption, this)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -717,4 +720,9 @@ open class TabbedPager(
|
|||||||
page.buttonX += addWidth
|
page.buttonX += addWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Alternative selection handler to [IPageExtensions.activated] */
|
||||||
|
fun onSelection(action: ((index: Int, caption: String, pager: TabbedPager) -> Unit)?) {
|
||||||
|
onSelectionCallback = action
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,32 +43,35 @@ class VictoryScreen(
|
|||||||
|
|
||||||
private enum class VictoryTabs(
|
private enum class VictoryTabs(
|
||||||
val key: Char,
|
val key: Char,
|
||||||
val iconName: String = "",
|
|
||||||
val caption: String? = null,
|
val caption: String? = null,
|
||||||
val allowAsSecret: Boolean = false
|
val allowAsSecret: Boolean = false
|
||||||
) {
|
) {
|
||||||
OurStatus('O', "StatIcons/Specialist", caption = "Our status") {
|
OurStatus('O', caption = "Our status") {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenOurVictory(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenOurVictory(parent.worldScreen)
|
||||||
override fun isHidden(playerCiv: Civilization) = playerCiv.isSpectator()
|
override fun isHidden(playerCiv: Civilization) = playerCiv.isSpectator()
|
||||||
},
|
},
|
||||||
Global('G', "OtherIcons/Nations", caption = "Global status") {
|
Global('G', caption = "Global status") {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenGlobalVictory(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenGlobalVictory(parent.worldScreen)
|
||||||
},
|
},
|
||||||
Demographics('D', "CityStateIcons/Cultured", allowAsSecret = true) {
|
Illustration('I', allowAsSecret = true) {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenDemographics(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenIllustrations(parent, parent.worldScreen)
|
||||||
|
override fun isHidden(playerCiv: Civilization) = !VictoryScreenIllustrations.enablePage(playerCiv.gameInfo)
|
||||||
|
},
|
||||||
|
Demographics('D', allowAsSecret = true) {
|
||||||
|
override fun getContent(parent: VictoryScreen) = VictoryScreenDemographics(parent.worldScreen)
|
||||||
override fun isHidden(playerCiv: Civilization) = !UncivGame.Current.settings.useDemographics
|
override fun isHidden(playerCiv: Civilization) = !UncivGame.Current.settings.useDemographics
|
||||||
},
|
},
|
||||||
Rankings('R', "CityStateIcons/Cultured", allowAsSecret = true) {
|
Rankings('R', allowAsSecret = true) {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenCivRankings(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenCivRankings(parent.worldScreen)
|
||||||
override fun isHidden(playerCiv: Civilization) = UncivGame.Current.settings.useDemographics
|
override fun isHidden(playerCiv: Civilization) = UncivGame.Current.settings.useDemographics
|
||||||
},
|
},
|
||||||
Charts('C', "OtherIcons/Charts") {
|
Charts('C') {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenCharts(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenCharts(parent.worldScreen)
|
||||||
override fun isHidden(playerCiv: Civilization) =
|
override fun isHidden(playerCiv: Civilization) =
|
||||||
!playerCiv.isSpectator() && playerCiv.statsHistory.size < 2
|
!playerCiv.isSpectator() && playerCiv.statsHistory.size < 2
|
||||||
},
|
},
|
||||||
Replay('P', "OtherIcons/Load", allowAsSecret = true) {
|
Replay('P', allowAsSecret = true) {
|
||||||
override fun getContent(worldScreen: WorldScreen) = VictoryScreenReplay(worldScreen)
|
override fun getContent(parent: VictoryScreen) = VictoryScreenReplay(parent.worldScreen)
|
||||||
override fun isHidden(playerCiv: Civilization) =
|
override fun isHidden(playerCiv: Civilization) =
|
||||||
!playerCiv.isSpectator()
|
!playerCiv.isSpectator()
|
||||||
&& playerCiv.gameInfo.victoryData == null
|
&& playerCiv.gameInfo.victoryData == null
|
||||||
@ -77,7 +80,7 @@ class VictoryScreen(
|
|||||||
// slider doesn't look weird.
|
// slider doesn't look weird.
|
||||||
&& playerCiv.gameInfo.turns < 5
|
&& playerCiv.gameInfo.turns < 5
|
||||||
};
|
};
|
||||||
abstract fun getContent(worldScreen: WorldScreen): Table
|
abstract fun getContent(parent: VictoryScreen): Table
|
||||||
open fun isHidden(playerCiv: Civilization) = false
|
open fun isHidden(playerCiv: Civilization) = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,10 +93,10 @@ class VictoryScreen(
|
|||||||
val tabHidden = tab.isHidden(playerCiv)
|
val tabHidden = tab.isHidden(playerCiv)
|
||||||
if (tabHidden && !(tab.allowAsSecret && Gdx.input.areSecretKeysPressed()))
|
if (tabHidden && !(tab.allowAsSecret && Gdx.input.areSecretKeysPressed()))
|
||||||
continue
|
continue
|
||||||
val icon = if (tab.iconName.isEmpty()) null else ImageGetter.getImage(tab.iconName)
|
val icon = ImageGetter.getImage("VictoryScreenIcons/${tab.name}")
|
||||||
tabs.addPage(
|
tabs.addPage(
|
||||||
tab.caption ?: tab.name,
|
tab.caption ?: tab.name,
|
||||||
tab.getContent(worldScreen),
|
tab.getContent(this),
|
||||||
icon, iconSize,
|
icon, iconSize,
|
||||||
scrollAlign = Align.topLeft,
|
scrollAlign = Align.topLeft,
|
||||||
shortcutKey = KeyCharAndCode(tab.key),
|
shortcutKey = KeyCharAndCode(tab.key),
|
||||||
|
@ -0,0 +1,323 @@
|
|||||||
|
package com.unciv.ui.screens.victoryscreen
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import com.badlogic.gdx.math.Interpolation
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Container
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Stack
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.utils.Drawable
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable
|
||||||
|
import com.badlogic.gdx.utils.Align
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import com.unciv.logic.GameInfo
|
||||||
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.ruleset.MilestoneType
|
||||||
|
import com.unciv.models.ruleset.Victory
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.components.TabbedPager
|
||||||
|
import com.unciv.ui.components.extensions.isNarrowerThan4to3
|
||||||
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
|
import com.unciv.ui.components.input.KeyCharAndCode
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
|
import com.unciv.ui.images.ImageWithCustomSize // Kdoc, not used
|
||||||
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
|
||||||
|
// todo Idea: use victoryCompletePercent to allow "percentage" images - e.g. "Destroy all players" now works all or nothing - boring.
|
||||||
|
// (requires some rework of the victoryCompletePercent here and similar code in VictoryManager - and likely move stuff to make MilestoneType an intelligent enum)
|
||||||
|
|
||||||
|
class VictoryScreenIllustrations(
|
||||||
|
parent: VictoryScreen,
|
||||||
|
worldScreen: WorldScreen
|
||||||
|
) : Table(BaseScreen.skin), TabbedPager.IPageExtensions {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val fadeDuration = 1.2f
|
||||||
|
private const val basePath = "VictoryIllustrations"
|
||||||
|
private const val iconPath = "VictoryTypeIcons"
|
||||||
|
private val enablingImages = listOf("Won", "Lost", "Background")
|
||||||
|
|
||||||
|
/** Check whether the entire "Illustrations" tab in VictoryScreen should display */
|
||||||
|
internal fun enablePage(game: GameInfo) = game.getEnabledVictories().values
|
||||||
|
.any { it.hasIllustrations() }
|
||||||
|
|
||||||
|
/** Check whether a Victory has enough images to display that Victory's sub-tab */
|
||||||
|
private fun Victory.hasIllustrations() = enablingImages.any { element ->
|
||||||
|
ImageGetter.imageExists(getImageName(this, element))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build a texture atlas path for a [victory] and an "[element]", which can be a Milestone name or other Decoration part name */
|
||||||
|
private fun getImageName(victory: Victory, element: String) =
|
||||||
|
"$basePath/${victory.name}/$element"
|
||||||
|
|
||||||
|
/** Gets an image if it exists as [ImageWithFixedPrefSize] */
|
||||||
|
private fun getImageOrNull(name: String) =
|
||||||
|
if (ImageGetter.imageExists(name))
|
||||||
|
// ImageGetter.getImage uses ImageWithCustomSize which interferes incorrectly with our sizing
|
||||||
|
ImageWithFixedPrefSize(ImageGetter.getDrawable(name)) else null
|
||||||
|
|
||||||
|
/** Gets an image if a texture for [victory] and [element] exists (see [getImageName]) as [ImageWithFixedPrefSize] */
|
||||||
|
private fun getImageOrNull(victory: Victory, element: String) =
|
||||||
|
getImageOrNull(getImageName(victory, element))
|
||||||
|
|
||||||
|
/** Readability shortcut for [getImages] */
|
||||||
|
private fun MutableList<Actor>.addImageIf(victory: Victory, element: String, test: () -> Boolean) {
|
||||||
|
if (!test()) return
|
||||||
|
val image = getImageOrNull(victory, element)
|
||||||
|
if (image != null) add(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val game = worldScreen.gameInfo
|
||||||
|
private val maxLabelWidth = parent.stage.run { width * (if (isNarrowerThan4to3()) 0.9f else 0.7f) }
|
||||||
|
private val victories = game.getEnabledVictories().values
|
||||||
|
.filter { it.hasIllustrations() }
|
||||||
|
.sortedBy { it.name.tr(hideIcons = true) }
|
||||||
|
private val selectedCiv = worldScreen.selectedCiv
|
||||||
|
private val completionPercentages = game.civilizations
|
||||||
|
.filter { it.isMajorCiv() && it.isAlive() || it == selectedCiv }
|
||||||
|
.associateWith { civ ->
|
||||||
|
victories.associateWith { victoryCompletePercent(it, civ) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val tabs = TabbedPager(backgroundColor = Color.CLEAR, shortcutScreen = parent, capacity = victories.size)
|
||||||
|
private val holder = Stack()
|
||||||
|
|
||||||
|
private var selectedVictory = selectVictory()
|
||||||
|
|
||||||
|
init {
|
||||||
|
top()
|
||||||
|
holder.touchable = Touchable.disabled
|
||||||
|
|
||||||
|
for (victory in victories) {
|
||||||
|
val iconName = "$iconPath/${victory.name}"
|
||||||
|
val icon = getImageOrNull(iconName)
|
||||||
|
val key = KeyCharAndCode(victory.name.first())
|
||||||
|
tabs.addPage(victory.name, holder, icon, 20f, shortcutKey = key)
|
||||||
|
}
|
||||||
|
|
||||||
|
tabs.selectPage(selectedVictory)
|
||||||
|
add(tabs).top().grow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Activates content for [selectedVictory]. Images are loaded and [FadeTo] animation started. */
|
||||||
|
// Note the little trick - all tabs of our inner per-Victory TabbedPager contain the same holder,
|
||||||
|
// So we can fade over from one Victory to the next.
|
||||||
|
private fun select() {
|
||||||
|
val victory = victories.firstOrNull { it.name == selectedVictory } ?: return
|
||||||
|
tabs.onSelection(null) // Prevent recursion from replacePage
|
||||||
|
// todo measure: 265f = PickerPane.bottomTable.height + SplitPane.handle.height + 2* TabbedPager.header.height + separator.height
|
||||||
|
val maxHeight = stage.height - 265f
|
||||||
|
val fadeAction = FadeTo(holder, getImages(victory), maxHeight) // side effect: adds images to holder and packs it
|
||||||
|
tabs.replacePage(tabs.activePage, holder) // Force TabbedPager to measure content
|
||||||
|
holder.addAction(fadeAction)
|
||||||
|
tabs.onSelection { _, name, _ ->
|
||||||
|
selectedVictory = name
|
||||||
|
select()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** When the outer TabbedPager selects `this` page... */
|
||||||
|
override fun activated(index: Int, caption: String, pager: TabbedPager) {
|
||||||
|
pager.setScrollDisabled(true)
|
||||||
|
select()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** When the outer TabbedPager de-selects `this` page... */
|
||||||
|
override fun deactivated(index: Int, caption: String, pager: TabbedPager) {
|
||||||
|
pager.setScrollDisabled(false)
|
||||||
|
holder.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A specialized Gdx.Action for fading over one set (already loaded into [holder]) of images to
|
||||||
|
* another (from parameter [newActors]).
|
||||||
|
*
|
||||||
|
* Initialization has the ***side effects*** of stacking the new images into [holder],
|
||||||
|
* sizing them preserving aspect ratio (which is why it needs `maxHeight`: taking available
|
||||||
|
* width from holder.width works, same for height does not), and invalidating ascendants.
|
||||||
|
*/
|
||||||
|
private class FadeTo(
|
||||||
|
private val holder: Stack,
|
||||||
|
private val newActors: List<Actor>,
|
||||||
|
maxHeight: Float
|
||||||
|
) : TemporalAction(fadeDuration), Disposable {
|
||||||
|
private var oldActors: List<Actor>? = holder.children.toList() // nullable to allow relinquishing the references when done
|
||||||
|
private val fadeOutFrom = oldActors!!.firstOrNull()?.color?.a ?: 1f
|
||||||
|
|
||||||
|
init {
|
||||||
|
holder.actions.filterIsInstance<FadeTo>().forEach { it.dispose() }
|
||||||
|
holder.addAndSize(newActors, maxHeight)
|
||||||
|
holder.invalidateHierarchy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
finish()
|
||||||
|
end()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(percent: Float) {
|
||||||
|
val alpha = Interpolation.fade.apply(percent)
|
||||||
|
for (actor in newActors) actor.color.a = alpha
|
||||||
|
if (oldActors == null) return
|
||||||
|
val oldAlpha = Interpolation.fade.apply(1f - percent) * fadeOutFrom
|
||||||
|
for (actor in oldActors!!) actor.color.a = oldAlpha
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun end() {
|
||||||
|
val toRemove = oldActors ?: return
|
||||||
|
oldActors = null
|
||||||
|
for (actor in toRemove) holder.removeActor(actor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Stack.addAndSize(actors: List<Actor>, maxHeight: Float) {
|
||||||
|
// Local and not to be confused with Gdx or awt versions. We need a width/height container only
|
||||||
|
class Rectangle(var width: Float, var height: Float) {
|
||||||
|
constructor(region: TextureRegion) : this(region.regionWidth.toFloat(), region.regionHeight.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
for (actor in actors) {
|
||||||
|
actor.color.a = 0f
|
||||||
|
// actor.width, actor.height are empirically equal to the image's pixel dimensions
|
||||||
|
// at this moment, before actor has a parent, but I don't trust that happenstance.
|
||||||
|
val pixelArea = Rectangle(((actor as Image).drawable as TextureRegionDrawable).region)
|
||||||
|
// Scale max image dimensions into holder space minus padding preserving aspect ratio
|
||||||
|
val imageArea = Rectangle(this.width - 30f, maxHeight - 30f)
|
||||||
|
if (pixelArea.width * imageArea.height > imageArea.width * pixelArea.height)
|
||||||
|
imageArea.height = imageArea.width * pixelArea.height / pixelArea.width
|
||||||
|
else
|
||||||
|
imageArea.width = imageArea.height * pixelArea.width / pixelArea.height
|
||||||
|
actor.setSize(imageArea.width, imageArea.height)
|
||||||
|
if (actor is ImageWithFixedPrefSize) actor.setPrefSize(imageArea.width, imageArea.height)
|
||||||
|
add(actor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determine the Victory to show initially - try to select the most interesting one for the current game. */
|
||||||
|
private fun selectVictory(): String {
|
||||||
|
if (game.victoryData != null) return game.victoryData!!.victoryType
|
||||||
|
val victory = victories.asSequence()
|
||||||
|
.sortedWith(
|
||||||
|
compareByDescending<Victory> { victory ->
|
||||||
|
completionPercentages[selectedCiv]?.get(victory) ?: 0
|
||||||
|
}.thenByDescending { victory ->
|
||||||
|
game.civilizations.filter { it != selectedCiv && it.isMajorCiv() && it.isAlive() }
|
||||||
|
.maxOfOrNull { victoryCompletePercent(victory, it) } ?: 0
|
||||||
|
}
|
||||||
|
).firstOrNull() ?: victories.first()
|
||||||
|
return victory.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculate a completion percentage for a [victory] -
|
||||||
|
* relative weights for individual milestones are not equal in this implementation!
|
||||||
|
* (weight = number of sub-steps, or 2 if a milestone doesn't have any - very debatable)
|
||||||
|
*/
|
||||||
|
private fun victoryCompletePercent(victory: Victory, civ: Civilization): Int {
|
||||||
|
var points = 0
|
||||||
|
var total = 0
|
||||||
|
for (milestone in victory.milestoneObjects) {
|
||||||
|
val completed = milestone.hasBeenCompletedBy(civ)
|
||||||
|
val milestonePoints = when (milestone.type) {
|
||||||
|
MilestoneType.AddedSSPartsInCapital -> {
|
||||||
|
total += victory.requiredSpaceshipParts.size
|
||||||
|
civ.victoryManager.currentsSpaceshipParts.sumValues()
|
||||||
|
}
|
||||||
|
MilestoneType.DestroyAllPlayers -> {
|
||||||
|
total += if (selectedCiv.hideCivCount()) game.gameParameters.maxNumberOfPlayers
|
||||||
|
else game.civilizations.count { it.isMajorCiv() }
|
||||||
|
game.civilizations.count {
|
||||||
|
it != civ && it.isMajorCiv() && civ.knows(it) && it.isDefeated()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MilestoneType.CaptureAllCapitals -> {
|
||||||
|
total += if (selectedCiv.hideCivCount()) game.gameParameters.maxNumberOfPlayers
|
||||||
|
else game.getCities().count { it.isOriginalCapital }
|
||||||
|
civ.cities.count { it.isOriginalCapital }
|
||||||
|
}
|
||||||
|
MilestoneType.CompletePolicyBranches -> {
|
||||||
|
total += milestone.params[0].toInt()
|
||||||
|
civ.policies.completedBranches.size
|
||||||
|
}
|
||||||
|
MilestoneType.WorldReligion -> {
|
||||||
|
total += game.civilizations.count { it.isMajorCiv() && it.isAlive() }
|
||||||
|
val religion = civ.religionManager.religion?.takeUnless { it.isPantheon() }
|
||||||
|
game.civilizations.count {
|
||||||
|
religion != null &&
|
||||||
|
it.isMajorCiv() && it.isAlive() && civ.knows(it) &&
|
||||||
|
it.religionManager.isMajorityReligionForCiv(religion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MilestoneType.ScoreAfterTimeOut -> {
|
||||||
|
total += game.gameParameters.maxTurns
|
||||||
|
game.turns.coerceAtMost(game.gameParameters.maxTurns)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
total += 2
|
||||||
|
if (completed) 2 else 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points += milestonePoints
|
||||||
|
}
|
||||||
|
return points * 100 / total
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getImages(victory: Victory): List<Actor> {
|
||||||
|
game.victoryData?.run {
|
||||||
|
if (victory.name == victoryType && selectedCiv.civName == winningCiv) {
|
||||||
|
val image = getImageOrNull(victory, "Won")
|
||||||
|
return getWonOrLostStack(image, victory.victoryString, Color.GOLD)
|
||||||
|
}
|
||||||
|
val image = getImageOrNull(victory, "Lost")
|
||||||
|
return getWonOrLostStack(image, victory.defeatString.takeIf { victory.name == victoryType }, Color.MAROON)
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = mutableListOf<Actor>()
|
||||||
|
result.addImageIf(victory, "Background") { true }
|
||||||
|
for (milestone in victory.milestoneObjects) {
|
||||||
|
val element = milestone.uniqueDescription.replace("[", "").replace("]", "")
|
||||||
|
result.addImageIf(victory, element) { milestone.hasBeenCompletedBy(selectedCiv) }
|
||||||
|
if (milestone.type != MilestoneType.AddedSSPartsInCapital) continue
|
||||||
|
for ((key, required) in victory.requiredSpaceshipPartsAsCounter) {
|
||||||
|
val built = selectedCiv.victoryManager.currentsSpaceshipParts[key]
|
||||||
|
result.addImageIf(victory, key) { built > 0 }
|
||||||
|
for (i in 1..required)
|
||||||
|
result.addImageIf(victory, "$key $i") { built >= i }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWonOrLostStack(image: Image?, text: String?, color: Color): List<Actor> {
|
||||||
|
val container = if (text == null) null
|
||||||
|
else {
|
||||||
|
val label = text.toLabel(color, 50, Align.bottom)
|
||||||
|
label.wrap = true
|
||||||
|
label.width = maxLabelWidth
|
||||||
|
Container(label).apply { bottom() }
|
||||||
|
}
|
||||||
|
return listOfNotNull(image, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variant of [ImageWithCustomSize] that avoids certain problems.
|
||||||
|
*
|
||||||
|
* Reports a `prefWidth`/`prefHeight` set through [setPrefSize], which cannot be otherwise
|
||||||
|
* altered, especially not by ascendant layout methods, since they don't know the interface.
|
||||||
|
* This size defaults to the [drawable]'s minWidth/minHeight - same as what [Image] reports as
|
||||||
|
* `prefWidth`/`prefHeight` directly without the ability to override.
|
||||||
|
*/
|
||||||
|
private class ImageWithFixedPrefSize(drawable: Drawable) : Image(drawable) {
|
||||||
|
private var prefW: Float = prefWidth
|
||||||
|
private var prefH: Float = prefHeight
|
||||||
|
fun setPrefSize(w: Float, h: Float) {
|
||||||
|
prefW = w
|
||||||
|
prefH = h
|
||||||
|
}
|
||||||
|
override fun getPrefWidth() = prefW
|
||||||
|
override fun getPrefHeight() = prefH
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,17 @@
|
|||||||
package com.unciv.ui.screens.victoryscreen
|
package com.unciv.ui.screens.victoryscreen
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Stack
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.ruleset.MilestoneType
|
||||||
import com.unciv.models.ruleset.Victory
|
import com.unciv.models.ruleset.Victory
|
||||||
import com.unciv.ui.components.TabbedPager
|
import com.unciv.ui.components.TabbedPager
|
||||||
import com.unciv.ui.components.extensions.addSeparator
|
import com.unciv.ui.components.extensions.addSeparator
|
||||||
import com.unciv.ui.components.extensions.toLabel
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
import com.unciv.ui.screens.worldscreen.WorldScreen
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
|
||||||
@ -15,6 +19,7 @@ class VictoryScreenOurVictory(
|
|||||||
worldScreen: WorldScreen
|
worldScreen: WorldScreen
|
||||||
) : Table(BaseScreen.skin), TabbedPager.IPageExtensions {
|
) : Table(BaseScreen.skin), TabbedPager.IPageExtensions {
|
||||||
private val header = Table()
|
private val header = Table()
|
||||||
|
private val stageWidth = worldScreen.stage.width
|
||||||
|
|
||||||
init {
|
init {
|
||||||
align(Align.top)
|
align(Align.top)
|
||||||
@ -25,7 +30,7 @@ class VictoryScreenOurVictory(
|
|||||||
defaults().pad(10f)
|
defaults().pad(10f)
|
||||||
for ((victoryName, victory) in victoriesToShow) {
|
for ((victoryName, victory) in victoriesToShow) {
|
||||||
header.add("[$victoryName] Victory".toLabel()).pad(10f)
|
header.add("[$victoryName] Victory".toLabel()).pad(10f)
|
||||||
add(getColumn(victory, worldScreen.viewingCiv))
|
add(getColumn(victory, worldScreen.viewingCiv)).top()
|
||||||
}
|
}
|
||||||
|
|
||||||
row()
|
row()
|
||||||
|
@ -729,6 +729,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
- [Swords](https://thenounproject.com/icon/swords-1580316/) created by Muhajir ila Robbi for Blockaded tile marker
|
- [Swords](https://thenounproject.com/icon/swords-1580316/) created by Muhajir ila Robbi for Blockaded tile marker
|
||||||
- [Keyboard](https://thenounproject.com/icon/keyboard-2685534/) by Twenty Foo Studio for Options Keys
|
- [Keyboard](https://thenounproject.com/icon/keyboard-2685534/) by Twenty Foo Studio for Options Keys
|
||||||
- [charts](https://thenounproject.com/icon/charts-2312023/) by Srinivas Agra (gimped to appear bolder) for the Charts page
|
- [charts](https://thenounproject.com/icon/charts-2312023/) by Srinivas Agra (gimped to appear bolder) for the Charts page
|
||||||
|
- [framed image](https://thenounproject.com/icon/framed-image-2332187/) by Jose Dean for Victory Illustrations page
|
||||||
|
|
||||||
|
|
||||||
### Main menu
|
### Main menu
|
||||||
|
@ -70,6 +70,28 @@ The Unit Types as defined in [UnitTypes.json](Mod-file-structure/4-Unit-related-
|
|||||||
The individual Beliefs - as opposed to Belief types, as defined in [Beliefs.json](Mod-file-structure/2-Civilization-related-JSON-files.md#beliefsjson) have no icons in the base game, but Civilopedia can decorate their entries if you supply images named 'Images/ReligionIcons/<Belief>.png'.
|
The individual Beliefs - as opposed to Belief types, as defined in [Beliefs.json](Mod-file-structure/2-Civilization-related-JSON-files.md#beliefsjson) have no icons in the base game, but Civilopedia can decorate their entries if you supply images named 'Images/ReligionIcons/<Belief>.png'.
|
||||||
Civilopedia falls back to the icon for the Belief type - as you can see in the base game, but individual icons have precedence if they exist.
|
Civilopedia falls back to the icon for the Belief type - as you can see in the base game, but individual icons have precedence if they exist.
|
||||||
|
|
||||||
|
### Adding Victory illustrations
|
||||||
|
|
||||||
|
You can enable pictures for each of the Victories, illustrating their progress. That could be a Spaceship under construction, showing the parts you've added, or cultural progress as you complete Policy branches. They will be shown on a new tab of the Victory Screen.
|
||||||
|
|
||||||
|
For this, you need to create a number of images. In the following, `<>` denote names as they appear in [VictoryTypes.json](../Other/Miscellaneous-JSON-files.md#victorytypes-json), untranslated, and these file names (like any other in Unciv) are case-sensitive. All files are optional, except Background as noted:
|
||||||
|
* `VictoryIllustrations/<name>/Background.png` - this determines overall dimensions, the others must not exceed its size and should ideally have identical size. Mandatory, if this file is missing, no illustrations will be shown for this Victory Type.
|
||||||
|
* `VictoryIllustrations/<name>/Won.png` - shown if _you_ (the viewing player) won this Victory.
|
||||||
|
* `VictoryIllustrations/<name>/Lost.png` - shown if a competitor won this Victory - or you have completed this Victory, but have won a different one before.
|
||||||
|
* `VictoryIllustrations/<name>/<milestone>.png` - One image for each entry in the `milestones` field without an `[amount]`, name taken verbatim but _without_ square brackets, spaces preserved.
|
||||||
|
* `VictoryIllustrations/<name>/<milestone> <index>.png` - For entries in the `milestones` field with an `[amount]`, one image per step, starting at index 1.
|
||||||
|
* `VictoryIllustrations/<name>/<component>.png` - One image for each unique entry in the `requiredSpaceshipParts` field, that is, for parts that can only be built once. Spaces in unit names must be preserved.
|
||||||
|
* `VictoryIllustrations/<name>/<component> <index>.png` - For parts in the `requiredSpaceshipParts` field that must be built several times, one per instance. Spaces in unit names must be preserved, and there must be one space between the name and the index. Indexes start at 1.
|
||||||
|
|
||||||
|
Remember - these are logical names as they are indexed in your atlas file, if you let Unciv pack for you, the `VictoryIllustrations` folder should be placed under `<mod>/Images` - or maybe `<mod>/Images.Victories` if you want these images to occupy a separate `Victories.atlas` (Do not omit the `Images` folder even if left empty, the texture packer needs it as marker to do its task).
|
||||||
|
|
||||||
|
That's almost all there is - no json needed, and works as ['Permanent audiovisual mod'](#permanent-audiovisual-mods). The Background image is the trigger, and if it's present all part images must be present too, or your spaceship crashes before takeoff, taking Unciv along with it. That was a joke, all other images are optional, it could just look boring if you omit the wrong ones.
|
||||||
|
|
||||||
|
As for "almost" - all images are overlaid one by one over the Background one, so they must all be the same size. Except for Won and Lost - those, if their condition is met, _replace_ the entire rest, so they can be different sizes than the background. The part images are overlaid over the background image in no guaranteed order, therefore they should use _transparency_ to avoid hiding parts of each other.
|
||||||
|
|
||||||
|
One way to create a set is to take one final image, select all parts that should be the centerpiece itself not background (use lasso, magic wand or similar tools, use antialiasing and feathering as you see fit), copy and paste as new layer. Then apply desaturation and/or curves to the selection on the background layer to only leave a hint of how the completed victory will look like. Now take apart the centerpiece - do a selection fitting one part name, copy and paste as new layer (in place), then delete the selected part from the original centerpiece layer. Rinse and repeat, then export each layer separately as png with the appropriate filenames.
|
||||||
|
There's no suggested size, but keep in mind textures are a maximum of 2048x2048 pixels, and if you want your images packed properly, several should fit into one texture. They will be scaled down if needed to no more than 80% screen size, preserving aspect ratio.
|
||||||
|
|
||||||
## Sounds
|
## Sounds
|
||||||
|
|
||||||
Standard values are below. The sounds themselves can be found [here](/sounds).
|
Standard values are below. The sounds themselves can be found [here](/sounds).
|
||||||
|