From 1441dd49f546f1e1ed39629e4950d5b374e94481 Mon Sep 17 00:00:00 2001 From: JackRainy Date: Mon, 20 Jan 2020 22:53:59 +0200 Subject: [PATCH] Aircraft carrier is added (#1731) * Implemented aircraft carrier by @ltrcao in PR #1723 * New icon for the Carrier unit --- android/Images/UnitIcons/Carrier.png | Bin 0 -> 2258 bytes android/assets/jsons/Units.json | 10 ++++++ .../translationsByLanguage/English.properties | 2 ++ .../template.properties | 1 + .../automation/SpecificUnitAutomation.kt | 4 +++ core/src/com/unciv/logic/map/MapUnit.kt | 3 ++ .../unciv/logic/map/UnitMovementAlgorithms.kt | 25 +++++++++++++- .../com/unciv/models/ruleset/unit/UnitType.kt | 12 +++++++ .../com/unciv/ui/tilegroups/TileGroupIcons.kt | 23 +++++++++++-- .../unciv/ui/worldscreen/WorldMapHolder.kt | 31 +++++++++++------- docs/Credits.md | 1 + 11 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 android/Images/UnitIcons/Carrier.png diff --git a/android/Images/UnitIcons/Carrier.png b/android/Images/UnitIcons/Carrier.png new file mode 100644 index 0000000000000000000000000000000000000000..8b08dc95d67078db82653a919435bc8e1fb7d9e0 GIT binary patch literal 2258 zcmai0c{~%08(+O?na%1|(%k8qdl`~S%r&8P*o?D6w2pgg`=n}>z3y>c_ zS;4kKPeN`rWl)-@&?uCNudnYV8r}6MBvtuU(88UA6)Z~bU(S&VrA6t-M_;&Q#ng?f zbKd;$!N6dS)kne-pQJ*4rzyw^PESvd_Zg|X{_hz{SsA9Pp_`u4(UX+ri~o$sj4a7l-^dF)n+QhZD71=N2RMxb* zRj5DrVHAYM;R#p2db^b=_lfX-R7;DbDhrFQ)-{K${0-8qP1}!u(I$&sEvR12HPO#Y z+DRU5L7bT2simkOq_()hYZYc}Z0zO-E#}$Swu}7((6$nF&<Hwz+-=*LDk!+lX9F+ zVsuW!Vnhw_CiRXv=#lqSKED;XpL4y8C5fsCf;WC(k>>+$H4Q19Z~Df!wx% z@N*gY)p2%<%Us1WBW8I*p7gkS(Bd{ELYUi8821ow^%~}VK9YatPRBq?IpgN0;+@Ie z;lQ3VE>E_hbe0S-)u)NUNGV3t20U&M`*PQ@{TbJ*VMWJ#xV@u~#X`6Js2X0Dy;kBF zoEHfiCbgp2;X)i|&Zm9bx*bF6C?$t!MWw1VKjY>u5=&lsW^|#`DBQWnAtK6l zHYg+gnrJTk7|iD!`3DlDv3&OQJDZPGVeM-PjTx7>Zdse6QvCy*^+(fJ9wr}FD^C0( zdw(3Q^F1B6EEU=g8n(P!8NAz*HC5{QFb6s8{oRf9WgZP*z6rkHOS67+Wkzz{gC`LY zct$ERv2~8f=R+%IZ}E=eIqDe{GnOf<&q?AhQjp~@g)rQufzF#Neg*kk2QN1 zQ`qkUvnL=E4jGKvnNY5%t$}s!@`X#V36S-E-c165(9p`TPIok8Dmv#@7jk+uDZ?tt z${*V)kx;#-#%8BUJKDzSYjf_Y@3ZV)ujZPe;un!Q|9-K2+1SWaoM^Wy#Phb*_)^@w zf`U|6<|!=6@^O(tFnF<+?dg=j$b={#P8nk~ODXL{0Y8gAXNWzCdZ+n-0-B7eG_SNi z)&z|NEb!#ri8=c+@+2=%zC4Rt)Ve(C+=^0EdDgXH|8GK}i*HteoVHzgXxuV$HP4KB z|EX1h!5}Q8z=`ZY#*iJF!`@uKl%;f0w`H;RR%E0<$?4|ZUQlT->KOyOj@RM zymxULEC~{g52!1EoWzVj$LeLw zQEz43*%rXb5qE;a8C~7v;!Y4t`VcT>l-+S&!!+x<+XKWuSaoWQs#uf4h0S$B#+o1c;^>2Wl%k12dtQHH z7xq(xV7IHq)_tvu+jN6N6nwC~mZqwKgP|=SFb#I@;Rt>Y^jm~3(fP)F*MWm426i-u zsAW>bK@W2G(mA5Z25!?r*8Z&@h=WmqFp#Set{y#UH`Myeu#fMI6&#vrQWZ4M* O4*=T8%CO1+8}lCx7F)dl literal 0 HcmV?d00001 diff --git a/android/assets/jsons/Units.json b/android/assets/jsons/Units.json index a361693b..8148d616 100644 --- a/android/assets/jsons/Units.json +++ b/android/assets/jsons/Units.json @@ -856,6 +856,16 @@ "hurryCostModifier": 20, "attackSound": "shot" }, + { + "name": "Carrier", + "unitType": "WaterAircraftCarrier", + "movement": 5, + "strength": 40, + "cost": 375, + "requiredTech": "Electronics", + "uniques": ["Can carry 2 aircraft"], + "hurryCostModifier": 20 + }, { "name": "Triplane", "unitType": "Fighter", diff --git a/android/assets/jsons/translationsByLanguage/English.properties b/android/assets/jsons/translationsByLanguage/English.properties index ff8c48e4..3766ce82 100644 --- a/android/assets/jsons/translationsByLanguage/English.properties +++ b/android/assets/jsons/translationsByLanguage/English.properties @@ -3050,6 +3050,8 @@ Ambush I = # Requires translation! Ambush II = # Requires translation! +Can carry 2 aircraft = Can carry 2 aircraft + # Requires translation! Haka War Dance = # Requires translation! -10% combat strength for adjacent enemy units = diff --git a/android/assets/jsons/translationsByLanguage/template.properties b/android/assets/jsons/translationsByLanguage/template.properties index 92d92a5a..7fd26873 100644 --- a/android/assets/jsons/translationsByLanguage/template.properties +++ b/android/assets/jsons/translationsByLanguage/template.properties @@ -1657,6 +1657,7 @@ Reduces damage taken from interception by 50% = Bonus when intercepting [amount]% = Ambush I = Ambush II = +Can carry 2 aircraft = Haka War Dance = -10% combat strength for adjacent enemy units = Rejuvenation = diff --git a/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt b/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt index 2ba6a238..0adc86a6 100644 --- a/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt @@ -190,6 +190,8 @@ class SpecificUnitAutomation{ if(enemyAirUnitsInRange.isNotEmpty()) return // we need to be on standby in case they attack if(battleHelper.tryAttackNearbyEnemy(unit)) return + // TODO Implement consideration for landing on aircraft carrier + val immediatelyReachableCities = tilesInRange .filter { it.isCityCenter() && it.getOwner()==unit.civInfo && unit.movement.canMoveTo(it)} @@ -226,6 +228,8 @@ class SpecificUnitAutomation{ val tilesInRange = unit.currentTile.getTilesInDistance(unit.getRange()) + // TODO Implement consideration for landing on aircraft carrier + val immediatelyReachableCities = tilesInRange .filter { it.isCityCenter() && it.getOwner() == unit.civInfo && unit.movement.canMoveTo(it) } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 129b1504..e4320d55 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -63,6 +63,7 @@ class MapUnit { var attacksThisTurn = 0 var promotions = UnitPromotions() var due: Boolean = true + var isUnitInCity: Boolean = true companion object { private const val ANCIENT_RUIN_MAP_REVEAL_OFFSET = 4 @@ -80,6 +81,7 @@ class MapUnit { toReturn.action=action toReturn.attacksThisTurn=attacksThisTurn toReturn.promotions=promotions.clone() + toReturn.isUnitInCity=isUnitInCity return toReturn } @@ -461,6 +463,7 @@ class MapUnit { type.isCivilian() -> tile.civilianUnit=this else -> tile.militaryUnit=this } + isUnitInCity = tile.isCityCenter() // prevent carriers from sailing away with air units explicitly assigned to city moveThroughTile(tile) } diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index a66a8c58..c4421bb6 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -237,9 +237,20 @@ class UnitMovementAlgorithms(val unit:MapUnit) { if(unit.isFortified() || unit.action==Constants.unitActionSetUp || unit.action==Constants.unitActionSleep) unit.action=null // unfortify/setup after moving + // If this unit is a carrier, keep record of its air payload whereabouts. + var origin = unit.getTile() + unit.removeFromTile() unit.putInTile(destination) + if(unit.type.isAircraftCarrierUnit() || unit.type.isMissileCarrierUnit()){ // bring along the payloads + for(airUnit in origin.airUnits.filter { !it.isUnitInCity }){ + airUnit.removeFromTile() + airUnit.putInTile(destination) + airUnit.isUnitInCity = false // don't leave behind payloads in the city if carrier happens to dock + } + } + // Move through all intermediate tiles to get ancient ruins, barb encampments // and to view tiles along the way // We only activate the moveThroughTile AFTER the putInTile because of a really weird bug - @@ -260,7 +271,19 @@ class UnitMovementAlgorithms(val unit:MapUnit) { */ fun canMoveTo(tile: TileInfo): Boolean { if(unit.type.isAirUnit()) - return tile.airUnits.size<6 && tile.isCityCenter() && tile.getCity()?.civInfo==unit.civInfo + if(tile.isCityCenter()) + return tile.airUnits.size<6 && tile.getCity()?.civInfo==unit.civInfo + else if(tile.militaryUnit!=null) { + val unitAtDestination = tile.militaryUnit!! + + var unitCapacity = if (unitAtDestination.getUniques().contains("Can carry 2 aircraft")) 2 else 0 + // unitCapacity += unitAtDestination.getUniques().count { it == "Can carry 1 extra air unit" } + + return ((unitAtDestination.type.isAircraftCarrierUnit() && !unit.type.isMissileUnit()) || + (unitAtDestination.type.isMissileCarrierUnit() && unit.type.isMissileUnit())) + && unitAtDestination.owner==unit.owner && tile.airUnits.size < unitCapacity + } else + return false if(!canPassThrough(tile)) return false diff --git a/core/src/com/unciv/models/ruleset/unit/UnitType.kt b/core/src/com/unciv/models/ruleset/unit/UnitType.kt index e8713694..3818a538 100644 --- a/core/src/com/unciv/models/ruleset/unit/UnitType.kt +++ b/core/src/com/unciv/models/ruleset/unit/UnitType.kt @@ -14,6 +14,8 @@ enum class UnitType{ WaterMelee, WaterRanged, WaterSubmarine, + WaterAircraftCarrier, + WaterMissileCarrier, Fighter, Bomber, @@ -60,6 +62,8 @@ enum class UnitType{ || this==WaterRanged || this==WaterMelee || this==WaterCivilian + || this==WaterAircraftCarrier + || this==WaterMissileCarrier } fun isAirUnit():Boolean{ @@ -71,4 +75,12 @@ enum class UnitType{ fun isMissileUnit():Boolean{ return this == Missile } + + fun isAircraftCarrierUnit():Boolean{ + return this == WaterAircraftCarrier + } + + fun isMissileCarrierUnit():Boolean{ + return this == WaterMissileCarrier + } } \ No newline at end of file diff --git a/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt b/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt index 79ec28f0..06190e10 100644 --- a/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt +++ b/core/src/com/unciv/ui/tilegroups/TileGroupIcons.kt @@ -3,11 +3,11 @@ package com.unciv.ui.tilegroups import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.ui.Image +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.logic.map.MapUnit -import com.unciv.ui.utils.ImageGetter -import com.unciv.ui.utils.UnitGroup -import com.unciv.ui.utils.center +import com.unciv.ui.utils.* /** Helper class for TileGroup, which was getting too full */ class TileGroupIcons(val tileGroup: TileGroup){ @@ -58,6 +58,23 @@ class TileGroupIcons(val tileGroup: TileGroup){ newImage.center(tileGroup) newImage.y += yFromCenter + // Display number of carried air units + if ((unit.type.isAircraftCarrierUnit() || unit.type.isMissileCarrierUnit()) + && !unit.getTile().airUnits.isEmpty() && !unit.getTile().isCityCenter()) { + val holder = Table() + val secondarycolor = unit.civInfo.nation.getInnerColor() + val airUnitTable = Table().apply { defaults().pad(5f) } + airUnitTable.background = ImageGetter.getRoundedEdgeTableBackground(unit.civInfo.nation.getOuterColor()) + val aircraftImage = ImageGetter.getImage("OtherIcons/Aircraft") + aircraftImage.color = secondarycolor + airUnitTable.add(aircraftImage).size(15f) + airUnitTable.add(unit.getTile().airUnits.size.toString().toLabel(secondarycolor, 14)) + holder.add(airUnitTable).row() + holder.setOrigin(Align.center) + holder.center(tileGroup) + newImage.addActor(holder) + } + // Instead of fading out the entire unit with its background, we just fade out its central icon, // that way it remains much more visible on the map if (!unit.isIdle() && unit.civInfo == UncivGame.Current.worldScreen.viewingCiv) diff --git a/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt b/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt index 0bb77ed3..18d38acf 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldMapHolder.kt @@ -125,20 +125,27 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap if(moveHereDto!=null) table.add(getMoveHereButton(moveHereDto)) + var unitList = ArrayList() if (tileInfo.isCityCenter() && tileInfo.getOwner()==worldScreen.viewingCiv) { - for (unit in tileInfo.getCity()!!.getCenterTile().getUnits()) { - val unitGroup = UnitGroup(unit, 60f).surroundWithCircle(80f) - unitGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f } - if (unit.currentMovement == 0f) unitGroup.color.a = 0.5f - unitGroup.touchable = Touchable.enabled - unitGroup.onClick { - worldScreen.bottomUnitTable.selectedUnit = unit - worldScreen.bottomUnitTable.selectedCity = null - worldScreen.shouldUpdate = true - unitActionOverlay?.remove() - } - table.add(unitGroup) + unitList.addAll(tileInfo.getCity()!!.getCenterTile().getUnits()) + } else if (tileInfo.militaryUnit!=null && + (tileInfo.militaryUnit!!.type.isAircraftCarrierUnit() || tileInfo.militaryUnit!!.type.isMissileCarrierUnit()) && + tileInfo.militaryUnit!!.civInfo==worldScreen.viewingCiv && !tileInfo.airUnits.isEmpty()) { + unitList.addAll(tileInfo.getUnits()) + } + + for (unit in unitList) { + val unitGroup = UnitGroup(unit, 60f).surroundWithCircle(80f) + unitGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f } + if (unit.currentMovement == 0f) unitGroup.color.a = 0.5f + unitGroup.touchable = Touchable.enabled + unitGroup.onClick { + worldScreen.bottomUnitTable.selectedUnit = unit + worldScreen.bottomUnitTable.selectedCity = null + worldScreen.shouldUpdate = true + unitActionOverlay?.remove() } + table.add(unitGroup) } addOverlayOnTileGroup(tileInfo, table) diff --git a/docs/Credits.md b/docs/Credits.md index 163f1afc..5eb732b4 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -99,6 +99,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https: * [Modern Armor](https://thenounproject.com/search/?q=tank&i=218) By Public Domain Nouns for Modern Armor * [Manhattan Project](https://thenounproject.com/search/?q=Nuclear%20Bomb&i=2041074) By corpus delicti, GR * [Nuclear Missile](https://thenounproject.com/marialuisa.iborra/collection/missiles-bombs/?i=1022574) By Lluisa Iborra, ES +* Icon for Carrier made by [JackRainy](https://github.com/JackRainy), based on [Aircraft Carrier](https://thenounproject.com/icolabs/collection/flat-icons-transport/?i=2332914) By IcoLabs, BR ### Great People