Add ship damage notifications
authorTheSaminator <TheSaminator@users.noreply.github.com>
Sat, 5 Mar 2022 00:33:18 +0000 (19:33 -0500)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Sat, 5 Mar 2022 00:33:18 +0000 (19:33 -0500)
src/commonMain/kotlin/starshipfights/game/game_chat.kt
src/commonMain/kotlin/starshipfights/game/game_state.kt
src/commonMain/kotlin/starshipfights/game/ship_weapons.kt
src/jsMain/kotlin/starshipfights/game/game_ui.kt

index c5a720bd59b9cca33266b41321f24835080b6a0e..42c575a0addb91e6944feb8bd8704c0c6d99fce1 100644 (file)
@@ -26,19 +26,28 @@ sealed class ChatEntry {
                override val sentAt: Moment
        ) : ChatEntry()
        
+       @Serializable
+       data class ShipAttacked(
+               val ship: Id<ShipInstance>,
+               val attacker: ShipAttacker,
+               override val sentAt: Moment,
+               val damageInflicted: Int,
+               val weapon: ShipWeapon?,
+       ) : ChatEntry()
+       
        @Serializable
        data class ShipDestroyed(
                val ship: Id<ShipInstance>,
                override val sentAt: Moment,
-               val destroyedBy: ShipDestructionType
+               val destroyedBy: ShipAttacker
        ) : ChatEntry()
 }
 
 @Serializable
-sealed class ShipDestructionType {
+sealed class ShipAttacker {
        @Serializable
-       data class EnemyShip(val id: Id<ShipInstance>) : ShipDestructionType()
+       data class EnemyShip(val id: Id<ShipInstance>) : ShipAttacker()
        
        @Serializable
-       object Bombers : ShipDestructionType()
+       object Bombers : ShipAttacker()
 }
index 154abeb9e5ca66d79a7b99256b2e078e9aeaca13..167a1ef4b44d93561abe216280d7da500556e422 100644 (file)
@@ -98,7 +98,7 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide
                                        is ImpactResult.Damaged -> id to impactResult.ship
                                        is ImpactResult.Destroyed -> {
                                                newWrecks[id] = impactResult.ship
-                                               newChatEntries += ChatEntry.ShipDestroyed(id, Moment.now, ShipDestructionType.Bombers)
+                                               newChatEntries += ChatEntry.ShipDestroyed(id, Moment.now, ShipAttacker.Bombers)
                                                null
                                        }
                                }
@@ -179,7 +179,13 @@ enum class GlobalSide {
 fun GlobalSide.relativeTo(me: GlobalSide) = if (this == me) LocalSide.BLUE else LocalSide.RED
 
 enum class LocalSide {
-       BLUE, RED
+       BLUE, RED;
+       
+       val other: LocalSide
+               get() = when (this) {
+                       BLUE -> RED
+                       RED -> BLUE
+               }
 }
 
 val LocalSide.htmlColor: String
index a45c14d368481e6be8bbf3132c2ff90c97a597ec..b23df0d7e87723e25cb51f02a13bf68dc01c22cb 100644 (file)
@@ -247,15 +247,15 @@ fun cannonChanceToHit(attacker: ShipInstance, targeted: ShipInstance): Double {
 }
 
 sealed class ImpactResult {
-       data class Damaged(val ship: ShipInstance) : ImpactResult()
+       data class Damaged(val ship: ShipInstance, val amount: Int?) : ImpactResult()
        data class Destroyed(val ship: ShipWreck) : ImpactResult()
 }
 
 fun ShipInstance.impact(damage: Int) = if (damage > shieldAmount) {
        if (damage - shieldAmount >= hullAmount)
                ImpactResult.Destroyed(ShipWreck(ship, owner))
-       else ImpactResult.Damaged(copy(shieldAmount = 0, hullAmount = hullAmount - (damage - shieldAmount)))
-} else ImpactResult.Damaged(copy(shieldAmount = shieldAmount - damage))
+       else ImpactResult.Damaged(copy(shieldAmount = 0, hullAmount = hullAmount - (damage - shieldAmount)), amount = damage)
+} else ImpactResult.Damaged(copy(shieldAmount = shieldAmount - damage), amount = damage)
 
 @Serializable
 data class ShipHangarWing(
@@ -324,7 +324,8 @@ fun ShipInstance.afterTargeted(by: ShipInstance, weaponId: Id<ShipWeapon>) = whe
                        if (weapon.weapon.wing == StrikeCraftWing.FIGHTERS)
                                copy(fighterWings = fighterWings + setOf(ShipHangarWing(by.id, weaponId)))
                        else
-                               copy(bomberWings = bomberWings + setOf(ShipHangarWing(by.id, weaponId)))
+                               copy(bomberWings = bomberWings + setOf(ShipHangarWing(by.id, weaponId))),
+                       amount = 0
                )
        }
        is ShipWeaponInstance.Torpedo -> {
@@ -332,7 +333,7 @@ fun ShipInstance.afterTargeted(by: ShipInstance, weaponId: Id<ShipWeapon>) = whe
                        if (Random.nextBoolean())
                                impact(1)
                        else
-                               ImpactResult.Damaged(this)
+                               ImpactResult.Damaged(this, amount = 0)
                } else
                        impact(2)
        }
