Added Replacable Parts tech and Great War Infantry

Musketman now upgrades to Rifleman
Solved more rare concurrency problems
This commit is contained in:
Yair Morgenstern 2018-12-02 23:05:05 +02:00
parent 28ae533acc
commit 24b27a791f
22 changed files with 427 additions and 387 deletions

2
.gitignore vendored
View file

@ -127,3 +127,5 @@ gradle.properties
SaveFiles/
android/android-release.apk
android/assets/GameSettings.json
android/release/output.json
android/release/android-release.apk

View file

@ -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

View file

@ -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?

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

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

View file

@ -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",

View file

@ -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 */

View file

@ -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

View file

@ -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() {

View file

@ -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
}

View file

@ -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()
}

View file

@ -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()

View file

@ -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
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -41,7 +41,7 @@ class IdleUnitButton (internal val unitTable: UnitTable,
tileToSelect = tilesWithIdleUnits[index]
}
tileMapHolder.setCenterPosition(tileToSelect.position)
unitTable.worldScreen.update()
unitTable.worldScreen.shouldUpdate=true
}
}

View file

@ -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

View file

@ -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
}