From df45ae0645371efcb28f0b5182adfbd0c50379bd Mon Sep 17 00:00:00 2001 From: TheSaminator Date: Fri, 4 Mar 2022 19:33:18 -0500 Subject: [PATCH] Add ship damage notifications --- .../kotlin/starshipfights/game/game_chat.kt | 17 +++-- .../kotlin/starshipfights/game/game_state.kt | 10 ++- .../starshipfights/game/ship_weapons.kt | 64 ++++++++++++++----- .../kotlin/starshipfights/game/game_ui.kt | 55 +++++++++++++++- 4 files changed, 121 insertions(+), 25 deletions(-) diff --git a/src/commonMain/kotlin/starshipfights/game/game_chat.kt b/src/commonMain/kotlin/starshipfights/game/game_chat.kt index c5a720b..42c575a 100644 --- a/src/commonMain/kotlin/starshipfights/game/game_chat.kt +++ b/src/commonMain/kotlin/starshipfights/game/game_chat.kt @@ -26,19 +26,28 @@ sealed class ChatEntry { override val sentAt: Moment ) : ChatEntry() + @Serializable + data class ShipAttacked( + val ship: Id, + val attacker: ShipAttacker, + override val sentAt: Moment, + val damageInflicted: Int, + val weapon: ShipWeapon?, + ) : ChatEntry() + @Serializable data class ShipDestroyed( val ship: Id, 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) : ShipDestructionType() + data class EnemyShip(val id: Id) : ShipAttacker() @Serializable - object Bombers : ShipDestructionType() + object Bombers : ShipAttacker() } diff --git a/src/commonMain/kotlin/starshipfights/game/game_state.kt b/src/commonMain/kotlin/starshipfights/game/game_state.kt index 154abeb..167a1ef 100644 --- a/src/commonMain/kotlin/starshipfights/game/game_state.kt +++ b/src/commonMain/kotlin/starshipfights/game/game_state.kt @@ -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 diff --git a/src/commonMain/kotlin/starshipfights/game/ship_weapons.kt b/src/commonMain/kotlin/starshipfights/game/ship_weapons.kt index a45c14d..b23df0d 100644 --- a/src/commonMain/kotlin/starshipfights/game/ship_weapons.kt +++ b/src/commonMain/kotlin/starshipfights/game/ship_weapons.kt @@ -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) = 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) = 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) = whe copy( weaponAmount = (0..weaponAmount).random(), shieldAmount = (0..shieldAmount).random(), - ) + ), + amount = 0 ) } } @@ -430,8 +432,23 @@ fun GameState.useWeaponPickResponse(attacker: ShipInstance, weaponId: Id - (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 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) diff --git a/src/jsMain/kotlin/starshipfights/game/game_ui.kt b/src/jsMain/kotlin/starshipfights/game/game_ui.kt index 3264aad..34fe5f4 100644 --- a/src/jsMain/kotlin/starshipfights/game/game_ui.kt +++ b/src/jsMain/kotlin/starshipfights/game/game_ui.kt @@ -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 -- 2.25.1