@@ -347,7 +348,8 @@ fun ShipInstance.afterTargeted(by: ShipInstance, weaponId: Id<ShipWeapon>) = whe
                        copy(
                                weaponAmount = (0..weaponAmount).random(),
                                shieldAmount = (0..shieldAmount).random(),
-                       )
+                       ),
+                       amount = 0
                )
        }
 }
@@ -430,8 +432,23 @@ fun GameState.useWeaponPickResponse(attacker: ShipInstance, weaponId: Id<ShipWea
                        }.toMap()
                        
                        val newChatMessages = chatBox + impacts.mapNotNull { (_, impact) ->
-                               (impact as? ImpactResult.Destroyed)?.ship?.let {
-                                       ChatEntry.ShipDestroyed(it.id, Moment.now, ShipDestructionType.EnemyShip(newAttacker.id))
+                               when (impact) {
+                                       is ImpactResult.Damaged -> impact.amount?.let { damage ->
+                                               ChatEntry.ShipAttacked(
+                                                       impact.ship.id,
+                                                       ShipAttacker.EnemyShip(newAttacker.id),
+                                                       Moment.now,
+                                                       damage,
+                                                       weapon.weapon,
+                                               )
+                                       }
+                                       is ImpactResult.Destroyed -> {
+                                               ChatEntry.ShipDestroyed(
+                                                       impact.ship.id,
+                                                       Moment.now,
+                                                       ShipAttacker.EnemyShip(newAttacker.id)
+                                               )
+                                       }
                                }
                        }
                        
@@ -443,20 +460,35 @@ fun GameState.useWeaponPickResponse(attacker: ShipInstance, weaponId: Id<ShipWea
                        val targetedShipId = (target as? PickResponse.Ship)?.id ?: return GameEvent.InvalidAction("Invalid pick response type")
                        val targetedShip = ships[targetedShipId] ?: return GameEvent.InvalidAction("That ship does not exist")
                        
-                       val newTarget = targetedShip.afterTargeted(attacker, weaponId)
+                       val impact = targetedShip.afterTargeted(attacker, weaponId)
                        val newAttacker = attacker.afterUsing(weaponId)
                        
-                       val newShips = (if (newTarget is ImpactResult.Damaged)
-                               ships + mapOf(targetedShipId to newTarget.ship)
+                       val newShips = (if (impact is ImpactResult.Damaged)
+                               ships + mapOf(targetedShipId to impact.ship)
                        else ships - targetedShipId) + mapOf(attacker.id to newAttacker)
                        
-                       val newWrecks = destroyedShips + if (newTarget is ImpactResult.Destroyed)
-                               mapOf(targetedShipId to newTarget.ship)
+                       val newWrecks = destroyedShips + if (impact is ImpactResult.Destroyed)
+                               mapOf(targetedShipId to impact.ship)
                        else emptyMap()
                        
-                       val newChatMessages = chatBox + if (newTarget is ImpactResult.Destroyed)
-                               listOf(ChatEntry.ShipDestroyed(newTarget.ship.id, Moment.now, ShipDestructionType.EnemyShip(newAttacker.id)))
-                       else emptyList()
+                       val newChatMessages = chatBox + listOfNotNull(
+                               when (impact) {
+                                       is ImpactResult.Destroyed -> ChatEntry.ShipDestroyed(
+                                               impact.ship.id,
+                                               Moment.now,
+                                               ShipAttacker.EnemyShip(newAttacker.id)
+                                       )
+                                       is ImpactResult.Damaged -> impact.amount?.let { damage ->
+                                               ChatEntry.ShipAttacked(
+                                                       impact.ship.id,
+                                                       ShipAttacker.EnemyShip(newAttacker.id),
+                                                       Moment.now,
+                                                       damage,
+                                                       weapon.weapon,
+                                               )
+                                       }
+                               }
+                       )
                        
                        GameEvent.StateChange(
                                copy(ships = newShips, destroyedShips = newWrecks, chatBox = newChatMessages)
index 3264aad0ca3fcef38f655cf6b35a4f8bd6752f8f..34fe5f4ab71ed5ec3f00d0892ad94f2bee30e235 100644 (file)
@@ -202,6 +202,55 @@ object GameUI {
                                                                +"disengaged from"
                                                        +" the battlefield!"
                                                }
+                                               is ChatEntry.ShipAttacked -> {
+                                                       val ship = state.getShipInfo(entry.ship)
+                                                       val owner = state.getShipOwner(entry.ship).relativeTo(mySide)
+                                                       +"The "
+                                                       if (owner == LocalSide.RED)
+                                                               +"enemy ship "
+                                                       strong {
+                                                               style = "color:${owner.htmlColor}"
+                                                               +ship.fullName
+                                                       }
+                                                       +" has taken "
+                                                       
+                                                       if (entry.weapon is ShipWeapon.EmpAntenna)
+                                                               +"subsystem-disabling"
+                                                       else
+                                                               +entry.damageInflicted.toString()
+                                                       
+                                                       +" damage from "
+                                                       when (entry.attacker) {
+                                                               ShipAttacker.Bombers -> {
+                                                                       if (owner == LocalSide.RED)
+                                                                               +"our "
+                                                                       else
+                                                                               +"enemy "
+                                                                       +"bombers"
+                                                               }
+                                                               is ShipAttacker.EnemyShip -> {
+                                                                       if (entry.weapon != null) {
+                                                                               +"the "
+                                                                               when (entry.weapon) {
+                                                                                       is ShipWeapon.Cannon -> +"cannons"
+                                                                                       is ShipWeapon.Lance -> +"lances"
+                                                                                       is ShipWeapon.Hangar -> +"bombers"
+                                                                                       is ShipWeapon.Torpedo -> +"torpedoes"
+                                                                                       ShipWeapon.MegaCannon -> +"Mega Giga Cannon"
+                                                                                       ShipWeapon.RevelationGun -> +"Revelation Gun"
+                                                                                       ShipWeapon.EmpAntenna -> +"EMP antenna"
+                                                                               }
+                                                                               +" of "
+                                                                       }
+                                                                       +"the "
+                                                                       span {
+                                                                               style = "color:${owner.other.htmlColor}"
+                                                                               +state.getShipInfo(entry.attacker.id).fullName
+                                                                       }
+                                                               }
+                                                       }
+                                                       +"."
+                                               }
                                                is ChatEntry.ShipDestroyed -> {
                                                        val ship = state.getShipInfo(entry.ship)
                                                        val owner = state.getShipOwner(entry.ship).relativeTo(mySide)
@@ -215,14 +264,14 @@ object GameUI {
                                                        }
                                                        +" has been destroyed by "
                                                        when (entry.destroyedBy) {
-                                                               is ShipDestructionType.EnemyShip -> {
+                                                               is ShipAttacker.EnemyShip -> {
                                                                        +"the "
                                                                        span {
-                                                                               style = "color:${state.getShipOwner(entry.destroyedBy.id).relativeTo(mySide).htmlColor}"
+                                                                               style = "color:${owner.other.htmlColor}"
                                                                                +state.getShipInfo(entry.destroyedBy.id).fullName
                                                                        }
                                                                }
-                                                               ShipDestructionType.Bombers -> {
+                                                               ShipAttacker.Bombers -> {
                                                                        if (owner == LocalSide.RED)
                                                                                +"our "
                                                                        else