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()
}
}
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(
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 -> {
if (Random.nextBoolean())
impact(1)
else
- ImpactResult.Damaged(this)
+ ImpactResult.Damaged(this, amount = 0)
} else
impact(2)
}
copy(
weaponAmount = (0..weaponAmount).random(),
shieldAmount = (0..shieldAmount).random(),
- )
+ ),
+ amount = 0
)
}
}
}.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)
+ )
+ }
}
}
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)
+"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)
}
+" 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