implemented torpedoes!

This commit is contained in:
Christopher
2023-03-04 15:24:05 +13:00
parent 5c25a83eaf
commit 781d0566f8
5 changed files with 148 additions and 53 deletions

View File

@@ -132,22 +132,24 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) {
// todo account for being blocked
let path = find_path(ship.quadrant, ship.sector, course, warp_speed);
let (path, hit_edge) = find_nav_path(ship.quadrant, ship.sector, course, warp_speed);
let energy_cost = path.len() as u16 + 10;
if path.energy_cost > ship.total_energy {
if energy_cost > ship.total_energy {
view::insuffient_warp_energy(warp_speed);
return
}
if path.hit_edge {
view::hit_edge(&path);
let (end_quadrant, end_sector) = path[path.len() - 1].to_local_quadrant_sector();
if hit_edge {
view::hit_edge(end_quadrant, end_sector);
}
if ship.quadrant != path.quadrant {
view::enter_quadrant(&path.quadrant);
galaxy.scanned.insert(path.quadrant);
if ship.quadrant != end_quadrant {
view::enter_quadrant(end_quadrant);
galaxy.scanned.insert(end_quadrant);
if galaxy.quadrants[path.quadrant.as_index()].klingons.len() > 0 {
if galaxy.quadrants[end_quadrant.as_index()].klingons.len() > 0 {
view::condition_red();
if ship.shields <= 200 {
view::danger_shields();
@@ -155,16 +157,16 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) {
}
}
ship.quadrant = path.quadrant;
ship.sector = path.sector;
ship.quadrant = end_quadrant;
ship.sector = end_sector;
let quadrant = &galaxy.quadrants[path.quadrant.as_index()];
let quadrant = &galaxy.quadrants[end_quadrant.as_index()];
if quadrant.docked_at_starbase(ship.sector) {
ship.shields = 0;
ship.photon_torpedoes = MAX_PHOTON_TORPEDOES;
ship.total_energy = MAX_ENERGY;
} else {
ship.total_energy = (ship.total_energy - path.energy_cost).max(0);
ship.total_energy = ship.total_energy - energy_cost;
if ship.shields > ship.total_energy {
view::divert_energy_from_shields();
ship.shields = ship.total_energy;
@@ -174,23 +176,16 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) {
view::short_range_scan(&galaxy)
}
fn find_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> EndPosition {
fn find_nav_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> (Vec<Pos>, bool) {
// this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs
let dir = (course - 1.0) % 8.0;
let (dx1, dy1) = COURSES[dir as usize];
let (dx2, dy2) = COURSES[(dir + 1.0) as usize];
let frac = dir - (dir as i32) as f32;
let dx = dx1 + (dx2 - dx1) * frac;
let dy = dy1 + (dy2 - dy1) * frac;
let (dx, dy) = calculate_delta(course);
let mut distance = (warp_speed * 8.0) as i8;
if distance == 0 {
distance = 1;
}
let mut last_sector = start_quadrant * 8 + start_sector;
let mut last_sector = start_sector.as_galactic_sector(start_quadrant);
let mut path = Vec::new();
let mut hit_edge;
@@ -210,11 +205,20 @@ fn find_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f3
}
}
let quadrant = Pos((last_sector.0 / 8) as u8, (last_sector.1 / 8) as u8);
let sector = Pos((last_sector.0 % 8) as u8, (last_sector.1 % 8) as u8);
let energy_cost = path.len() as u16 + 10;
(path, hit_edge)
}
EndPosition { quadrant, sector, hit_edge, energy_cost }
fn calculate_delta(course: f32) -> (f32, f32) {
// this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs
let dir = (course - 1.0) % 8.0;
let (dx1, dy1) = COURSES[dir as usize];
let (dx2, dy2) = COURSES[(dir + 1.0) as usize];
let frac = dir - (dir as i32) as f32;
let dx = dx1 + (dx2 - dx1) * frac;
let dy = dy1 + (dy2 - dy1) * frac;
(dx, dy)
}
fn klingons_move(galaxy: &mut Galaxy) {
@@ -371,12 +375,15 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec<String>) {
}
pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec<String>) {
if galaxy.enterprise.damaged.contains_key(systems::TORPEDOES) {
let star_bases = galaxy.remaining_starbases();
let ship = &mut galaxy.enterprise;
if ship.damaged.contains_key(systems::TORPEDOES) {
view::inoperable(&systems::name_for(systems::TORPEDOES));
return;
}
if galaxy.enterprise.photon_torpedoes == 0 {
if ship.photon_torpedoes == 0 {
view::no_torpedoes_remaining();
return;
}
@@ -387,12 +394,68 @@ pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec<String>)
return;
}
galaxy.enterprise.photon_torpedoes -= 1;
ship.photon_torpedoes -= 1;
view::torpedo_track();
// calculate direction
// step through sectors
// test for hits or final miss
let path = find_torpedo_path(ship.sector, course.unwrap());
let quadrant = &mut galaxy.quadrants[ship.quadrant.as_index()];
let mut hit = false;
for p in path {
view::torpedo_path(p);
match quadrant.sector_status(p) {
SectorStatus::Empty => continue,
SectorStatus::Star => {
hit = true;
view::star_absorbed_torpedo(p);
break;
},
SectorStatus::Klingon => {
hit = true;
quadrant.get_klingon(p).unwrap().energy = 0.0;
quadrant.klingons.retain(|k| k.energy > 0.0);
view::klingon_destroyed();
break;
},
SectorStatus::StarBase => {
hit = true;
quadrant.star_base = None;
let remaining = star_bases - 1;
view::destroyed_starbase(remaining > 0);
if remaining == 0 {
ship.destroyed = true;
}
break;
}
}
}
if ship.destroyed { // if you wiped out the last starbase, trigger game over
return;
}
if !hit {
view::torpedo_missed();
}
klingons_fire(galaxy);
}
fn find_torpedo_path(start_sector: Pos, course: f32) -> Vec<Pos> {
let (dx, dy) = calculate_delta(course);
let mut last_sector = start_sector;
let mut path = Vec::new();
loop {
let nx = (last_sector.0 as f32 + dx) as i8;
let ny = (last_sector.1 as f32 + dy) as i8;
if nx < 0 || ny < 0 || nx >= 8 || ny >= 8 {
break;
}
last_sector = Pos(nx as u8, ny as u8);
path.push(last_sector);
}
path
}

View File

@@ -20,7 +20,7 @@ fn main() {
view::intro(&galaxy);
let _ = input::prompt(view::prompts::WHEN_READY);
view::starting_quadrant(&galaxy.enterprise.quadrant);
view::starting_quadrant(galaxy.enterprise.quadrant);
view::short_range_scan(&galaxy);
loop {

View File

@@ -60,7 +60,8 @@ impl Enterprise {
if self.shields <= hit_strength {
view::enterprise_destroyed();
self.destroyed = true
self.destroyed = true;
return;
}
self.shields -= hit_strength;
@@ -141,13 +142,6 @@ pub mod systems {
}
}
pub struct EndPosition {
pub quadrant: Pos,
pub sector: Pos,
pub hit_edge: bool,
pub energy_cost: u16,
}
#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)]
pub struct Pos(pub u8, pub u8);
@@ -159,6 +153,14 @@ impl Pos {
pub fn abs_diff(&self, other: Pos) -> u8 {
self.0.abs_diff(other.0) + self.1.abs_diff(other.1)
}
pub fn as_galactic_sector(&self, containing_quadrant: Pos) -> Self {
Pos(containing_quadrant.0 * 8 + self.0, containing_quadrant.1 * 8 + self.1)
}
pub fn to_local_quadrant_sector(&self) -> (Self, Self) {
(Pos(self.0 / 8, self.1 / 8), Pos(self.0 % 8, self.1 % 8))
}
}
impl Mul<u8> for Pos {
@@ -286,7 +288,7 @@ impl Quadrant {
SectorStatus::Star
} else if self.is_starbase(sector) {
SectorStatus::StarBase
} else if self.has_klingon(&sector) {
} else if self.has_klingon(sector) {
SectorStatus::Klingon
} else {
SectorStatus::Empty
@@ -300,9 +302,14 @@ impl Quadrant {
}
}
fn has_klingon(&self, sector: &Pos) -> bool {
fn has_klingon(&self, sector: Pos) -> bool {
let klingons = &self.klingons;
klingons.into_iter().find(|k| &k.sector == sector).is_some()
klingons.into_iter().find(|k| k.sector == sector).is_some()
}
pub fn get_klingon(&mut self, sector: Pos) -> Option<&mut Klingon> {
let klingons = &mut self.klingons;
klingons.into_iter().find(|k| k.sector == sector)
}
pub fn find_empty_sector(&self) -> Pos {

View File

@@ -1,4 +1,4 @@
use crate::model::{Galaxy, Pos, EndPosition, SectorStatus, Enterprise, systems};
use crate::model::{Galaxy, Pos, SectorStatus, Enterprise, systems};
pub mod prompts {
pub const COURSE: &str = "Course (1-9)?";
@@ -187,19 +187,19 @@ const REGION_NAMES: [&str; 16] = [
const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"];
fn quadrant_name(quadrant: &Pos) -> String {
fn quadrant_name(quadrant: Pos) -> String {
format!("{} {}",
REGION_NAMES[((quadrant.1 << 1) + (quadrant.0 >> 2)) as usize],
SUB_REGION_NAMES[(quadrant.1 % 4) as usize])
}
pub fn starting_quadrant(quadrant: &Pos) {
pub fn starting_quadrant(quadrant: Pos) {
println!(
"\nYour mission begins with your starship located
in the galactic quadrant, '{}'.\n", quadrant_name(quadrant))
}
pub fn enter_quadrant(quadrant: &Pos) {
pub fn enter_quadrant(quadrant: Pos) {
println!("\nNow entering {} quadrant . . .\n", quadrant_name(quadrant))
}
@@ -285,13 +285,13 @@ pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) {
println!("{hit_strength} unit hit on Enterprise from sector {from_sector}");
}
pub fn hit_edge(end: &EndPosition) {
pub fn hit_edge(quadrant: Pos, sector: Pos) {
println!(
"Lt. Uhura report message from Starfleet Command:
'Permission to attempt crossing of galactic perimeter
is hereby *Denied*. Shut down your engines.'
Chief Engineer Scott reports, 'Warp engines shut down
at sector {} of quadrant {}.'", end.sector, end.quadrant);
at sector {} of quadrant {}.'", sector, quadrant);
}
pub fn condition_red() {
@@ -494,7 +494,7 @@ pub fn klingon_remaining_energy(energy: f32) {
}
pub fn klingon_destroyed() {
println!(" Target Destroyed!") // not standard for game but feedback is good. Sorry Mr. Roddenberry
println!("*** Klingon destroyed ***")
}
pub fn congratulations(efficiency: f32) {
@@ -519,4 +519,29 @@ pub fn no_torpedoes_remaining() {
pub fn torpedo_track() {
println!("Torpedo track:")
}
pub fn torpedo_path(sector: Pos) {
println!("{:<16}{}", "", sector)
}
pub fn torpedo_missed() {
println!("Torpedo missed!")
}
pub fn star_absorbed_torpedo(sector: Pos) {
println!("Star at {sector} absorbed torpedo energy.")
}
pub fn destroyed_starbase(not_the_last_starbase: bool) {
println!("*** Starbase destroyed ***");
if not_the_last_starbase {
println!("
Starfleet Command reviewing your record to consider
court martial!")
} else {
println!("
That does it, Captain!! You are hereby relieved of command
and sentenced to 99 stardates at hard labor on Cygnus 12!!")
}
}

View File

@@ -25,9 +25,9 @@ Started after movement and display of stats was finished (no energy management o
- [x] proximity detection for docking
- [x] repair on damage control
- [x] protection from shots
- [ ] weapons
- [x] weapons
- [x] phasers
- [ ] torpedoes
- [x] torpedoes
- [ ] computer
- [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned)
- [ ] 1 - klingons, starbases, stardate and damage control