"Sleep until healed" functionality (#1821)

* "Sleep until healed" functionality

* Unit test for actions translations is added

* "Fortify until healed" functionality

* Refactoring
This commit is contained in:
JackRainy
2020-02-02 09:55:10 +02:00
committed by GitHub
parent 0914750489
commit db5cc82ec7
13 changed files with 142 additions and 62 deletions

View File

@ -1380,10 +1380,12 @@ Stop automation =
Construct road = Construct road =
# Requires translation! # Requires translation!
Fortify = Fortify =
Fortify until healed = Fortify until healed
# Requires translation! # Requires translation!
Fortification = Fortification =
# Requires translation! # Requires translation!
Sleep = Sleep =
Sleep until healed = Sleep until healed
# Requires translation! # Requires translation!
Moving = Moving =
# Requires translation! # Requires translation!

View File

@ -760,8 +760,10 @@ Automate = Автоматизировать
Stop automation = Остановить автоматизацию Stop automation = Остановить автоматизацию
Construct road = Построить дорогу Construct road = Построить дорогу
Fortify = Укрепить Fortify = Укрепить
Fortify until healed = Укрепить до выздоровления
Fortification = к защите Fortification = к защите
Sleep = Спать Sleep = Спать
Sleep until healed = Спать до выздоровления
Moving = В движении Moving = В движении
Set up = Подготовиться Set up = Подготовиться
Upgrade to [unitType] ([goldCost] gold) = Улучшить до [unitType] ([goldCost] золота) Upgrade to [unitType] ([goldCost] gold) = Улучшить до [unitType] ([goldCost] золота)

View File

@ -762,8 +762,10 @@ Automate = Автоматизувати
Stop automation = Зупинити автоматизацію Stop automation = Зупинити автоматизацію
Construct road = Будувати дорогу Construct road = Будувати дорогу
Fortify = Укріпити Fortify = Укріпити
Fortify until healed = Укріпити до одужання
Fortification = Фортифікація Fortification = Фортифікація
Sleep = Спати Sleep = Спати
Sleep until healed = Спати до одужання
Moving = У русі Moving = У русі
Set up = Підготуватися Set up = Підготуватися
Upgrade to [unitType] ([goldCost] gold) = Удосконалити до [unitType] ([goldCost] золота) Upgrade to [unitType] ([goldCost] gold) = Удосконалити до [unitType] ([goldCost] золота)

View File

@ -760,8 +760,10 @@ Automate =
Stop automation = Stop automation =
Construct road = Construct road =
Fortify = Fortify =
Fortify until healed =
Fortification = Fortification =
Sleep = Sleep =
Sleep until healed =
Moving = Moving =
Set up = Set up =
Upgrade to [unitType] ([goldCost] gold) = Upgrade to [unitType] ([goldCost] gold) =

View File

@ -41,6 +41,7 @@ class Constants{
val unitActionSetUp = "Set Up" val unitActionSetUp = "Set Up"
val unitActionSleep = "Sleep" val unitActionSleep = "Sleep"
val unitActionSleepUntilHealed = "Sleep until healed"
val unitActionAutomation = "Automate" val unitActionAutomation = "Automate"
val unitActionExplore = "Explore" val unitActionExplore = "Explore"
val futureTech = "Future Tech" val futureTech = "Future Tech"

View File

@ -201,7 +201,7 @@ object Battle {
unit.useMovementPoints(1f) unit.useMovementPoints(1f)
} else unit.currentMovement = 0f } else unit.currentMovement = 0f
unit.attacksThisTurn += 1 unit.attacksThisTurn += 1
if (unit.isFortified() || unit.action == Constants.unitActionSleep) if (unit.isFortified() || unit.isSleeping())
attacker.unit.action = null // but not, for instance, if it's Set Up - then it should definitely keep the action! attacker.unit.action = null // but not, for instance, if it's Set Up - then it should definitely keep the action!
} else if (attacker is CityCombatant) { } else if (attacker is CityCombatant) {
attacker.city.attackedThisTurn = true attacker.city.attackedThisTurn = true

View File

@ -166,6 +166,10 @@ class MapUnit {
return action?.startsWith("Fortify") == true return action?.startsWith("Fortify") == true
} }
fun isSleeping(): Boolean {
return action?.startsWith("Sleep") == true
}
fun getFortificationTurns(): Int { fun getFortificationTurns(): Int {
if(!isFortified()) return 0 if(!isFortified()) return 0
return action!!.split(" ")[1].toInt() return action!!.split(" ")[1].toInt()
@ -181,7 +185,7 @@ class MapUnit {
if (name == Constants.worker && getTile().improvementInProgress != null) return false if (name == Constants.worker && getTile().improvementInProgress != null) return false
if (hasUnique("Can construct roads") && currentTile.improvementInProgress=="Road") return false if (hasUnique("Can construct roads") && currentTile.improvementInProgress=="Road") return false
if (isFortified()) return false if (isFortified()) return false
if (action==Constants.unitActionExplore || action==Constants.unitActionSleep if (action==Constants.unitActionExplore || isSleeping()
|| action == Constants.unitActionAutomation) return false || action == Constants.unitActionAutomation) return false
return true return true
} }
@ -268,13 +272,17 @@ class MapUnit {
action = "Fortify 0" action = "Fortify 0"
} }
fun fortifyUntilHealed() {
action = "Fortify 0 until healed"
}
fun fortifyIfCan() { fun fortifyIfCan() {
if (canFortify()) { if (canFortify()) {
fortify() fortify()
} }
} }
fun adjacentHealingBonus():Int{ private fun adjacentHealingBonus():Int{
var healingBonus = 0 var healingBonus = 0
if(hasUnique("This unit and all others in adjacent tiles heal 5 additional HP per turn")) healingBonus +=5 if(hasUnique("This unit and all others in adjacent tiles heal 5 additional HP per turn")) healingBonus +=5
if(hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")) healingBonus +=5 if(hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")) healingBonus +=5
@ -337,7 +345,8 @@ class MapUnit {
if(currentMovement == getMaxMovement().toFloat() if(currentMovement == getMaxMovement().toFloat()
&& isFortified()){ && isFortified()){
val currentTurnsFortified = getFortificationTurns() val currentTurnsFortified = getFortificationTurns()
if(currentTurnsFortified<2) action = "Fortify ${currentTurnsFortified+1}" if(currentTurnsFortified<2)
action = action!!.replace(currentTurnsFortified.toString(),(currentTurnsFortified+1).toString(), true)
} }
} }
@ -418,6 +427,10 @@ class MapUnit {
|| getUniques().contains("Unit will heal every turn, even if it performs an action")){ || getUniques().contains("Unit will heal every turn, even if it performs an action")){
heal() heal()
} }
if(action != null && health > 99)
if (action!!.endsWith(" until healed")) {
action = null // wake up when healed
}
} }
fun startTurn(){ fun startTurn(){
@ -426,7 +439,7 @@ class MapUnit {
due = true due = true
// Wake sleeping units if there's an enemy nearby // Wake sleeping units if there's an enemy nearby
if(action==Constants.unitActionSleep && currentTile.getTilesInDistance(2).any { if(isSleeping() && currentTile.getTilesInDistance(2).any {
it.militaryUnit!=null && it.militaryUnit!!.civInfo.isAtWarWith(civInfo) it.militaryUnit!=null && it.militaryUnit!!.civInfo.isAtWarWith(civInfo)
}) })
action=null action=null

View File

@ -235,7 +235,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
unit.currentMovement -= distanceToTiles[destination]!!.totalDistance unit.currentMovement -= distanceToTiles[destination]!!.totalDistance
if (unit.currentMovement < 0.1) unit.currentMovement = 0f // silly floats which are "almost zero" if (unit.currentMovement < 0.1) unit.currentMovement = 0f // silly floats which are "almost zero"
if(unit.isFortified() || unit.action==Constants.unitActionSetUp || unit.action==Constants.unitActionSleep) if(unit.isFortified() || unit.action==Constants.unitActionSetUp || unit.isSleeping())
unit.action=null // unfortify/setup after moving unit.action=null // unfortify/setup after moving
// If this unit is a carrier, keep record of its air payload whereabouts. // If this unit is a carrier, keep record of its air payload whereabouts.

View File

@ -15,7 +15,9 @@ enum class UnitActionType(val value: String) {
StopAutomation("Stop automation"), StopAutomation("Stop automation"),
StopExploration("Stop exploration"), StopExploration("Stop exploration"),
Sleep("Sleep"), Sleep("Sleep"),
SleepUntilHealed("Sleep until healed"),
Fortify("Fortify"), Fortify("Fortify"),
FortifyUntilHealed("Fortify until healed"),
Explore("Explore"), Explore("Explore"),
Promote("Promote"), Promote("Promote"),
Upgrade("Upgrade"), Upgrade("Upgrade"),

View File

@ -16,7 +16,7 @@ class Translations : LinkedHashMap<String, TranslationEntry>(){
return get(text)!![language]!! return get(text)!![language]!!
} }
fun hasTranslation(text:String,language:String): Boolean { private fun hasTranslation(text:String,language:String): Boolean {
return containsKey(text) && get(text)!!.containsKey(language) return containsKey(text) && get(text)!!.containsKey(language)
} }

View File

@ -35,31 +35,18 @@ class UnitActions {
val workingOnImprovement = unit.hasUnique("Can build improvements on tiles") val workingOnImprovement = unit.hasUnique("Can build improvements on tiles")
&& unit.currentTile.hasImprovementInProgress() && unit.currentTile.hasImprovementInProgress()
if (!unit.isFortified() && (!unit.canFortify() || unit.health < 100) && unit.currentMovement > 0 if (!unit.isFortified() && !unit.canFortify()
&& !workingOnImprovement) { && unit.currentMovement > 0 && !workingOnImprovement) {
val isSleeping = unit.action == Constants.unitActionSleep addSleepActions(actionList, unit, unitTable)
actionList += UnitAction(
type = UnitActionType.Sleep,
canAct = !isSleeping,
isCurrentAction = isSleeping,
action = {
unit.action = Constants.unitActionSleep
unitTable.selectedUnit = null
})
} }
if (unit.canFortify()) { if (unit.canFortify()) {
actionList += UnitAction( addFortifyActions(actionList, unit, unitTable)
type = UnitActionType.Fortify,
canAct = unit.currentMovement > 0,
uncivSound = UncivSound.Fortify,
action = {
unit.fortify()
unitTable.selectedUnit = null
})
} else if (unit.isFortified()) { } else if (unit.isFortified()) {
actionList += UnitAction( actionList += UnitAction(
type = UnitActionType.Fortify, type = if (unit.action!!.endsWith(" until healed"))
UnitActionType.FortifyUntilHealed else
UnitActionType.Fortify,
canAct = false, canAct = false,
isCurrentAction = true, isCurrentAction = true,
title = "${"Fortification".tr()} ${unit.getFortificationTurns() * 20}%" title = "${"Fortification".tr()} ${unit.getFortificationTurns() * 20}%"
@ -320,6 +307,58 @@ class UnitActions {
return actionList return actionList
} }
private fun addFortifyActions(actionList: ArrayList<UnitAction>, unit: MapUnit, unitTable: UnitTable) {
val action = UnitAction(
type = UnitActionType.Fortify,
canAct = unit.currentMovement > 0,
uncivSound = UncivSound.Fortify,
action = {
unit.fortify()
unitTable.selectedUnit = null
})
if (unit.health < 100) {
val actionForWounded = action.copy(
type = UnitActionType.FortifyUntilHealed,
title = UnitActionType.FortifyUntilHealed.value,
action = {
unit.fortifyUntilHealed()
unitTable.selectedUnit = null
})
actionList += actionForWounded
}
actionList += action
}
private fun addSleepActions(actionList: ArrayList<UnitAction>, unit: MapUnit, unitTable: UnitTable) {
val isSleeping = unit.isSleeping()
val action = UnitAction(
type = UnitActionType.Sleep,
canAct = !isSleeping,
isCurrentAction = isSleeping,
action = {
unit.action = Constants.unitActionSleep
unitTable.selectedUnit = null
})
if (unit.health < 100 && !isSleeping) {
val actionForWounded = action.copy(
type = UnitActionType.SleepUntilHealed,
title = UnitActionType.SleepUntilHealed.value,
action = {
unit.action = Constants.unitActionSleepUntilHealed
unitTable.selectedUnit = null
})
actionList += actionForWounded
}
actionList += action
}
fun canPillage(unit: MapUnit, tile: TileInfo): Boolean { fun canPillage(unit: MapUnit, tile: TileInfo): Boolean {
if (tile.improvement == null || tile.improvement == Constants.barbarianEncampment if (tile.improvement == null || tile.improvement == Constants.barbarianEncampment
|| tile.improvement == Constants.ancientRuins || tile.improvement == Constants.ancientRuins

View File

@ -18,17 +18,19 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
touchable = Touchable.enabled touchable = Touchable.enabled
} }
fun getIconForUnitAction(unitAction:String): Actor { private fun getIconForUnitAction(unitAction:String): Actor {
if(unitAction.startsWith("Upgrade to")){ when {
unitAction.startsWith("Upgrade to") -> {
// Regexplaination: start with a [, take as many non-] chars as you can, until you reach a ]. // 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 // 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 val unitToUpgradeTo = Regex("""Upgrade to \[([^\]]*)\]""").find(unitAction)!!.groups[1]!!.value
return ImageGetter.getUnitIcon(unitToUpgradeTo) return ImageGetter.getUnitIcon(unitToUpgradeTo)
} }
when(unitAction){ unitAction.startsWith("Sleep") -> return ImageGetter.getImage("OtherIcons/Sleep")
unitAction.startsWith("Fortify") -> return ImageGetter.getImage("OtherIcons/Shield").apply { color= Color.BLACK }
else -> when(unitAction){
"Move unit" -> return ImageGetter.getStatIcon("Movement") "Move unit" -> return ImageGetter.getStatIcon("Movement")
"Stop movement"-> return ImageGetter.getStatIcon("Movement").apply { color= Color.RED } "Stop movement"-> return ImageGetter.getStatIcon("Movement").apply { color= Color.RED }
"Fortify" -> return ImageGetter.getImage("OtherIcons/Shield").apply { color= Color.BLACK }
"Promote" -> return ImageGetter.getImage("OtherIcons/Star").apply { color= Color.GOLD } "Promote" -> return ImageGetter.getImage("OtherIcons/Star").apply { color= Color.GOLD }
"Construct improvement" -> return ImageGetter.getUnitIcon(Constants.worker) "Construct improvement" -> return ImageGetter.getUnitIcon(Constants.worker)
"Automate" -> return ImageGetter.getUnitIcon("Great Engineer") "Automate" -> return ImageGetter.getUnitIcon("Great Engineer")
@ -44,7 +46,6 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
"Construct Customs House" -> return ImageGetter.getImprovementIcon("Customs house") "Construct Customs House" -> return ImageGetter.getImprovementIcon("Customs house")
"Set up" -> return ImageGetter.getUnitIcon("Catapult") "Set up" -> return ImageGetter.getUnitIcon("Catapult")
"Disband unit" -> return ImageGetter.getImage("OtherIcons/DisbandUnit") "Disband unit" -> return ImageGetter.getImage("OtherIcons/DisbandUnit")
"Sleep" -> return ImageGetter.getImage("OtherIcons/Sleep")
"Explore" -> return ImageGetter.getUnitIcon("Scout") "Explore" -> return ImageGetter.getUnitIcon("Scout")
"Stop exploration" -> return ImageGetter.getImage("OtherIcons/Stop") "Stop exploration" -> return ImageGetter.getImage("OtherIcons/Stop")
"Create Fishing Boats" -> return ImageGetter.getImprovementIcon("Fishing Boats") "Create Fishing Boats" -> return ImageGetter.getImprovementIcon("Fishing Boats")
@ -54,6 +55,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
else -> return ImageGetter.getImage("OtherIcons/Star") else -> return ImageGetter.getImage("OtherIcons/Star")
} }
} }
}
fun update(unit: MapUnit?){ fun update(unit: MapUnit?){
clear() clear()

View File

@ -4,6 +4,7 @@ package com.unciv.testing
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.Array
import com.unciv.JsonParser import com.unciv.JsonParser
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.Nation import com.unciv.models.ruleset.Nation
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
@ -52,6 +53,20 @@ class TranslationTests {
allStringsHaveTranslation) allStringsHaveTranslation)
} }
@Test
fun allUnitActionsHaveTranslation() {
val actions: MutableSet<String> = HashSet()
for (action in UnitActionType.values()) {
if (action == UnitActionType.Upgrade)
actions.add("Upgrade to [unitType] ([goldCost] gold)")
else
actions.add(action.value)
}
val allUnitActionsHaveTranslation = allStringAreTranslated(actions)
Assert.assertTrue("This test will only pass when there is a translation for all unit actions",
allUnitActionsHaveTranslation)
}
@Test @Test
fun allBuildingsHaveTranslation() { fun allBuildingsHaveTranslation() {
val allBuildingsHaveTranslation = allStringAreTranslated(ruleset.buildings.keys) val allBuildingsHaveTranslation = allStringAreTranslated(ruleset.buildings.keys)