From: TheSaminator Date: Wed, 9 Feb 2022 18:10:12 +0000 (-0500) Subject: Rename Emitter power and rework shield regeneration X-Git-Url: https://gitweb.starshipfights.net/?a=commitdiff_plain;h=b8eaacfa17a571ea099506acd6b8f76a4d9520f7;p=starship-fights Rename Emitter power and rework shield regeneration --- diff --git a/plan/mechanics.md b/plan/mechanics.md deleted file mode 100644 index e5f95b8..0000000 --- a/plan/mechanics.md +++ /dev/null @@ -1,74 +0,0 @@ -# Starship Fights - -## Phases of Battle - -Each turn consists of several phases. Each player takes their turn simultaneously. - -### Power Phase - -Distribute power among the ship's subsystems: - -* Weapons - Used to attack other ships -* Shields - Used to defend against attacks -* Impulse - Used to move around in space -* Emitter - Used for special abilities - -Power starts off as being evenly split between all four subsystems. The ship's Grid Efficiency -is how many Power Output (PO) points can be transferred between subsystems in any given Power Phase. Once the -phase ends, the power distribution stays like it is until it is modified again, i.e. it never automatically -resets back to the default evenly-shared distribution. - -Different ship tiers have different total amounts of power, as well as a certain Grid Efficiency: - -1. Escort: 8 PO, 1 GE -2. *Frigate* (Vestigium only): 12 PO, 1 GE -3. Destroyer: 12 PO, 2 GE -4. Cruiser: 16 PO, 3 GE -5. *Line Ship* (Vestigium only): 20 PO, 3 GE -6. Battlecruiser: 16 PO, 4 GE -7. *Heavy Cruiser* (Isarnareykk only): 24 PO, 3 GE -8. Battleship: 24 PO, 4 GE -9. *Dreadnought* (Vestigium only): 28 PO, 5 GE -10. *Colossus* (Masra Draetsen only): 36 PO, 7 GE - -The effects that different power levels have is as follows: - -* Each unit of Weapon Power is consumed when a ship fires a weapon or charges a Lance battery - * Weapon power is replenished completely after the End phase ends -* Each unit of Shield Power is consumed when a ship's shields block an attack - * Shield power is replenished after the End phase ends - * Each Blast Marker the ship is touching has a 50% chance of reducing the replenished shield power by 1 -* Engine power modifies the ship's maximum acceleration - * The normal Engine Power `e_0` is 25% of the total PO - * The current Engine Power `e_1` is however many points the ship has put into its Engines - * The movement speed factor is `η = sqrt(e_1 / e_0)` - * The maximum distance moved during the Movement phase is `a_max = a_max_0 * η` where `a_max_0` is the default max movement - * The maximum angle turned during the Movement phase is `α_max = α_max_0 * η` -* Emitter power modifies the power of the ship's Emitter abilities - * Similar factor: `μ = sqrt(m_1 / m_0)` - * The reason why the `sqrt` function is used is to represent the diminishing returns of putting more power into a subsystem - -### Movement Phase - -Ships change their velocity during this phase. Velocity as a property of ships is persistent, -being modified by the ship's acceleration which is decided during this phase. - -The way ships move is as follows, where ship's maximum acceleration is `a_max`, current position is `x_1`, previous position is `x_0`, and current ship facing is `θ`: - -1. Ship rotates a certain amount (up to maximum rotation) chosen by the player away from `θ`, this new facing angle is put into `φ`. -2. A line is drawn starting at `x_1 + (x_1 - x_0)`, this point is put into `x_2`. -3. The line traverses the vector `a_max * (î cos ((θ + φ) / 2) + ĵ sin ((θ + φ) / /2))` away from `x_2` -4. The player chooses a point along this line for the ship to travel to, this point is put into `x_new` -5. `x_1 -> x_0`, then `x_new -> x_1` and `φ -> θ` - -### Action Phase - -Ships call attacks against other ships during this phase, -as well as defending themselves or each other from those attacks. - -### End Phase - -Attacks, defenses, and results of actions are resolved. - -Blast markers are created; each successfully-hit attack creates a blast marker within -a certain radius of the targeted ship. diff --git a/src/commonMain/kotlin/starshipfights/game/game_ability.kt b/src/commonMain/kotlin/starshipfights/game/game_ability.kt index 05de169..add7a05 100644 --- a/src/commonMain/kotlin/starshipfights/game/game_ability.kt +++ b/src/commonMain/kotlin/starshipfights/game/game_ability.kt @@ -137,12 +137,14 @@ sealed class PlayerAbilityType { val shipInstance = gameState.ships[ship] ?: return GameEvent.InvalidAction("That ship does not exist") if (!shipInstance.validatePowerMode(data.powerMode)) return GameEvent.InvalidAction("Invalid power distribution") + val prevShieldDamage = shipInstance.powerMode.shields - shipInstance.shieldAmount + val newShipInstance = shipInstance.copy( powerMode = data.powerMode, isDoneCurrentPhase = true, weaponAmount = data.powerMode.weapons, - shieldAmount = data.powerMode.shields, + shieldAmount = (data.powerMode.shields - prevShieldDamage).coerceAtLeast(0), ) val newShips = gameState.ships + mapOf(ship to newShipInstance) diff --git a/src/commonMain/kotlin/starshipfights/game/game_state.kt b/src/commonMain/kotlin/starshipfights/game/game_state.kt index 4c7acf3..ae2a0d0 100644 --- a/src/commonMain/kotlin/starshipfights/game/game_state.kt +++ b/src/commonMain/kotlin/starshipfights/game/game_state.kt @@ -32,19 +32,14 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide val newChatEntries = mutableListOf() when (phase) { - is GamePhase.Power -> { - newShips = newShips.mapValues { (_, ship) -> - ship.copy( - weaponAmount = ship.powerMode.weapons, - shieldAmount = ship.powerMode.shields, - ) - } - } is GamePhase.Move -> { + // Auto-move drifting ships newShips = newShips.mapValues { (_, ship) -> if (ship.isDoneCurrentPhase) ship else ship.copy(position = ship.position.drift) } + + // Ships that move off the battlefield are considered to disengage newShips = newShips.mapNotNull fleeingShips@{ (id, ship) -> val r = ship.position.currentLocation.vector val mx = start.battlefieldWidth / 2 @@ -58,6 +53,8 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide id to ship }.toMap() + + // Identify enemy ships newShips = newShips.mapValues { (_, ship) -> if (ship.isIdentified) ship else if (newShips.values.any { it.owner != ship.owner && (it.position.currentLocation - ship.position.currentLocation).length <= SHIP_SENSOR_RANGE }) @@ -70,6 +67,7 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide is GamePhase.Attack -> { val strikeWingDamage = mutableMapOf() + // Apply damage to ships from strike craft newShips = newShips.mapNotNull strikeBombard@{ (id, ship) -> if (ship.bomberWings.isEmpty()) return@strikeBombard id to ship @@ -115,6 +113,8 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide } } }.toMap() + + // Apply damage to strike craft wings newShips = newShips.mapValues { (shipId, ship) -> val newArmaments = ship.armaments.weaponInstances.mapValues { (weaponId, weapon) -> if (weapon is ShipWeaponInstance.Hangar) @@ -126,8 +126,13 @@ fun GameState.afterPlayerReady(playerSide: GlobalSide) = if (ready == playerSide armaments = ShipInstanceArmaments(newArmaments) ) } + + // Recall strike craft and regenerate weapon and shield powers newShips = newShips.mapValues { (_, ship) -> ship.copy( + weaponAmount = ship.powerMode.weapons, + shieldAmount = (ship.shieldAmount..ship.powerMode.shields).random(), + fighterWings = emptyList(), bomberWings = emptyList(), usedArmaments = emptySet(), diff --git a/src/commonMain/kotlin/starshipfights/game/ship_instances.kt b/src/commonMain/kotlin/starshipfights/game/ship_instances.kt index ade5f96..bd3ee1f 100644 --- a/src/commonMain/kotlin/starshipfights/game/ship_instances.kt +++ b/src/commonMain/kotlin/starshipfights/game/ship_instances.kt @@ -59,7 +59,7 @@ data class ShipPosition( } enum class ShipSubsystem { - WEAPONS, SHIELDS, ENGINES, EMITTER; + WEAPONS, SHIELDS, ENGINES, BATTERY; val displayName: String get() = name.lowercase().replaceFirstChar { it.uppercase() } @@ -69,7 +69,7 @@ enum class ShipSubsystem { WEAPONS -> "#FF6633" SHIELDS -> "#6699FF" ENGINES -> "#FFCC33" - EMITTER -> "#33FF66" + BATTERY -> "#33FF66" } val imageUrl: String @@ -86,13 +86,13 @@ data class ShipPowerMode( val weapons: Int, val shields: Int, val engines: Int, - val emitter: Int, + val battery: Int, ) { operator fun plus(delta: Map) = copy( weapons = weapons + (delta[ShipSubsystem.WEAPONS] ?: 0), shields = shields + (delta[ShipSubsystem.SHIELDS] ?: 0), engines = engines + (delta[ShipSubsystem.ENGINES] ?: 0), - emitter = emitter + (delta[ShipSubsystem.EMITTER] ?: 0), + battery = battery + (delta[ShipSubsystem.BATTERY] ?: 0), ) operator fun minus(delta: Map) = this + delta.mapValues { (_, d) -> -d } @@ -101,11 +101,11 @@ data class ShipPowerMode( ShipSubsystem.WEAPONS -> weapons ShipSubsystem.SHIELDS -> shields ShipSubsystem.ENGINES -> engines - ShipSubsystem.EMITTER -> emitter + ShipSubsystem.BATTERY -> battery } val total: Int - get() = weapons + shields + engines + emitter + get() = weapons + shields + engines + battery infix fun distanceTo(other: ShipPowerMode) = ShipSubsystem.values().sumOf { subsystem -> abs(this[subsystem] - other[subsystem]) } } diff --git a/src/jsMain/resources/images/subsystem-battery.svg b/src/jsMain/resources/images/subsystem-battery.svg new file mode 100644 index 0000000..fefe69b --- /dev/null +++ b/src/jsMain/resources/images/subsystem-battery.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/src/jsMain/resources/images/subsystem-emitter.svg b/src/jsMain/resources/images/subsystem-emitter.svg deleted file mode 100644 index fefe69b..0000000 --- a/src/jsMain/resources/images/subsystem-emitter.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - diff --git a/src/jvmMain/kotlin/starshipfights/info/views_ships.kt b/src/jvmMain/kotlin/starshipfights/info/views_ships.kt index 6d36955..b776589 100644 --- a/src/jvmMain/kotlin/starshipfights/info/views_ships.kt +++ b/src/jvmMain/kotlin/starshipfights/info/views_ships.kt @@ -30,7 +30,7 @@ suspend fun ApplicationCall.shipsPage(): HTML.() -> Unit = page("Game Manual", s } h3 { +"Subsystem Powering" } p { - +"Ships have two particular attributes that are closely related: Reactor Power and Energy Flow. Reactor Power is how much power the ship's generators generate, and starts off as being split evenly between the ship's four subsystems: Weapons, Shields, Engines, and Emitters. Weapons Power is expended when firing Cannons or charging Lances; Shields Power is expended whenever the ship's shields are impacted by enemy fire; Engines Power modifies the speed and turn rate of the ship; finally, Emitter Power modifies the ship's special techno-science abilities. The ship's Energy Flow statistic determines how many transfers can be made between subsystems during the Power Distribution phase of a turn." + +"Ships have two particular attributes that are closely related: Reactor Power and Energy Flow. Reactor Power is how much power the ship's generators generate, and starts off as being split evenly between the ship's four subsystems: Weapons, Shields, Engines, and Battery. Weapons Power is expended when firing Cannons or charging Lances; Shields Power is expended whenever the ship's shields are impacted by enemy fire; Engines Power modifies the speed and turn rate of the ship; finally, Battery Power modifies the ship's special techno-science abilities. The ship's Energy Flow statistic determines how many transfers can be made between subsystems during the Power Distribution phase of a turn." } h3 { +"Turn Structure" } p {