Added Replacable Parts tech and Great War Infantry
Musketman now upgrades to Rifleman Solved more rare concurrency problems
This commit is contained in:
parent
28ae533acc
commit
24b27a791f
22 changed files with 427 additions and 387 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -127,3 +127,5 @@ gradle.properties
|
|||
SaveFiles/
|
||||
android/android-release.apk
|
||||
android/assets/GameSettings.json
|
||||
android/release/output.json
|
||||
android/release/android-release.apk
|
||||
|
|
|
@ -57,6 +57,7 @@ All the following are from [the Noun Project](https://thenounproject.com) licenc
|
|||
|
||||
### Modern
|
||||
|
||||
* [Helmet](https://thenounproject.com/term/helmet/25216/) By Daniel Turner for Great War Infantry
|
||||
* [Tank](https://thenounproject.com/term/tank/1287510/) By corpus delicti for Landship
|
||||
|
||||
### Great People
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
![](https://travis-ci.org/yairm210/UnCiv.svg?branch=master)
|
||||
|
||||
[![LibGDX](https://img.shields.io/badge/libgdx-1.9.6-red.svg)](https://libgdx.badlogicgames.com/)
|
||||
[![Kotlin](https://img.shields.io/badge/kotlin-1.2.41-orange.svg)](http://kotlinlang.org/)
|
||||
[![LibGDX](https://img.shields.io/badge/libgdx-1.9.9-red.svg)](https://libgdx.badlogicgames.com/)
|
||||
[![Kotlin](https://img.shields.io/badge/kotlin-1.3.10-orange.svg)](http://kotlinlang.org/)
|
||||
|
||||
## What is this?
|
||||
|
||||
|
|
BIN
android/Images/TechIcons/Replacable Parts.png
Normal file
BIN
android/Images/TechIcons/Replacable Parts.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
android/Images/UnitIcons/Great War Infantry.png
Normal file
BIN
android/Images/UnitIcons/Great War Infantry.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1 KiB |
File diff suppressed because it is too large
Load diff
Binary file not shown.
Before Width: | Height: | Size: 768 KiB After Width: | Height: | Size: 780 KiB |
|
@ -363,6 +363,11 @@
|
|||
prerequisites:["Electricity"],
|
||||
baseDescription:"Does nothing since we have no sea tiles - In theory, allows construction of offshore platforms and submarines"
|
||||
},*/
|
||||
{
|
||||
name:"Replacable Parts",
|
||||
row:4,
|
||||
prerequisites:["Electricity","Steam Power"]
|
||||
},
|
||||
{
|
||||
name:"Radio",
|
||||
row:5,
|
||||
|
@ -385,7 +390,7 @@
|
|||
{
|
||||
name:"Plastics",
|
||||
row:3,
|
||||
prerequisites:["Biology"]
|
||||
prerequisites:["Biology","Replacable Parts"]
|
||||
},/*
|
||||
{
|
||||
name:"Electronics",
|
||||
|
|
|
@ -292,6 +292,8 @@
|
|||
strength:24,
|
||||
cost: 150,
|
||||
requiredTech:"Gunpowder",
|
||||
upgradesTo:"Rifleman,"
|
||||
obsoleteTech:"Rifling",
|
||||
hurryCostModifier:20
|
||||
},
|
||||
{
|
||||
|
@ -303,6 +305,8 @@
|
|||
strength:28,
|
||||
cost: 150,
|
||||
requiredTech:"Gunpowder",
|
||||
upgradesTo:"Rifleman,"
|
||||
obsoleteTech:"Rifling",
|
||||
hurryCostModifier:20
|
||||
},
|
||||
{
|
||||
|
@ -337,6 +341,8 @@
|
|||
strength:34,
|
||||
cost: 225,
|
||||
requiredTech:"Rifling",
|
||||
obsoleteTech:"Replacable Parts",
|
||||
upgradesTo:"Great War Infantry",
|
||||
hurryCostModifier:20
|
||||
},
|
||||
{
|
||||
|
@ -347,6 +353,7 @@
|
|||
cost: 225,
|
||||
requiredTech:"Military Science",
|
||||
requiredResource:"Horses",
|
||||
upgradesTo:"Landship",
|
||||
uniques:["Can move after attacking","No defensive terrain bonus","Penalty vs City 33%" ],
|
||||
hurryCostModifier:20
|
||||
},
|
||||
|
@ -359,7 +366,8 @@
|
|||
range:3,
|
||||
cost: 320,
|
||||
requiredTech:"Dynamite",
|
||||
uniques:["Bonus vs City 200%","No defensive terrain bonus","Must set up to ranged attack","Limited Visibility","Indirect Fire"],
|
||||
uniques:["Bonus vs City 200%","No defensive terrain bonus",
|
||||
"Must set up to ranged attack","Limited Visibility","Indirect Fire"],
|
||||
hurryCostModifier:20
|
||||
},
|
||||
{
|
||||
|
@ -387,6 +395,15 @@
|
|||
uniques:["Can move after attacking","No defensive terrain bonus"],
|
||||
hurryCostModifier:20
|
||||
},
|
||||
{
|
||||
name:"Great War Infantry",
|
||||
unitType:"Melee",
|
||||
movement:2,
|
||||
strength:50,
|
||||
cost: 320,
|
||||
requiredTech:"Replacable Parts",
|
||||
hurryCostModifier:20
|
||||
},
|
||||
|
||||
/* Great people */
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ android {
|
|||
applicationId "com.unciv.game"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 169
|
||||
versionName "2.10.8"
|
||||
versionCode 170
|
||||
versionName "2.10.9"
|
||||
}
|
||||
|
||||
// Had to add this crap for Travis to build, it wanted to sign the app
|
||||
|
|
|
@ -62,7 +62,7 @@ class UnCivGame : Game() {
|
|||
fun setWorldScreen() {
|
||||
setScreen(worldScreen)
|
||||
Gdx.input.inputProcessor = worldScreen.stage
|
||||
worldScreen.update() // This can set the screen to the policy picker or tech picker screen, so the input processor must come before
|
||||
worldScreen.shouldUpdate=true // This can set the screen to the policy picker or tech picker screen, so the input processor must come before
|
||||
}
|
||||
|
||||
override fun resume() {
|
||||
|
|
|
@ -34,7 +34,8 @@ class UnitAutomation{
|
|||
return SpecificUnitAutomation().automateWorkBoats(unit)
|
||||
}
|
||||
|
||||
if(unit.name.startsWith("Great")){
|
||||
if(unit.name.startsWith("Great")
|
||||
&& unit.name in GreatPersonManager().statToGreatPersonMapping.values){ // So "Great War Infantry" isn't caught here
|
||||
return SpecificUnitAutomation().automateGreatPerson(unit)// I don't know what to do with you yet.
|
||||
}
|
||||
|
||||
|
@ -357,10 +358,8 @@ class SpecificUnitAutomation{
|
|||
if (unit.currentMovement > 0 && unit.currentTile == closestReachableResource) {
|
||||
val createImprovementAction = UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen)
|
||||
.firstOrNull { it.name.startsWith("Create") } // could be either fishing boats or oil well
|
||||
if (createImprovementAction != null) {
|
||||
createImprovementAction.action()
|
||||
return // unit is already gone, can't "explore"
|
||||
}
|
||||
if (createImprovementAction != null)
|
||||
return createImprovementAction.action() // unit is already gone, can't "explore"
|
||||
}
|
||||
}
|
||||
else UnitAutomation().explore(unit, unit.getDistanceToTiles())
|
||||
|
@ -402,10 +401,7 @@ class SpecificUnitAutomation{
|
|||
.firstOrNull { unit.movementAlgs().canReach(it) }
|
||||
|
||||
if(bestCityLocation==null) // We got a badass over here, all tiles within 5 are taken? Screw it, random walk.
|
||||
{
|
||||
UnitAutomation().explore(unit, unit.getDistanceToTiles())
|
||||
return
|
||||
}
|
||||
return UnitAutomation().explore(unit, unit.getDistanceToTiles())
|
||||
|
||||
if(bestCityLocation.getTilesInDistance(3).any { it.isCityCenter() })
|
||||
throw Exception("City within distance")
|
||||
|
@ -430,7 +426,7 @@ class SpecificUnitAutomation{
|
|||
for(city in citiesByStatBoost){
|
||||
val pathToCity =unit.movementAlgs().getShortestPath(city.getCenterTile())
|
||||
if(pathToCity.isEmpty()) continue
|
||||
if(pathToCity.size>2) {
|
||||
if(pathToCity.size>2){
|
||||
unit.movementAlgs().headTowards(city.getCenterTile())
|
||||
return
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ class TechPickerScreen(internal val civInfo: CivilizationInfo) : PickerScreen()
|
|||
} else
|
||||
civTech.techsToResearch = techsToResearch
|
||||
game.setWorldScreen()
|
||||
game.worldScreen.update()
|
||||
game.worldScreen.shouldUpdate=true
|
||||
dispose()
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ class MinimapHolder(val tileMapHolder: TileMapHolder): Table(){
|
|||
populationImage.onClick {
|
||||
settings.showWorkedTiles = !settings.showWorkedTiles
|
||||
populationImage.image.color.a = if(settings.showWorkedTiles) 1f else 0.5f
|
||||
worldScreen.update()
|
||||
worldScreen.shouldUpdate=true
|
||||
}
|
||||
toggleIconTable.add(populationImage).row()
|
||||
|
||||
|
@ -128,7 +128,7 @@ class MinimapHolder(val tileMapHolder: TileMapHolder): Table(){
|
|||
resourceImage.onClick {
|
||||
settings.showResourcesAndImprovements = !settings.showResourcesAndImprovements
|
||||
resourceImage.image.color.a = if(settings.showResourcesAndImprovements) 1f else 0.5f
|
||||
worldScreen.update()
|
||||
worldScreen.shouldUpdate=true
|
||||
}
|
||||
toggleIconTable.add(resourceImage)
|
||||
toggleIconTable.pack()
|
||||
|
|
|
@ -102,7 +102,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
}
|
||||
|
||||
worldScreen.bottomBar.unitTable.tileSelected(tileInfo)
|
||||
worldScreen.update()
|
||||
worldScreen.shouldUpdate=true
|
||||
}
|
||||
|
||||
private fun addMoveHereButtonToTile(selectedUnit: MapUnit, tileInfo: TileInfo, tileGroup: WorldTileGroup) {
|
||||
|
@ -114,7 +114,8 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
val turnsToGetThere = selectedUnit.movementAlgs().getShortestPath(tileInfo).size
|
||||
val numberCircle = ImageGetter.getImage("OtherIcons/Circle").apply { width = size / 2; height = size / 2;color = Color.BLUE }
|
||||
moveHereButton.addActor(numberCircle)
|
||||
moveHereButton.addActor(Label(turnsToGetThere.toString(), CameraStageBaseScreen.skin).apply { center(numberCircle); setFontColor(Color.WHITE) })
|
||||
moveHereButton.addActor(Label(turnsToGetThere.toString(), CameraStageBaseScreen.skin)
|
||||
.apply { center(numberCircle); setFontColor(Color.WHITE) })
|
||||
|
||||
val unitIcon = ImageGetter.getUnitImage(selectedUnit, size / 2)
|
||||
unitIcon.y = size - unitIcon.height
|
||||
|
@ -132,7 +133,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
|
||||
// we don't update it directly because we're on a different thread; instead, we tell it to update itself
|
||||
worldScreen.shouldUpdate = true
|
||||
moveToOverlay!!.remove()
|
||||
moveToOverlay?.remove()
|
||||
moveToOverlay = null
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
// Here it's the same, only the Y axis is inverted - when at 0 we're at the top, not bottom - so we invert it back.
|
||||
scrollY = maxY - (tileGroup.y + tileGroup.width / 2 - worldScreen.stage.height / 2)
|
||||
updateVisualScroll()
|
||||
worldScreen.update()
|
||||
worldScreen.shouldUpdate=true
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,8 +86,10 @@ class WorldScreen : CameraStageBaseScreen() {
|
|||
createNextTurnButton() // needs civ table to be positioned
|
||||
}
|
||||
|
||||
|
||||
fun update() {
|
||||
// This is private so that we will set the shouldUpdate to true instead.
|
||||
// That way, not only do we save a lot of unneccesary updates, we also ensure that all updates are called from the main GL thread
|
||||
// and we don't get any silly concurrency problems!
|
||||
private fun update() {
|
||||
// many of the display functions will be called with the game clone and not the actual game,
|
||||
// because that's guaranteed to stay the exact same and so we won't get any concurrent modification exceptions
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
|||
attackButton.onClick {
|
||||
attacker.unit.moveToTile(attackableEnemy.tileToAttackFrom)
|
||||
battle.attack(attacker, defender)
|
||||
worldScreen.update()
|
||||
worldScreen.shouldUpdate=true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,6 @@ class WorldScreenDisplayOptionsTable() : PopupTable(){
|
|||
|
||||
pack() // Needed to show the background.
|
||||
center(UnCivGame.Current.worldScreen.stage)
|
||||
UnCivGame.Current.worldScreen.update()
|
||||
UnCivGame.Current.worldScreen.shouldUpdate=true
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ class IdleUnitButton (internal val unitTable: UnitTable,
|
|||
tileToSelect = tilesWithIdleUnits[index]
|
||||
}
|
||||
tileMapHolder.setCenterPosition(tileToSelect.position)
|
||||
unitTable.worldScreen.update()
|
||||
unitTable.worldScreen.shouldUpdate=true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ class UnitActions {
|
|||
actionList += UnitAction("Disband unit",unit.currentMovement != 0f
|
||||
) {
|
||||
YesNoPopupTable("Do you really want to disband this unit?".tr(),
|
||||
{unit.destroy(); worldScreen.update()} )
|
||||
{unit.destroy(); worldScreen.shouldUpdate=true} )
|
||||
}
|
||||
|
||||
return actionList
|
||||
|
|
|
@ -14,7 +14,9 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
|
|||
|
||||
fun getIconForUnitAction(unitAction:String): Actor {
|
||||
if(unitAction.startsWith("Upgrade to")){
|
||||
val unitToUpgradeTo = Regex("""Upgrade to \[(\S*)\]""").find(unitAction)!!.groups[1]!!.value
|
||||
// Regexplaination: start with a [, take as many non-] chars as you can, until you reach a ].
|
||||
// What you find between the first [ and the first ] that comes after it, will be group no. 1
|
||||
val unitToUpgradeTo = Regex("""Upgrade to \[([^\]]*)\]""").find(unitAction)!!.groups[1]!!.value
|
||||
return ImageGetter.getUnitIcon(unitToUpgradeTo)
|
||||
}
|
||||
when(unitAction){
|
||||
|
@ -60,7 +62,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
|
|||
actionButton.add(Label(unitAction.name.tr(),CameraStageBaseScreen.skin)
|
||||
.setFontColor(Color.WHITE)).pad(5f)
|
||||
actionButton.pack()
|
||||
actionButton.onClick({ unitAction.action(); UnCivGame.Current.worldScreen.update() })
|
||||
actionButton.onClick { unitAction.action(); UnCivGame.Current.worldScreen.shouldUpdate=true }
|
||||
if (!unitAction.canAct) actionButton.disable()
|
||||
return actionButton
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue