mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-07 14:02:48 +07:00
Assign Population Improvements (#6650)
City management UI to allow focusing automatic worker placement Improvements to worker / specialist assignment routines
This commit is contained in:
parent
a272e8e7ba
commit
a2bc1a1a29
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 14 KiB |
@ -1075,6 +1075,90 @@ TileSets/FantasyHex/Arrows/UnitHasAttacked
|
|||||||
orig: 100, 60
|
orig: 100, 60
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
TileSets/Default/Arrows/Generic
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 6
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/Generic
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 6
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Arrows/UnitAttacked
|
||||||
|
rotate: false
|
||||||
|
xy: 190, 1164
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/UnitAttacked
|
||||||
|
rotate: false
|
||||||
|
xy: 190, 1164
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Arrows/UnitMoved
|
||||||
|
rotate: false
|
||||||
|
xy: 298, 1150
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/UnitMoved
|
||||||
|
rotate: false
|
||||||
|
xy: 298, 1150
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Arrows/UnitMoving
|
||||||
|
rotate: false
|
||||||
|
xy: 112, 6
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/UnitMoving
|
||||||
|
rotate: false
|
||||||
|
xy: 112, 6
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Arrows/UnitTeleported
|
||||||
|
rotate: false
|
||||||
|
xy: 622, 1228
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/UnitTeleported
|
||||||
|
rotate: false
|
||||||
|
xy: 622, 1228
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Arrows/UnitWithdrew
|
||||||
|
rotate: false
|
||||||
|
xy: 730, 1228
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Arrows/UnitWithdrew
|
||||||
|
rotate: false
|
||||||
|
xy: 730, 1228
|
||||||
|
size: 100, 60
|
||||||
|
orig: 100, 60
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
TileSets/Default/AtollOverlay
|
TileSets/Default/AtollOverlay
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 830
|
xy: 4, 830
|
||||||
@ -1082,6 +1166,118 @@ TileSets/Default/AtollOverlay
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConcaveConvexInner
|
||||||
|
rotate: false
|
||||||
|
xy: 406, 1411
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConcaveConvexInner
|
||||||
|
rotate: false
|
||||||
|
xy: 406, 1411
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConcaveConvexOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 406, 1165
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConcaveConvexOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 406, 1165
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConcaveInner
|
||||||
|
rotate: false
|
||||||
|
xy: 622, 1205
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConcaveInner
|
||||||
|
rotate: false
|
||||||
|
xy: 622, 1205
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConcaveOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 1378, 1273
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConcaveOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 1378, 1273
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConvexConcaveInner
|
||||||
|
rotate: false
|
||||||
|
xy: 495, 1165
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConvexConcaveInner
|
||||||
|
rotate: false
|
||||||
|
xy: 495, 1165
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConvexConcaveOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 711, 1205
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConvexConcaveOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 711, 1205
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConvexInner
|
||||||
|
rotate: false
|
||||||
|
xy: 1378, 1250
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConvexInner
|
||||||
|
rotate: false
|
||||||
|
xy: 1378, 1250
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/Borders/ConvexOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 1467, 1273
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Borders/ConvexOuter
|
||||||
|
rotate: false
|
||||||
|
xy: 1467, 1273
|
||||||
|
size: 81, 15
|
||||||
|
orig: 81, 15
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
TileSets/Default/CityOverlay
|
TileSets/Default/CityOverlay
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1470, 1944
|
xy: 1470, 1944
|
||||||
@ -1089,6 +1285,34 @@ TileSets/Default/CityOverlay
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
TileSets/Default/Crosshair
|
||||||
|
rotate: false
|
||||||
|
xy: 482, 1944
|
||||||
|
size: 116, 100
|
||||||
|
orig: 116, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Crosshair
|
||||||
|
rotate: false
|
||||||
|
xy: 482, 1944
|
||||||
|
size: 116, 100
|
||||||
|
orig: 116, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/Default/CrosshatchHexagon
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 1340
|
||||||
|
size: 273, 236
|
||||||
|
orig: 273, 236
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/CrosshatchHexagon
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 1340
|
||||||
|
size: 273, 236
|
||||||
|
orig: 273, 236
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
TileSets/Default/FalloutOverlay
|
TileSets/Default/FalloutOverlay
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 590, 1836
|
xy: 590, 1836
|
||||||
@ -1110,6 +1334,20 @@ TileSets/Default/ForestOverlay
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
TileSets/Default/Highlight
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 1832
|
||||||
|
size: 284, 212
|
||||||
|
orig: 284, 212
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
TileSets/FantasyHex/Highlight
|
||||||
|
rotate: false
|
||||||
|
xy: 4, 1832
|
||||||
|
size: 284, 212
|
||||||
|
orig: 284, 212
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
TileSets/Default/HillOverlay
|
TileSets/Default/HillOverlay
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 590, 1728
|
xy: 590, 1728
|
||||||
@ -1175,263 +1413,25 @@ TileSets/Default/Road
|
|||||||
index: -1
|
index: -1
|
||||||
TileSets/Default/Tiles/River-Bottom
|
TileSets/Default/Tiles/River-Bottom
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1574, 735
|
xy: 1534, 694
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
TileSets/Default/Tiles/River-BottomLeft
|
TileSets/Default/Tiles/River-BottomLeft
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1574, 699
|
xy: 1534, 658
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
TileSets/Default/Tiles/River-BottomRight
|
TileSets/Default/Tiles/River-BottomRight
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1574, 663
|
xy: 1534, 622
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
TileSets/FantasyHex/Arrows/Generic
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 6
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/Generic
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 6
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Arrows/UnitAttacked
|
|
||||||
rotate: false
|
|
||||||
xy: 190, 1164
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/UnitAttacked
|
|
||||||
rotate: false
|
|
||||||
xy: 190, 1164
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Arrows/UnitMoved
|
|
||||||
rotate: false
|
|
||||||
xy: 298, 1150
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/UnitMoved
|
|
||||||
rotate: false
|
|
||||||
xy: 298, 1150
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Arrows/UnitMoving
|
|
||||||
rotate: false
|
|
||||||
xy: 112, 6
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/UnitMoving
|
|
||||||
rotate: false
|
|
||||||
xy: 112, 6
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Arrows/UnitTeleported
|
|
||||||
rotate: false
|
|
||||||
xy: 622, 1228
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/UnitTeleported
|
|
||||||
rotate: false
|
|
||||||
xy: 622, 1228
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Arrows/UnitWithdrew
|
|
||||||
rotate: false
|
|
||||||
xy: 730, 1228
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Arrows/UnitWithdrew
|
|
||||||
rotate: false
|
|
||||||
xy: 730, 1228
|
|
||||||
size: 100, 60
|
|
||||||
orig: 100, 60
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConcaveConvexInner
|
|
||||||
rotate: false
|
|
||||||
xy: 406, 1411
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConcaveConvexInner
|
|
||||||
rotate: false
|
|
||||||
xy: 406, 1411
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConcaveConvexOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 406, 1165
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConcaveConvexOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 406, 1165
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConcaveInner
|
|
||||||
rotate: false
|
|
||||||
xy: 622, 1205
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConcaveInner
|
|
||||||
rotate: false
|
|
||||||
xy: 622, 1205
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConcaveOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 1378, 1273
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConcaveOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 1378, 1273
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConvexConcaveInner
|
|
||||||
rotate: false
|
|
||||||
xy: 495, 1165
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConvexConcaveInner
|
|
||||||
rotate: false
|
|
||||||
xy: 495, 1165
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConvexConcaveOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 711, 1205
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConvexConcaveOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 711, 1205
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConvexInner
|
|
||||||
rotate: false
|
|
||||||
xy: 1378, 1250
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConvexInner
|
|
||||||
rotate: false
|
|
||||||
xy: 1378, 1250
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Borders/ConvexOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 1467, 1273
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Borders/ConvexOuter
|
|
||||||
rotate: false
|
|
||||||
xy: 1467, 1273
|
|
||||||
size: 81, 15
|
|
||||||
orig: 81, 15
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Crosshair
|
|
||||||
rotate: false
|
|
||||||
xy: 482, 1944
|
|
||||||
size: 116, 100
|
|
||||||
orig: 116, 100
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Crosshair
|
|
||||||
rotate: false
|
|
||||||
xy: 482, 1944
|
|
||||||
size: 116, 100
|
|
||||||
orig: 116, 100
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/CrosshatchHexagon
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 1340
|
|
||||||
size: 273, 236
|
|
||||||
orig: 273, 236
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/CrosshatchHexagon
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 1340
|
|
||||||
size: 273, 236
|
|
||||||
orig: 273, 236
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Highlight
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 1832
|
|
||||||
size: 284, 212
|
|
||||||
orig: 284, 212
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/Default/Highlight
|
|
||||||
rotate: false
|
|
||||||
xy: 4, 1832
|
|
||||||
size: 284, 212
|
|
||||||
orig: 284, 212
|
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
TileSets/FantasyHex/Railroad
|
TileSets/FantasyHex/Railroad
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 505, 1728
|
xy: 505, 1728
|
||||||
@ -2316,21 +2316,21 @@ TileSets/FantasyHex/Tiles/Quarry+Stone
|
|||||||
index: -1
|
index: -1
|
||||||
TileSets/FantasyHex/Tiles/River-Bottom
|
TileSets/FantasyHex/Tiles/River-Bottom
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1534, 694
|
xy: 1574, 735
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
TileSets/FantasyHex/Tiles/River-BottomLeft
|
TileSets/FantasyHex/Tiles/River-BottomLeft
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1534, 658
|
xy: 1574, 699
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
TileSets/FantasyHex/Tiles/River-BottomRight
|
TileSets/FantasyHex/Tiles/River-BottomRight
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1534, 622
|
xy: 1574, 663
|
||||||
size: 32, 28
|
size: 32, 28
|
||||||
orig: 32, 28
|
orig: 32, 28
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
@ -929,6 +929,8 @@ Nothing =
|
|||||||
Annex city =
|
Annex city =
|
||||||
Specialist Buildings =
|
Specialist Buildings =
|
||||||
Specialist Allocation =
|
Specialist Allocation =
|
||||||
|
Manual Specialists =
|
||||||
|
Auto Specialists =
|
||||||
Specialists =
|
Specialists =
|
||||||
[specialist] slots =
|
[specialist] slots =
|
||||||
Food eaten =
|
Food eaten =
|
||||||
@ -956,6 +958,16 @@ Worked by [cityName] =
|
|||||||
Lock =
|
Lock =
|
||||||
Unlock =
|
Unlock =
|
||||||
Move to city =
|
Move to city =
|
||||||
|
Reset Citizens =
|
||||||
|
Citizen Management =
|
||||||
|
Avoid Growth =
|
||||||
|
Default Focus =
|
||||||
|
Food Focus =
|
||||||
|
Production Focus =
|
||||||
|
Gold Focus =
|
||||||
|
Science Focus =
|
||||||
|
Culture Focus =
|
||||||
|
Happiness Focus =
|
||||||
Please enter a new name for your city =
|
Please enter a new name for your city =
|
||||||
Please select a tile for this building's [improvement] =
|
Please select a tile for this building's [improvement] =
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.unciv.logic.automation
|
package com.unciv.logic.automation
|
||||||
|
|
||||||
|
import com.unciv.logic.city.CityFocus
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.city.INonPerpetualConstruction
|
import com.unciv.logic.city.INonPerpetualConstruction
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
@ -8,7 +9,6 @@ import com.unciv.logic.map.MapUnit
|
|||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.ruleset.MilestoneType
|
|
||||||
import com.unciv.models.ruleset.Victory
|
import com.unciv.models.ruleset.Victory
|
||||||
import com.unciv.models.ruleset.Victory.Focus
|
import com.unciv.models.ruleset.Victory.Focus
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
@ -16,46 +16,94 @@ import com.unciv.models.ruleset.tile.TileImprovement
|
|||||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.victoryscreen.RankingType
|
import com.unciv.ui.victoryscreen.RankingType
|
||||||
|
|
||||||
object Automation {
|
object Automation {
|
||||||
|
|
||||||
fun rankTileForCityWork(tile: TileInfo, city: CityInfo, foodWeight: Float = 1f): Float {
|
fun rankTileForCityWork(tile: TileInfo, city: CityInfo, cityStats: Stats): Float {
|
||||||
val stats = tile.getTileStats(city, city.civInfo)
|
val stats = tile.getTileStats(city, city.civInfo)
|
||||||
return rankStatsForCityWork(stats, city, foodWeight)
|
return rankStatsForCityWork(stats, city, cityStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rankStatsForCityWork(stats: Stats, city: CityInfo, foodWeight: Float = 1f): Float {
|
fun rankSpecialist(specialist: String, cityInfo: CityInfo, cityStats: Stats): Float {
|
||||||
var rank = 0f
|
val stats = cityInfo.cityStats.getStatsOfSpecialist(specialist)
|
||||||
if (city.population.population < 5) {
|
var rank = rankStatsForCityWork(stats, cityInfo, cityStats, true)
|
||||||
// "small city" - we care more about food and less about global problems like gold science and culture
|
// derive GPP score
|
||||||
rank += stats.food * 1.2f * foodWeight
|
var gpp = 0f
|
||||||
rank += stats.production
|
if (cityInfo.getRuleset().specialists.containsKey(specialist)) { // To solve problems in total remake mods
|
||||||
rank += stats.science / 2
|
val specialistInfo = cityInfo.getRuleset().specialists[specialist]!!
|
||||||
rank += stats.culture / 2
|
gpp = specialistInfo.greatPersonPoints.sumValues().toFloat()
|
||||||
rank += stats.gold / 5 // it's barely worth anything at this point
|
|
||||||
} else {
|
|
||||||
if (stats.food <= 2 || city.civInfo.getHappiness() > 5) rank += stats.food * 1.2f * foodWeight // food get more value to keep city growing
|
|
||||||
else rank += (2.4f + (stats.food - 2) / 2) * foodWeight // 1.2 point for each food up to 2, from there on half a point
|
|
||||||
|
|
||||||
if (city.civInfo.gold < 0 && city.civInfo.statsForNextTurn.gold <= 0)
|
|
||||||
rank += stats.gold // we have a global problem
|
|
||||||
else rank += stats.gold / 3 // 3 gold is worse than 2 production
|
|
||||||
|
|
||||||
rank += stats.production
|
|
||||||
rank += stats.science
|
|
||||||
if (city.tiles.size < 12 || city.civInfo.wantsToFocusOn(Victory.Focus.Culture)) {
|
|
||||||
rank += stats.culture
|
|
||||||
} else rank += stats.culture / 2
|
|
||||||
}
|
}
|
||||||
|
gpp = gpp * (100 + cityInfo.currentGPPBonus) / 100
|
||||||
|
rank += gpp * 3 // GPP weight
|
||||||
return rank
|
return rank
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun rankSpecialist(stats: Stats, cityInfo: CityInfo): Float {
|
private fun rankStatsForCityWork(stats: Stats, city: CityInfo, cityStats: Stats, specialist: Boolean = false): Float {
|
||||||
var rank = rankStatsForCityWork(stats, cityInfo)
|
val cityAIFocus = city.cityAIFocus
|
||||||
rank += 0.3f //GPP bonus
|
val yieldStats = stats.clone()
|
||||||
return rank
|
|
||||||
|
if (specialist) {
|
||||||
|
// If you have the Food Bonus, count as 1 extra food production (base is 2food)
|
||||||
|
for (unique in city.getMatchingUniques(UniqueType.FoodConsumptionBySpecialists))
|
||||||
|
if (city.matchesFilter(unique.params[1]))
|
||||||
|
yieldStats.food -= (unique.params[0].toFloat() / 100f) * 2f // base 2 food per Pop
|
||||||
|
// Specialist Happiness Percentage Change 0f-1f
|
||||||
|
for (unique in city.getMatchingUniques(UniqueType.UnhappinessFromPopulationTypePercentageChange))
|
||||||
|
if (city.matchesFilter(unique.params[2]) && unique.params[1] == "Specialists")
|
||||||
|
yieldStats.happiness -= (unique.params[0].toFloat() / 100f) // relative val is negative, make positive
|
||||||
|
if (city.civInfo.getHappiness() < 0) yieldStats.happiness *= 2 // double weight for unhappy civilization
|
||||||
|
}
|
||||||
|
|
||||||
|
val surplusFood = cityStats[Stat.Food]
|
||||||
|
// Apply base weights
|
||||||
|
yieldStats.applyRankingWeights()
|
||||||
|
|
||||||
|
if (surplusFood > 0 && city.avoidGrowth) {
|
||||||
|
yieldStats.food = 0f // don't need more food!
|
||||||
|
} else {
|
||||||
|
if (cityAIFocus != CityFocus.NoFocus && cityAIFocus != CityFocus.FoodFocus && cityAIFocus != CityFocus.ProductionGrowthFocus && cityAIFocus != CityFocus.GoldGrowthFocus) {
|
||||||
|
// Focus on non-food/growth
|
||||||
|
if (surplusFood < 0)
|
||||||
|
yieldStats.food *= 8 // Starving, need Food, get to 0
|
||||||
|
else
|
||||||
|
yieldStats.food /= 2
|
||||||
|
} else if (!city.avoidGrowth) {
|
||||||
|
// NoFocus or Food/Growth Focus. Target +2 Food Surplus
|
||||||
|
if (surplusFood < 2)
|
||||||
|
yieldStats.food *= 8
|
||||||
|
else if (cityAIFocus != CityFocus.FoodFocus)
|
||||||
|
yieldStats.food /= 2
|
||||||
|
if (city.population.population < 5 && cityAIFocus != CityFocus.FoodFocus)
|
||||||
|
// NoFocus or GoldGrow or ProdGrow, not Avoid Growth, pop < 5. FoodFocus already does this up
|
||||||
|
yieldStats.food *= 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (city.population.population < 5) {
|
||||||
|
// "small city" - we care more about food and less about global problems like gold science and culture
|
||||||
|
// Food already handled above. Science/Culture have low weights in Stats already
|
||||||
|
yieldStats.gold /= 2 // it's barely worth anything at this point
|
||||||
|
} else {
|
||||||
|
if (city.civInfo.gold < 0 && city.civInfo.statsForNextTurn.gold <= 0)
|
||||||
|
yieldStats.gold *= 2 // We have a global problem
|
||||||
|
|
||||||
|
if (city.tiles.size < 12 || city.civInfo.wantsToFocusOn(Focus.Culture))
|
||||||
|
yieldStats.culture *= 2
|
||||||
|
|
||||||
|
if (city.civInfo.getHappiness() < 0 && !specialist) // since this doesn't get updated, may overshoot
|
||||||
|
yieldStats.happiness *= 2
|
||||||
|
|
||||||
|
if (city.civInfo.wantsToFocusOn(Focus.Science))
|
||||||
|
yieldStats.science *= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply City focus
|
||||||
|
cityAIFocus.applyWeightTo(yieldStats)
|
||||||
|
|
||||||
|
return yieldStats.values.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryTrainMilitaryUnit(city: CityInfo) {
|
fun tryTrainMilitaryUnit(city: CityInfo) {
|
||||||
@ -74,8 +122,8 @@ object Automation {
|
|||||||
mapUnit.getMatchingUniques(UniqueType.CarryAirUnits).firstOrNull() ?: return 0
|
mapUnit.getMatchingUniques(UniqueType.CarryAirUnits).firstOrNull() ?: return 0
|
||||||
if (mapUnitCarryUnique.params[1] != carryFilter) return 0 //Carries a different type of unit
|
if (mapUnitCarryUnique.params[1] != carryFilter) return 0 //Carries a different type of unit
|
||||||
return mapUnitCarryUnique.params[0].toInt() +
|
return mapUnitCarryUnique.params[0].toInt() +
|
||||||
mapUnit.getMatchingUniques(UniqueType.CarryExtraAirUnits)
|
mapUnit.getMatchingUniques(UniqueType.CarryExtraAirUnits)
|
||||||
.filter { it.params[1] == carryFilter }.sumOf { it.params[0].toInt() }
|
.filter { it.params[1] == carryFilter }.sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
val totalCarriableUnits =
|
val totalCarriableUnits =
|
||||||
@ -97,13 +145,15 @@ object Automation {
|
|||||||
findWaterConnectedCitiesAndEnemies.stepToEnd()
|
findWaterConnectedCitiesAndEnemies.stepToEnd()
|
||||||
if (findWaterConnectedCitiesAndEnemies.getReachedTiles().none {
|
if (findWaterConnectedCitiesAndEnemies.getReachedTiles().none {
|
||||||
(it.isCityCenter() && it.getOwner() != city.civInfo)
|
(it.isCityCenter() && it.getOwner() != city.civInfo)
|
||||||
|| (it.militaryUnit != null && it.militaryUnit!!.civInfo != city.civInfo)
|
|| (it.militaryUnit != null && it.militaryUnit!!.civInfo != city.civInfo)
|
||||||
}) // there is absolutely no reason for you to make water units on this body of water.
|
}) // there is absolutely no reason for you to make water units on this body of water.
|
||||||
militaryUnits = militaryUnits.filter { !it.isWaterUnit() }
|
militaryUnits = militaryUnits.filter { !it.isWaterUnit() }
|
||||||
|
|
||||||
|
|
||||||
val carryingOnlyUnits = militaryUnits.filter { it.hasUnique(UniqueType.CarryAirUnits)
|
val carryingOnlyUnits = militaryUnits.filter {
|
||||||
&& it.hasUnique(UniqueType.CannotAttack) }.toList()
|
it.hasUnique(UniqueType.CarryAirUnits)
|
||||||
|
&& it.hasUnique(UniqueType.CannotAttack)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
for (unit in carryingOnlyUnits)
|
for (unit in carryingOnlyUnits)
|
||||||
if (providesUnneededCarryingSlots(unit, city.civInfo))
|
if (providesUnneededCarryingSlots(unit, city.civInfo))
|
||||||
@ -125,9 +175,11 @@ object Automation {
|
|||||||
.map { it.unitType }
|
.map { it.unitType }
|
||||||
.distinct()
|
.distinct()
|
||||||
if (availableTypes.none()) return null
|
if (availableTypes.none()) return null
|
||||||
val bestUnitsForType = availableTypes.map { type -> militaryUnits
|
val bestUnitsForType = availableTypes.map { type ->
|
||||||
|
militaryUnits
|
||||||
.filter { unit -> unit.unitType == type }
|
.filter { unit -> unit.unitType == type }
|
||||||
.maxByOrNull { unit -> unit.cost }!! }
|
.maxByOrNull { unit -> unit.cost }!!
|
||||||
|
}
|
||||||
// Check the maximum force evaluation for the shortlist so we can prune useless ones (ie scouts)
|
// Check the maximum force evaluation for the shortlist so we can prune useless ones (ie scouts)
|
||||||
val bestForce = bestUnitsForType.maxOf { it.getForceEvaluation() }
|
val bestForce = bestUnitsForType.maxOf { it.getForceEvaluation() }
|
||||||
chosenUnit = bestUnitsForType.filter { it.uniqueTo != null || it.getForceEvaluation() > bestForce / 3 }.toList().random()
|
chosenUnit = bestUnitsForType.filter { it.uniqueTo != null || it.getForceEvaluation() > bestForce / 3 }.toList().random()
|
||||||
@ -172,14 +224,14 @@ object Automation {
|
|||||||
|
|
||||||
/** Checks both feasibility of Buildings with a CreatesOneImprovement unique
|
/** Checks both feasibility of Buildings with a CreatesOneImprovement unique
|
||||||
* and resource scarcity making a construction undesirable.
|
* and resource scarcity making a construction undesirable.
|
||||||
*/
|
*/
|
||||||
fun allowAutomatedConstruction(
|
fun allowAutomatedConstruction(
|
||||||
civInfo: CivilizationInfo,
|
civInfo: CivilizationInfo,
|
||||||
cityInfo: CityInfo,
|
cityInfo: CityInfo,
|
||||||
construction: INonPerpetualConstruction
|
construction: INonPerpetualConstruction
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return allowCreateImprovementBuildings(civInfo, cityInfo, construction)
|
return allowCreateImprovementBuildings(civInfo, cityInfo, construction)
|
||||||
&& allowSpendingResource(civInfo, construction)
|
&& allowSpendingResource(civInfo, construction)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks both feasibility of Buildings with a [UniqueType.CreatesOneImprovement] unique (appropriate tile available).
|
/** Checks both feasibility of Buildings with a [UniqueType.CreatesOneImprovement] unique (appropriate tile available).
|
||||||
@ -241,7 +293,7 @@ object Automation {
|
|||||||
val neededForBuilding = civInfo.lastEraResourceUsedForBuilding[resource] != null
|
val neededForBuilding = civInfo.lastEraResourceUsedForBuilding[resource] != null
|
||||||
// Don't care about old units
|
// Don't care about old units
|
||||||
val neededForUnits = civInfo.lastEraResourceUsedForUnit[resource] != null
|
val neededForUnits = civInfo.lastEraResourceUsedForUnit[resource] != null
|
||||||
&& civInfo.lastEraResourceUsedForUnit[resource]!! >= civInfo.getEraNumber()
|
&& civInfo.lastEraResourceUsedForUnit[resource]!! >= civInfo.getEraNumber()
|
||||||
|
|
||||||
// No need to save for both
|
// No need to save for both
|
||||||
if (!neededForBuilding || !neededForUnits) {
|
if (!neededForBuilding || !neededForUnits) {
|
||||||
@ -283,11 +335,11 @@ object Automation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Support [UniqueType.CreatesOneImprovement] unique - find best tile for placement automation */
|
/** Support [UniqueType.CreatesOneImprovement] unique - find best tile for placement automation */
|
||||||
fun getTileForConstructionImprovement(cityInfo: CityInfo, improvement: TileImprovement): TileInfo? {
|
fun getTileForConstructionImprovement(cityInfo: CityInfo, improvement: TileImprovement): TileInfo? {
|
||||||
return cityInfo.getTiles().filter {
|
return cityInfo.getTiles().filter {
|
||||||
it.canBuildImprovement(improvement, cityInfo.civInfo)
|
it.canBuildImprovement(improvement, cityInfo.civInfo)
|
||||||
}.maxByOrNull {
|
}.maxByOrNull {
|
||||||
rankTileForCityWork(it, cityInfo)
|
rankTileForCityWork(it, cityInfo, cityInfo.cityStats.currentCityStats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +402,7 @@ object Automation {
|
|||||||
if (adjacentTile.hasViewableResource(cityInfo.civInfo) &&
|
if (adjacentTile.hasViewableResource(cityInfo.civInfo) &&
|
||||||
(adjacentDistance < 3 ||
|
(adjacentDistance < 3 ||
|
||||||
adjacentTile.tileResource.resourceType != ResourceType.Bonus
|
adjacentTile.tileResource.resourceType != ResourceType.Bonus
|
||||||
)
|
)
|
||||||
) score -= 1
|
) score -= 1
|
||||||
if (adjacentTile.naturalWonder != null) {
|
if (adjacentTile.naturalWonder != null) {
|
||||||
if (adjacentDistance < 3) adjacentNaturalWonder = true
|
if (adjacentDistance < 3) adjacentNaturalWonder = true
|
||||||
@ -381,7 +433,7 @@ object Automation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ThreatLevel{
|
enum class ThreatLevel {
|
||||||
VeryLow,
|
VeryLow,
|
||||||
Low,
|
Low,
|
||||||
Medium,
|
Medium,
|
||||||
|
@ -853,7 +853,7 @@ object NextTurnAutomation {
|
|||||||
city.annexCity()
|
city.annexCity()
|
||||||
}
|
}
|
||||||
|
|
||||||
city.reassignPopulation()
|
city.reassignAllPopulation()
|
||||||
|
|
||||||
city.cityConstructions.chooseNextConstruction()
|
city.cityConstructions.chooseNextConstruction()
|
||||||
if (city.health < city.getMaxHealth())
|
if (city.health < city.getMaxHealth())
|
||||||
|
@ -19,6 +19,7 @@ import com.unciv.models.ruleset.tile.ResourceType
|
|||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
|
import com.unciv.models.stats.Stats
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
@ -34,6 +35,49 @@ enum class CityFlags {
|
|||||||
Resistance
|
Resistance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if tableEnabled == true, then Stat != null
|
||||||
|
enum class CityFocus(val label: String, val tableEnabled: Boolean, val stat: Stat? = null) {
|
||||||
|
NoFocus("Default Focus", true, null) {
|
||||||
|
override fun getStatMultiplier(stat: Stat) = 1f // actually redundant, but that's two steps to see
|
||||||
|
},
|
||||||
|
FoodFocus("${Stat.Food.name} Focus", true, Stat.Food),
|
||||||
|
ProductionFocus("${Stat.Production.name} Focus", true, Stat.Production),
|
||||||
|
GoldFocus("${Stat.Gold.name} Focus", true, Stat.Gold),
|
||||||
|
ScienceFocus("${Stat.Science.name} Focus", true, Stat.Science),
|
||||||
|
CultureFocus("${Stat.Culture.name} Focus", true, Stat.Culture),
|
||||||
|
GoldGrowthFocus("Gold Growth Focus", false) {
|
||||||
|
override fun getStatMultiplier(stat: Stat) = when (stat) {
|
||||||
|
Stat.Gold, Stat.Food -> 2f
|
||||||
|
else -> 1f
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ProductionGrowthFocus("Production Growth Focus", false) {
|
||||||
|
override fun getStatMultiplier(stat: Stat) = when (stat) {
|
||||||
|
Stat.Production, Stat.Food -> 2f
|
||||||
|
else -> 1f
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FaithFocus("${Stat.Faith.name} Focus", true, Stat.Faith),
|
||||||
|
HappinessFocus("${Stat.Happiness.name} Focus", false, Stat.Happiness);
|
||||||
|
//GreatPersonFocus;
|
||||||
|
|
||||||
|
open fun getStatMultiplier(stat: Stat) = when (this.stat) {
|
||||||
|
stat -> 3f
|
||||||
|
else -> 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun applyWeightTo(stats: Stats) {
|
||||||
|
for (stat in Stat.values()) {
|
||||||
|
stats[stat] *= getStatMultiplier(stat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun safeValueOf(stat: Stat): CityFocus {
|
||||||
|
return values().firstOrNull { it.stat == stat } ?: NoFocus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class CityInfo {
|
class CityInfo {
|
||||||
@Suppress("JoinDeclarationAndAssignment")
|
@Suppress("JoinDeclarationAndAssignment")
|
||||||
@Transient
|
@Transient
|
||||||
@ -81,10 +125,15 @@ class CityInfo {
|
|||||||
|
|
||||||
/** Tiles that the population in them won't be reassigned */
|
/** Tiles that the population in them won't be reassigned */
|
||||||
var lockedTiles = HashSet<Vector2>()
|
var lockedTiles = HashSet<Vector2>()
|
||||||
|
var manualSpecialists = false
|
||||||
var isBeingRazed = false
|
var isBeingRazed = false
|
||||||
var attackedThisTurn = false
|
var attackedThisTurn = false
|
||||||
var hasSoldBuildingThisTurn = false
|
var hasSoldBuildingThisTurn = false
|
||||||
var isPuppet = false
|
var isPuppet = false
|
||||||
|
var updateCitizens = false // flag so that on endTurn() the Governor reassigns Citizens
|
||||||
|
var cityAIFocus: CityFocus = CityFocus.NoFocus
|
||||||
|
var avoidGrowth: Boolean = false
|
||||||
|
@Transient var currentGPPBonus: Int = 0 // temporary variable saved for rankSpecialist()
|
||||||
|
|
||||||
/** The very first found city is the _original_ capital,
|
/** The very first found city is the _original_ capital,
|
||||||
* while the _current_ capital can be any other city after the original one is captured.
|
* while the _current_ capital can be any other city after the original one is captured.
|
||||||
@ -148,7 +197,6 @@ class CityInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
population.autoAssignPopulation()
|
population.autoAssignPopulation()
|
||||||
cityStats.update()
|
|
||||||
|
|
||||||
// Update proximity rankings for all civs
|
// Update proximity rankings for all civs
|
||||||
for (otherCiv in civInfo.gameInfo.getAliveMajorCivs()) {
|
for (otherCiv in civInfo.gameInfo.getAliveMajorCivs()) {
|
||||||
@ -302,6 +350,10 @@ class CityInfo {
|
|||||||
toReturn.isOriginalCapital = isOriginalCapital
|
toReturn.isOriginalCapital = isOriginalCapital
|
||||||
toReturn.flagsCountdown.putAll(flagsCountdown)
|
toReturn.flagsCountdown.putAll(flagsCountdown)
|
||||||
toReturn.demandedResource = demandedResource
|
toReturn.demandedResource = demandedResource
|
||||||
|
toReturn.updateCitizens = updateCitizens
|
||||||
|
toReturn.cityAIFocus = cityAIFocus
|
||||||
|
toReturn.avoidGrowth = avoidGrowth
|
||||||
|
toReturn.manualSpecialists = manualSpecialists
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +488,7 @@ class CityInfo {
|
|||||||
fun isGrowing() = foodForNextTurn() > 0
|
fun isGrowing() = foodForNextTurn() > 0
|
||||||
fun isStarving() = foodForNextTurn() < 0
|
fun isStarving() = foodForNextTurn() < 0
|
||||||
|
|
||||||
private fun foodForNextTurn() = cityStats.currentCityStats.food.roundToInt()
|
fun foodForNextTurn() = cityStats.currentCityStats.food.roundToInt()
|
||||||
|
|
||||||
/** Take null to mean infinity. */
|
/** Take null to mean infinity. */
|
||||||
fun getNumTurnsToNewPopulation(): Int? {
|
fun getNumTurnsToNewPopulation(): Int? {
|
||||||
@ -453,10 +505,32 @@ class CityInfo {
|
|||||||
if (!isStarving()) return null
|
if (!isStarving()) return null
|
||||||
return population.foodStored / -foodForNextTurn() + 1
|
return population.foodStored / -foodForNextTurn() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsBuildingUnique(uniqueType: UniqueType) =
|
fun containsBuildingUnique(uniqueType: UniqueType) =
|
||||||
cityConstructions.getBuiltBuildings().flatMap { it.uniqueObjects }.any { it.isOfType(uniqueType) }
|
cityConstructions.getBuiltBuildings().flatMap { it.uniqueObjects }.any { it.isOfType(uniqueType) }
|
||||||
|
|
||||||
|
fun getGreatPersonPercentageBonus(): Int{
|
||||||
|
var allGppPercentageBonus = 0
|
||||||
|
for (unique in getMatchingUniques(UniqueType.GreatPersonPointPercentage)
|
||||||
|
+ getMatchingUniques(UniqueType.GreatPersonPointPercentageDeprecated)
|
||||||
|
) {
|
||||||
|
if (!matchesFilter(unique.params[1])) continue
|
||||||
|
allGppPercentageBonus += unique.params[0].toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sweden UP
|
||||||
|
for (otherCiv in civInfo.getKnownCivs()) {
|
||||||
|
if (!civInfo.getDiplomacyManager(otherCiv).hasFlag(DiplomacyFlags.DeclarationOfFriendship))
|
||||||
|
continue
|
||||||
|
|
||||||
|
for (ourUnique in civInfo.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship))
|
||||||
|
allGppPercentageBonus += ourUnique.params[0].toInt()
|
||||||
|
for (theirUnique in otherCiv.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship))
|
||||||
|
allGppPercentageBonus += theirUnique.params[0].toInt()
|
||||||
|
}
|
||||||
|
return allGppPercentageBonus
|
||||||
|
}
|
||||||
|
|
||||||
fun getGreatPersonPointsForNextTurn(): HashMap<String, Counter<String>> {
|
fun getGreatPersonPointsForNextTurn(): HashMap<String, Counter<String>> {
|
||||||
val sourceToGPP = HashMap<String, Counter<String>>()
|
val sourceToGPP = HashMap<String, Counter<String>>()
|
||||||
|
|
||||||
@ -481,24 +555,7 @@ class CityInfo {
|
|||||||
gppCounter.add(unitName, gppCounter[unitName]!! * unique.params[1].toInt() / 100)
|
gppCounter.add(unitName, gppCounter[unitName]!! * unique.params[1].toInt() / 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
var allGppPercentageBonus = 0
|
val allGppPercentageBonus = getGreatPersonPercentageBonus()
|
||||||
for (unique in getMatchingUniques(UniqueType.GreatPersonPointPercentage)
|
|
||||||
+ getMatchingUniques(UniqueType.GreatPersonPointPercentageDeprecated)
|
|
||||||
) {
|
|
||||||
if (!matchesFilter(unique.params[1])) continue
|
|
||||||
allGppPercentageBonus += unique.params[0].toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sweden UP
|
|
||||||
for (otherCiv in civInfo.getKnownCivs()) {
|
|
||||||
if (!civInfo.getDiplomacyManager(otherCiv).hasFlag(DiplomacyFlags.DeclarationOfFriendship))
|
|
||||||
continue
|
|
||||||
|
|
||||||
for (ourUnique in civInfo.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship))
|
|
||||||
allGppPercentageBonus += ourUnique.params[0].toInt()
|
|
||||||
for (theirUnique in otherCiv.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship))
|
|
||||||
allGppPercentageBonus += theirUnique.params[0].toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unitName in gppCounter.keys)
|
for (unitName in gppCounter.keys)
|
||||||
gppCounter.add(unitName, gppCounter[unitName]!! * allGppPercentageBonus / 100)
|
gppCounter.add(unitName, gppCounter[unitName]!! * allGppPercentageBonus / 100)
|
||||||
@ -585,7 +642,11 @@ class CityInfo {
|
|||||||
tryUpdateRoadStatus()
|
tryUpdateRoadStatus()
|
||||||
attackedThisTurn = false
|
attackedThisTurn = false
|
||||||
|
|
||||||
if (isPuppet) reassignPopulation()
|
if (isPuppet) reassignAllPopulation()
|
||||||
|
else if (updateCitizens){
|
||||||
|
reassignPopulation()
|
||||||
|
updateCitizens = false
|
||||||
|
}
|
||||||
|
|
||||||
// The ordering is intentional - you get a turn without WLTKD even if you have the next resource already
|
// The ordering is intentional - you get a turn without WLTKD even if you have the next resource already
|
||||||
if (!hasFlag(CityFlags.WeLoveTheKing))
|
if (!hasFlag(CityFlags.WeLoveTheKing))
|
||||||
@ -644,19 +705,23 @@ class CityInfo {
|
|||||||
demandedResource = ""
|
demandedResource = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reassignPopulation() {
|
// Reassign all Specialists and Unlock all tiles
|
||||||
var foodWeight = 1f
|
// Mainly for automated cities, Puppets, just captured
|
||||||
var foodPerTurn = 0f
|
fun reassignAllPopulation() {
|
||||||
while (foodWeight < 3 && foodPerTurn <= 0) {
|
manualSpecialists = false
|
||||||
workedTiles = hashSetOf()
|
reassignPopulation(resetLocked = true)
|
||||||
population.specialistAllocations.clear()
|
}
|
||||||
for (i in 0..population.population)
|
|
||||||
population.autoAssignPopulation(foodWeight)
|
|
||||||
cityStats.update()
|
|
||||||
|
|
||||||
foodPerTurn = foodForNextTurn().toFloat()
|
fun reassignPopulation(resetLocked: Boolean = false) {
|
||||||
foodWeight += 0.5f
|
if (resetLocked) {
|
||||||
|
workedTiles = hashSetOf()
|
||||||
|
lockedTiles = hashSetOf()
|
||||||
|
} else {
|
||||||
|
workedTiles = lockedTiles
|
||||||
}
|
}
|
||||||
|
if (!manualSpecialists)
|
||||||
|
population.specialistAllocations.clear()
|
||||||
|
population.autoAssignPopulation()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun endTurn() {
|
fun endTurn() {
|
||||||
@ -905,4 +970,4 @@ class CityInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
|||||||
|
|
||||||
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||||
if (population.population > 1) population.addPopulation(-1 - population.population / 4) // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
if (population.population > 1) population.addPopulation(-1 - population.population / 4) // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
||||||
reassignPopulation()
|
reassignAllPopulation()
|
||||||
|
|
||||||
if (!reconqueredCityWhileStillInResistance && foundingCiv != receivingCiv.civName) {
|
if (!reconqueredCityWhileStillInResistance && foundingCiv != receivingCiv.civName) {
|
||||||
// add resistance
|
// add resistance
|
||||||
|
@ -2,9 +2,12 @@ package com.unciv.logic.city
|
|||||||
|
|
||||||
import com.unciv.logic.automation.Automation
|
import com.unciv.logic.automation.Automation
|
||||||
import com.unciv.logic.civilization.NotificationIcon
|
import com.unciv.logic.civilization.NotificationIcon
|
||||||
|
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.models.Counter
|
import com.unciv.models.Counter
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import com.unciv.models.stats.Stat
|
||||||
|
import com.unciv.ui.utils.toPercent
|
||||||
import com.unciv.ui.utils.withItem
|
import com.unciv.ui.utils.withItem
|
||||||
import com.unciv.ui.utils.withoutItem
|
import com.unciv.ui.utils.withoutItem
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
@ -82,7 +85,7 @@ class PopulationManager {
|
|||||||
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
|
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
|
||||||
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
|
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
|
||||||
addPopulation(1)
|
addPopulation(1)
|
||||||
autoAssignPopulation()
|
cityInfo.updateCitizens = true
|
||||||
cityInfo.civInfo.addNotification("[${cityInfo.name}] has grown!", cityInfo.location, NotificationIcon.Growth)
|
cityInfo.civInfo.addNotification("[${cityInfo.name}] has grown!", cityInfo.location, NotificationIcon.Growth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,34 +112,50 @@ class PopulationManager {
|
|||||||
addPopulation(-population + count)
|
addPopulation(-population + count)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun autoAssignPopulation(foodWeight: Float = 1f) {
|
internal fun autoAssignPopulation() {
|
||||||
|
cityInfo.cityStats.update() // calculate current stats with current assignments
|
||||||
|
val cityStats = cityInfo.cityStats.currentCityStats
|
||||||
|
cityInfo.currentGPPBonus = cityInfo.getGreatPersonPercentageBonus() // pre-calculate
|
||||||
|
var specialistFoodBonus = 2f // See CityStats.calcFoodEaten()
|
||||||
|
for (unique in cityInfo.getMatchingUniques(UniqueType.FoodConsumptionBySpecialists))
|
||||||
|
if (cityInfo.matchesFilter(unique.params[1]))
|
||||||
|
specialistFoodBonus *= unique.params[0].toPercent()
|
||||||
|
specialistFoodBonus = 2f - specialistFoodBonus
|
||||||
|
|
||||||
for (i in 1..getFreePopulation()) {
|
for (i in 1..getFreePopulation()) {
|
||||||
//evaluate tiles
|
//evaluate tiles
|
||||||
val bestTile: TileInfo? = cityInfo.getTiles()
|
val (bestTile, valueBestTile) = cityInfo.getTiles()
|
||||||
.filter { it.aerialDistanceTo(cityInfo.getCenterTile()) <= 3 }
|
.filter { it.aerialDistanceTo(cityInfo.getCenterTile()) <= 3 }
|
||||||
.filterNot { it.providesYield() }
|
.filterNot { it.providesYield() }
|
||||||
.maxByOrNull { Automation.rankTileForCityWork(it, cityInfo, foodWeight) }
|
.associateWith { Automation.rankTileForCityWork(it, cityInfo, cityStats) }
|
||||||
val valueBestTile = if (bestTile == null) 0f
|
.maxByOrNull { it.value }
|
||||||
else Automation.rankTileForCityWork(bestTile, cityInfo, foodWeight)
|
?: object : Map.Entry<TileInfo?, Float> {
|
||||||
|
override val key: TileInfo? = null
|
||||||
|
override val value = 0f
|
||||||
|
}
|
||||||
|
|
||||||
val bestJob: String? = getMaxSpecialists()
|
val bestJob: String? = if (cityInfo.manualSpecialists) null else getMaxSpecialists()
|
||||||
.filter { specialistAllocations[it.key]!! < it.value }
|
.filter { specialistAllocations[it.key]!! < it.value }
|
||||||
.map { it.key }
|
.map { it.key }
|
||||||
.maxByOrNull { Automation.rankSpecialist(getStatsOfSpecialist(it), cityInfo) }
|
.maxByOrNull { Automation.rankSpecialist(it, cityInfo, cityStats) }
|
||||||
|
|
||||||
|
|
||||||
var valueBestSpecialist = 0f
|
var valueBestSpecialist = 0f
|
||||||
if (bestJob != null) {
|
if (bestJob != null) {
|
||||||
val specialistStats = getStatsOfSpecialist(bestJob)
|
valueBestSpecialist = Automation.rankSpecialist(bestJob, cityInfo, cityStats)
|
||||||
valueBestSpecialist = Automation.rankSpecialist(specialistStats, cityInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//assign population
|
//assign population
|
||||||
if (valueBestTile > valueBestSpecialist) {
|
if (valueBestTile > valueBestSpecialist) {
|
||||||
if (bestTile != null)
|
if (bestTile != null) {
|
||||||
cityInfo.workedTiles = cityInfo.workedTiles.withItem(bestTile.position)
|
cityInfo.workedTiles = cityInfo.workedTiles.withItem(bestTile.position)
|
||||||
} else if (bestJob != null) specialistAllocations.add(bestJob, 1)
|
cityStats[Stat.Food] += bestTile.getTileStats(cityInfo, cityInfo.civInfo)[Stat.Food]
|
||||||
|
}
|
||||||
|
} else if (bestJob != null) {
|
||||||
|
specialistAllocations.add(bestJob, 1)
|
||||||
|
cityStats[Stat.Food] += specialistFoodBonus
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
cityInfo.cityStats.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unassignExtraPopulation() {
|
fun unassignExtraPopulation() {
|
||||||
@ -162,19 +181,19 @@ class PopulationManager {
|
|||||||
cityInfo.workedTiles.asSequence()
|
cityInfo.workedTiles.asSequence()
|
||||||
.map { cityInfo.tileMap[it] }
|
.map { cityInfo.tileMap[it] }
|
||||||
.minByOrNull {
|
.minByOrNull {
|
||||||
Automation.rankTileForCityWork(it, cityInfo)
|
Automation.rankTileForCityWork(it, cityInfo, cityInfo.cityStats.currentCityStats)
|
||||||
+(if (it.isLocked()) 10 else 0)
|
+(if (it.isLocked()) 10 else 0)
|
||||||
}!!
|
}!!
|
||||||
}
|
}
|
||||||
val valueWorstTile = if (worstWorkedTile == null) 0f
|
val valueWorstTile = if (worstWorkedTile == null) 0f
|
||||||
else Automation.rankTileForCityWork(worstWorkedTile, cityInfo)
|
else Automation.rankTileForCityWork(worstWorkedTile, cityInfo, cityInfo.cityStats.currentCityStats)
|
||||||
|
|
||||||
//evaluate specialists
|
//evaluate specialists
|
||||||
val worstJob: String? = specialistAllocations.keys
|
val worstJob: String? = if (cityInfo.manualSpecialists) null else specialistAllocations.keys
|
||||||
.minByOrNull { Automation.rankSpecialist(getStatsOfSpecialist(it), cityInfo) }
|
.minByOrNull { Automation.rankSpecialist(it, cityInfo, cityInfo.cityStats.currentCityStats) }
|
||||||
var valueWorstSpecialist = 0f
|
var valueWorstSpecialist = 0f
|
||||||
if (worstJob != null)
|
if (worstJob != null)
|
||||||
valueWorstSpecialist = Automation.rankSpecialist(getStatsOfSpecialist(worstJob), cityInfo)
|
valueWorstSpecialist = Automation.rankSpecialist(worstJob, cityInfo, cityInfo.cityStats.currentCityStats)
|
||||||
|
|
||||||
|
|
||||||
//un-assign population
|
//un-assign population
|
||||||
|
@ -257,6 +257,9 @@ class TechManager {
|
|||||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||||
}
|
}
|
||||||
updateTransientBooleans()
|
updateTransientBooleans()
|
||||||
|
for (city in civInfo.cities) {
|
||||||
|
city.updateCitizens = true
|
||||||
|
}
|
||||||
|
|
||||||
civInfo.addNotification("Research of [$techName] has completed!", TechAction(techName), NotificationIcon.Science, techName)
|
civInfo.addNotification("Research of [$techName] has completed!", TechAction(techName), NotificationIcon.Science, techName)
|
||||||
civInfo.popupAlerts.add(PopupAlert(AlertType.TechResearched, techName))
|
civInfo.popupAlerts.add(PopupAlert(AlertType.TechResearched, techName))
|
||||||
|
@ -678,6 +678,7 @@ class MapUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tile.improvementInProgress = null
|
tile.improvementInProgress = null
|
||||||
|
tile.getCity()?.updateCitizens = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +126,17 @@ open class Stats(
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun div(number: Float) = times(1/number)
|
operator fun div(number: Float) = times(1/number)
|
||||||
|
|
||||||
|
/** Apply weighting for Production Ranking */
|
||||||
|
fun applyRankingWeights(){
|
||||||
|
food *= 14
|
||||||
|
production *= 12
|
||||||
|
gold *= 8 // 3 gold worth about 2 production
|
||||||
|
science *= 7
|
||||||
|
culture *= 6
|
||||||
|
happiness *= 10 // base
|
||||||
|
faith *= 5
|
||||||
|
}
|
||||||
|
|
||||||
/** ***Not*** only a debug helper. It returns a string representing the content, already _translated_.
|
/** ***Not*** only a debug helper. It returns a string representing the content, already _translated_.
|
||||||
*
|
*
|
||||||
|
62
core/src/com/unciv/ui/cityscreen/CitizenManagementTable.kt
Normal file
62
core/src/com/unciv/ui/cityscreen/CitizenManagementTable.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.unciv.ui.cityscreen
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.logic.city.CityFocus
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
|
import com.unciv.ui.utils.*
|
||||||
|
|
||||||
|
class CitizenManagementTable(val cityScreen: CityScreen) : Table() {
|
||||||
|
private val innerTable = Table()
|
||||||
|
val city = cityScreen.city
|
||||||
|
|
||||||
|
init {
|
||||||
|
innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().darken(0.5f))
|
||||||
|
add(innerTable).pad(2f).fill()
|
||||||
|
background = ImageGetter.getBackground(Color.WHITE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(visible: Boolean = false) {
|
||||||
|
innerTable.clear()
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
|
isVisible = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isVisible = true
|
||||||
|
|
||||||
|
val colorSelected = BaseScreen.skin.get("selection", Color::class.java)
|
||||||
|
val colorButton = BaseScreen.skin.get("color", Color::class.java)
|
||||||
|
// effectively a button, but didn't want to rewrite TextButton style
|
||||||
|
// and much more compact and can control backgrounds easily based on settings
|
||||||
|
val avoidLabel = "Avoid Growth".toLabel()
|
||||||
|
val avoidCell = Table()
|
||||||
|
avoidCell.touchable = Touchable.enabled
|
||||||
|
avoidCell.add(avoidLabel).pad(5f)
|
||||||
|
avoidCell.onClick { city.avoidGrowth = !city.avoidGrowth; city.reassignPopulation(); cityScreen.update() }
|
||||||
|
|
||||||
|
avoidCell.background = ImageGetter.getBackground(if (city.avoidGrowth) colorSelected else colorButton)
|
||||||
|
innerTable.add(avoidCell).colspan(2).growX().pad(3f)
|
||||||
|
innerTable.row()
|
||||||
|
|
||||||
|
for (focus in CityFocus.values()) {
|
||||||
|
if (!focus.tableEnabled) continue
|
||||||
|
if (focus == CityFocus.FaithFocus && !city.civInfo.gameInfo.isReligionEnabled()) continue
|
||||||
|
val label = focus.label.toLabel()
|
||||||
|
val cell = Table()
|
||||||
|
cell.touchable = Touchable.enabled
|
||||||
|
cell.add(label).pad(5f)
|
||||||
|
cell.onClick { city.cityAIFocus = focus; city.reassignPopulation(); cityScreen.update() }
|
||||||
|
|
||||||
|
cell.background = ImageGetter.getBackground(if (city.cityAIFocus == focus) colorSelected else colorButton)
|
||||||
|
innerTable.add(cell).growX().pad(3f)
|
||||||
|
if (focus.stat != null)
|
||||||
|
innerTable.add(ImageGetter.getStatIcon(focus.stat.name)).size(20f).padRight(5f)
|
||||||
|
innerTable.row()
|
||||||
|
}
|
||||||
|
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,10 +15,10 @@ import com.unciv.models.ruleset.Building
|
|||||||
import com.unciv.models.ruleset.tile.TileImprovement
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.map.TileGroupMap
|
import com.unciv.ui.map.TileGroupMap
|
||||||
import com.unciv.ui.popup.ToastPopup
|
import com.unciv.ui.popup.ToastPopup
|
||||||
import com.unciv.ui.tilegroups.TileGroup
|
|
||||||
import com.unciv.ui.tilegroups.TileSetStrings
|
import com.unciv.ui.tilegroups.TileSetStrings
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -56,6 +56,12 @@ class CityScreen(
|
|||||||
/** Displays raze city button - sits on TOP CENTER */
|
/** Displays raze city button - sits on TOP CENTER */
|
||||||
private var razeCityButtonHolder = Table()
|
private var razeCityButtonHolder = Table()
|
||||||
|
|
||||||
|
/** Displays reset locks button - sits on BOT RIGHT */
|
||||||
|
private var resetCitizensButtonHolder = Table()
|
||||||
|
|
||||||
|
/** Displays reset locks button - sits on BOT RIGHT */
|
||||||
|
private var citizenManagementButtonHolder = Table()
|
||||||
|
|
||||||
/** Displays city stats info */
|
/** Displays city stats info */
|
||||||
private var cityStatsTable = CityStatsTable(this)
|
private var cityStatsTable = CityStatsTable(this)
|
||||||
|
|
||||||
@ -65,6 +71,10 @@ class CityScreen(
|
|||||||
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
|
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
|
||||||
private var selectedConstructionTable = ConstructionInfoTable(this)
|
private var selectedConstructionTable = ConstructionInfoTable(this)
|
||||||
|
|
||||||
|
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
|
||||||
|
private var citizenManagementTable = CitizenManagementTable(this)
|
||||||
|
var citizenManagementVisible = false
|
||||||
|
|
||||||
/** Displays city name, allows switching between cities - sits on BOTTOM CENTER */
|
/** Displays city name, allows switching between cities - sits on BOTTOM CENTER */
|
||||||
private var cityPickerTable = CityScreenCityPickerTable(this)
|
private var cityPickerTable = CityScreenCityPickerTable(this)
|
||||||
|
|
||||||
@ -109,10 +119,27 @@ class CityScreen(
|
|||||||
|
|
||||||
//stage.setDebugTableUnderMouse(true)
|
//stage.setDebugTableUnderMouse(true)
|
||||||
stage.addActor(cityStatsTable)
|
stage.addActor(cityStatsTable)
|
||||||
|
val resetCitizensButton = "Reset Citizens".toTextButton()
|
||||||
|
resetCitizensButton.labelCell.pad(5f)
|
||||||
|
resetCitizensButton.onClick { city.reassignPopulation(resetLocked = true); update() }
|
||||||
|
resetCitizensButtonHolder.add(resetCitizensButton)
|
||||||
|
resetCitizensButtonHolder.pack()
|
||||||
|
stage.addActor(resetCitizensButtonHolder)
|
||||||
|
val citizenManagementButton = "Citizen Management".toTextButton()
|
||||||
|
citizenManagementButton.labelCell.pad(5f)
|
||||||
|
citizenManagementButton.onClick {
|
||||||
|
clearSelection()
|
||||||
|
citizenManagementVisible = true
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
citizenManagementButtonHolder.add(citizenManagementButton)
|
||||||
|
citizenManagementButtonHolder.pack()
|
||||||
|
stage.addActor(citizenManagementButtonHolder)
|
||||||
constructionsTable.addActorsToStage()
|
constructionsTable.addActorsToStage()
|
||||||
stage.addActor(cityInfoTable)
|
stage.addActor(cityInfoTable)
|
||||||
stage.addActor(selectedConstructionTable)
|
stage.addActor(selectedConstructionTable)
|
||||||
stage.addActor(tileTable)
|
stage.addActor(tileTable)
|
||||||
|
stage.addActor(citizenManagementTable)
|
||||||
stage.addActor(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait
|
stage.addActor(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait
|
||||||
stage.addActor(exitCityButton)
|
stage.addActor(exitCityButton)
|
||||||
update()
|
update()
|
||||||
@ -150,7 +177,24 @@ class CityScreen(
|
|||||||
tileTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
tileTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
||||||
selectedConstructionTable.update(selectedConstruction)
|
selectedConstructionTable.update(selectedConstruction)
|
||||||
selectedConstructionTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
selectedConstructionTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
||||||
|
citizenManagementTable.update(citizenManagementVisible)
|
||||||
|
citizenManagementTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
||||||
|
if (selectedTile == null && selectedConstruction == null && !citizenManagementVisible)
|
||||||
|
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
|
||||||
|
posFromEdge, Align.bottomRight)
|
||||||
|
else if (selectedConstruction != null)
|
||||||
|
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
|
||||||
|
posFromEdge + selectedConstructionTable.height + 10f, Align.bottomRight)
|
||||||
|
else if (selectedTile != null)
|
||||||
|
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
|
||||||
|
posFromEdge + tileTable.height + 10f, Align.bottomRight)
|
||||||
|
else
|
||||||
|
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
|
||||||
|
posFromEdge + citizenManagementTable.height + 10f, Align.bottomRight)
|
||||||
|
citizenManagementButtonHolder.isVisible = !citizenManagementVisible
|
||||||
|
citizenManagementButtonHolder.setPosition(stage.width - posFromEdge,
|
||||||
|
posFromEdge + resetCitizensButtonHolder.y + resetCitizensButtonHolder.height + 10f, Align.bottomRight)
|
||||||
|
|
||||||
// In portrait mode only: calculate already occupied horizontal space
|
// In portrait mode only: calculate already occupied horizontal space
|
||||||
val rightMargin = when {
|
val rightMargin = when {
|
||||||
!isPortrait() -> 0f
|
!isPortrait() -> 0f
|
||||||
@ -343,9 +387,12 @@ class CityScreen(
|
|||||||
if (tileGroup.isWorkable && canChangeState) {
|
if (tileGroup.isWorkable && canChangeState) {
|
||||||
if (!tileInfo.providesYield() && cityInfo.population.getFreePopulation() > 0) {
|
if (!tileInfo.providesYield() && cityInfo.population.getFreePopulation() > 0) {
|
||||||
cityInfo.workedTiles.add(tileInfo.position)
|
cityInfo.workedTiles.add(tileInfo.position)
|
||||||
|
cityInfo.lockedTiles.add(tileInfo.position)
|
||||||
game.settings.addCompletedTutorialTask("Reassign worked tiles")
|
game.settings.addCompletedTutorialTask("Reassign worked tiles")
|
||||||
} else if (tileInfo.isWorked() && !tileInfo.isLocked())
|
} else if (tileInfo.isWorked()) {
|
||||||
cityInfo.workedTiles.remove(tileInfo.position)
|
cityInfo.workedTiles.remove(tileInfo.position)
|
||||||
|
cityInfo.lockedTiles.remove(tileInfo.position)
|
||||||
|
}
|
||||||
cityInfo.cityStats.update()
|
cityInfo.cityStats.update()
|
||||||
}
|
}
|
||||||
update()
|
update()
|
||||||
@ -365,11 +412,13 @@ class CityScreen(
|
|||||||
pickTileData = null
|
pickTileData = null
|
||||||
}
|
}
|
||||||
selectedTile = null
|
selectedTile = null
|
||||||
|
citizenManagementVisible = false
|
||||||
}
|
}
|
||||||
private fun selectTile(newTile: TileInfo?) {
|
private fun selectTile(newTile: TileInfo?) {
|
||||||
selectedConstruction = null
|
selectedConstruction = null
|
||||||
selectedQueueEntryTargetTile = null
|
selectedQueueEntryTargetTile = null
|
||||||
pickTileData = null
|
pickTileData = null
|
||||||
|
citizenManagementVisible = false
|
||||||
selectedTile = newTile
|
selectedTile = newTile
|
||||||
}
|
}
|
||||||
fun clearSelection() = selectTile(null)
|
fun clearSelection() = selectTile(null)
|
||||||
|
@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
|||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.city.CityFlags
|
import com.unciv.logic.city.CityFlags
|
||||||
|
import com.unciv.logic.city.CityFocus
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
@ -35,9 +36,24 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
innerTable.clear()
|
innerTable.clear()
|
||||||
|
|
||||||
val miniStatsTable = Table()
|
val miniStatsTable = Table()
|
||||||
|
val selected = BaseScreen.skin.get("selection", Color::class.java)
|
||||||
for ((stat, amount) in cityInfo.cityStats.currentCityStats) {
|
for ((stat, amount) in cityInfo.cityStats.currentCityStats) {
|
||||||
if (stat == Stat.Faith && !cityInfo.civInfo.gameInfo.isReligionEnabled()) continue
|
if (stat == Stat.Faith && !cityInfo.civInfo.gameInfo.isReligionEnabled()) continue
|
||||||
miniStatsTable.add(ImageGetter.getStatIcon(stat.name)).size(20f).padRight(5f)
|
val icon = Table()
|
||||||
|
if (cityInfo.cityAIFocus.stat == stat) {
|
||||||
|
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = selected))
|
||||||
|
icon.onClick {
|
||||||
|
cityInfo.cityAIFocus = CityFocus.NoFocus
|
||||||
|
cityInfo.reassignPopulation(); cityScreen.update()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = Color.CLEAR))
|
||||||
|
icon.onClick {
|
||||||
|
cityInfo.cityAIFocus = cityInfo.cityAIFocus.safeValueOf(stat)
|
||||||
|
cityInfo.reassignPopulation(); cityScreen.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
miniStatsTable.add(icon).size(27f).padRight(5f)
|
||||||
val valueToDisplay = if (stat == Stat.Happiness) cityInfo.cityStats.happinessList.values.sum() else amount
|
val valueToDisplay = if (stat == Stat.Happiness) cityInfo.cityStats.happinessList.values.sum() else amount
|
||||||
miniStatsTable.add(round(valueToDisplay).toInt().toLabel()).padRight(10f)
|
miniStatsTable.add(round(valueToDisplay).toInt().toLabel()).padRight(10f)
|
||||||
}
|
}
|
||||||
@ -57,6 +73,8 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
private fun addText() {
|
private fun addText() {
|
||||||
val unassignedPopString = "{Unassigned population}: ".tr() +
|
val unassignedPopString = "{Unassigned population}: ".tr() +
|
||||||
cityInfo.population.getFreePopulation().toString() + "/" + cityInfo.population.population
|
cityInfo.population.getFreePopulation().toString() + "/" + cityInfo.population.population
|
||||||
|
val unassignedPopLabel = unassignedPopString.toLabel()
|
||||||
|
unassignedPopLabel.onClick { cityInfo.reassignPopulation(); cityScreen.update() }
|
||||||
|
|
||||||
var turnsToExpansionString =
|
var turnsToExpansionString =
|
||||||
if (cityInfo.cityStats.currentCityStats.culture > 0 && cityInfo.expansion.getChoosableTiles().any()) {
|
if (cityInfo.cityStats.currentCityStats.culture > 0 && cityInfo.expansion.getChoosableTiles().any()) {
|
||||||
@ -80,7 +98,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
}.tr()
|
}.tr()
|
||||||
turnsToPopString += " (${cityInfo.population.foodStored}${Fonts.food}/${cityInfo.population.getFoodToNextPopulation()}${Fonts.food})"
|
turnsToPopString += " (${cityInfo.population.foodStored}${Fonts.food}/${cityInfo.population.getFoodToNextPopulation()}${Fonts.food})"
|
||||||
|
|
||||||
innerTable.add(unassignedPopString.toLabel()).row()
|
innerTable.add(unassignedPopLabel).row()
|
||||||
innerTable.add(turnsToExpansionString.toLabel()).row()
|
innerTable.add(turnsToExpansionString.toLabel()).row()
|
||||||
innerTable.add(turnsToPopString.toLabel()).row()
|
innerTable.add(turnsToPopString.toLabel()).row()
|
||||||
|
|
||||||
|
@ -6,15 +6,27 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
|||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
|
|
||||||
class SpecialistAllocationTable(val cityScreen: CityScreen): Table(BaseScreen.skin){
|
class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
|
||||||
val cityInfo = cityScreen.city
|
val cityInfo = cityScreen.city
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
clear()
|
clear()
|
||||||
|
// Auto/Manual Specialists Toggle
|
||||||
|
// Color of "color" coming from Skin.json that's loaded into BaseScreen
|
||||||
|
// 5 columns: unassignButton, AllocationTable, assignButton, SeparatorVertical, SpecialistsStatsTabe
|
||||||
|
if (cityInfo.manualSpecialists) {
|
||||||
|
val manualSpecialists = "Manual Specialists".toLabel().addBorder(5f, BaseScreen.skin.get("color", Color::class.java))
|
||||||
|
manualSpecialists.onClick { cityInfo.manualSpecialists = false; cityInfo.reassignPopulation(); cityScreen.update() }
|
||||||
|
add(manualSpecialists).colspan(5).row()
|
||||||
|
} else {
|
||||||
|
val autoSpecialists = "Auto Specialists".toLabel().addBorder(5f, BaseScreen.skin.get("color", Color::class.java))
|
||||||
|
autoSpecialists.onClick { cityInfo.manualSpecialists = true; update() }
|
||||||
|
add(autoSpecialists).colspan(5).row()
|
||||||
|
}
|
||||||
for ((specialistName, maxSpecialists) in cityInfo.population.getMaxSpecialists()) {
|
for ((specialistName, maxSpecialists) in cityInfo.population.getMaxSpecialists()) {
|
||||||
if (!cityInfo.getRuleset().specialists.containsKey(specialistName)) // specialist doesn't exist in this ruleset, probably a mod
|
if (!cityInfo.getRuleset().specialists.containsKey(specialistName)) // specialist doesn't exist in this ruleset, probably a mod
|
||||||
continue
|
continue
|
||||||
@ -31,7 +43,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(BaseScreen.sk
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getAllocationTable(assignedSpecialists: Int, maxSpecialists: Int, specialistName: String):Table{
|
fun getAllocationTable(assignedSpecialists: Int, maxSpecialists: Int, specialistName: String): Table {
|
||||||
|
|
||||||
val specialistIconTable = Table()
|
val specialistIconTable = Table()
|
||||||
val specialistObject = cityInfo.getRuleset().specialists[specialistName]!!
|
val specialistObject = cityInfo.getRuleset().specialists[specialistName]!!
|
||||||
@ -44,14 +56,15 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(BaseScreen.sk
|
|||||||
return specialistIconTable
|
return specialistIconTable
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAssignButton(assignedSpecialists: Int, maxSpecialists: Int, specialistName: String):Actor {
|
private fun getAssignButton(assignedSpecialists: Int, maxSpecialists: Int, specialistName: String): Actor {
|
||||||
|
|
||||||
if (assignedSpecialists >= maxSpecialists || cityInfo.isPuppet) return Table()
|
if (assignedSpecialists >= maxSpecialists || cityInfo.isPuppet) return Table()
|
||||||
val assignButton = "+".toLabel(Color.BLACK, Constants.headingFontSize)
|
val assignButton = "+".toLabel(Color.BLACK, Constants.headingFontSize)
|
||||||
.apply { this.setAlignment(Align.center) }
|
.apply { this.setAlignment(Align.center) }
|
||||||
.surroundWithCircle(30f).apply { circle.color= Color.GREEN.darken(0.2f) }
|
.surroundWithCircle(30f).apply { circle.color = Color.GREEN.darken(0.2f) }
|
||||||
assignButton.onClick {
|
assignButton.onClick {
|
||||||
cityInfo.population.specialistAllocations.add(specialistName, 1)
|
cityInfo.population.specialistAllocations.add(specialistName, 1)
|
||||||
|
cityInfo.manualSpecialists = true
|
||||||
cityInfo.cityStats.update()
|
cityInfo.cityStats.update()
|
||||||
cityScreen.update()
|
cityScreen.update()
|
||||||
}
|
}
|
||||||
@ -60,17 +73,18 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(BaseScreen.sk
|
|||||||
return assignButton
|
return assignButton
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUnassignButton(assignedSpecialists: Int, specialistName: String):Actor {
|
private fun getUnassignButton(assignedSpecialists: Int, specialistName: String): Actor {
|
||||||
val unassignButton = "-".toLabel(Color.BLACK,Constants.headingFontSize)
|
val unassignButton = "-".toLabel(Color.BLACK, Constants.headingFontSize)
|
||||||
.apply { this.setAlignment(Align.center) }
|
.apply { this.setAlignment(Align.center) }
|
||||||
.surroundWithCircle(30f).apply { circle.color= Color.RED.darken(0.1f) }
|
.surroundWithCircle(30f).apply { circle.color = Color.RED.darken(0.1f) }
|
||||||
unassignButton.onClick {
|
unassignButton.onClick {
|
||||||
cityInfo.population.specialistAllocations.add(specialistName, -1)
|
cityInfo.population.specialistAllocations.add(specialistName, -1)
|
||||||
|
cityInfo.manualSpecialists = true
|
||||||
cityInfo.cityStats.update()
|
cityInfo.cityStats.update()
|
||||||
cityScreen.update()
|
cityScreen.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assignedSpecialists <= 0 || cityInfo.isPuppet) unassignButton.isVisible=false
|
if (assignedSpecialists <= 0 || cityInfo.isPuppet) unassignButton.isVisible = false
|
||||||
if (!UncivGame.Current.worldScreen.isPlayersTurn) unassignButton.clear()
|
if (!UncivGame.Current.worldScreen.isPlayersTurn) unassignButton.clear()
|
||||||
return unassignButton
|
return unassignButton
|
||||||
}
|
}
|
||||||
@ -88,7 +102,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen): Table(BaseScreen.sk
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun asExpander(onChange: (()->Unit)?): ExpanderTab {
|
fun asExpander(onChange: (() -> Unit)?): ExpanderTab {
|
||||||
return ExpanderTab(
|
return ExpanderTab(
|
||||||
title = "{Specialists}:",
|
title = "{Specialists}:",
|
||||||
fontSize = Constants.defaultFontSize,
|
fontSize = Constants.defaultFontSize,
|
||||||
|
@ -282,6 +282,7 @@ object UnitActions {
|
|||||||
tile.setPillaged()
|
tile.setPillaged()
|
||||||
unit.civInfo.lastSeenImprovement.remove(tile.position)
|
unit.civInfo.lastSeenImprovement.remove(tile.position)
|
||||||
if (tile.resource != null) tile.getOwner()?.updateDetailedCivResources() // this might take away a resource
|
if (tile.resource != null) tile.getOwner()?.updateDetailedCivResources() // this might take away a resource
|
||||||
|
tile.getCity()?.updateCitizens = true
|
||||||
|
|
||||||
val freePillage = unit.hasUnique(UniqueType.NoMovementToPillage, checkCivInfoUniques = true)
|
val freePillage = unit.hasUnique(UniqueType.NoMovementToPillage, checkCivInfoUniques = true)
|
||||||
if (!freePillage) unit.useMovementPoints(1f)
|
if (!freePillage) unit.useMovementPoints(1f)
|
||||||
|
Loading…
Reference in New Issue
Block a user