Compare commits
8 Commits
1f2ba92bea
...
7272f2a00a
Author | SHA1 | Date |
---|---|---|
Mark | 7272f2a00a | |
Mark | de07e763c3 | |
Mark | d3195983ec | |
Mark | 82f2f5fc85 | |
Mark | 9f19becf0c | |
Mark | a6bc1a021d | |
Mark | f5c9540fb7 | |
Mark | ab17930449 |
1
TODO.md
1
TODO.md
|
@ -17,6 +17,7 @@
|
|||
- fps textbox positioning
|
||||
- shield generation curve
|
||||
- clippy & rules
|
||||
- reject unknown toml
|
||||
|
||||
## Small jobs
|
||||
- Better planet icons in radar
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[outfit."plasma engines"]
|
||||
name = "Plasma Engines"
|
||||
thumbnail = "icon::engine"
|
||||
cost = 30
|
||||
|
||||
desc = """
|
||||
This is the smallest of the plasma propulsion systems produced by
|
||||
|
@ -21,6 +22,7 @@ steering.power = 20
|
|||
[outfit."shield generator"]
|
||||
thumbnail = "icon::shield"
|
||||
name = "Shield Generator"
|
||||
cost = 10
|
||||
|
||||
desc = """
|
||||
This is the standard shield generator for fighters and interceptors,
|
||||
|
@ -40,6 +42,7 @@ shield.delay = 2.0
|
|||
[outfit."blaster"]
|
||||
thumbnail = "icon::blaster"
|
||||
name = "Blaster"
|
||||
cost = 20
|
||||
|
||||
desc = """
|
||||
Although not the most accurate or damaging of weapons, the Energy Blaster is popular because it
|
||||
|
|
|
@ -113,10 +113,15 @@ fn event(state, event) {
|
|||
}
|
||||
|
||||
fn step(state) {
|
||||
if state.player_ship().stat_shield_strength() == 0.0 {
|
||||
radialbar::set_val("shield", 0.0);
|
||||
} else {
|
||||
radialbar::set_val("shield",
|
||||
state.player_ship().current_shields()
|
||||
/ state.player_ship().stat_shield_strength()
|
||||
);
|
||||
}
|
||||
|
||||
radialbar::set_val("hull",
|
||||
state.player_ship().current_hull()
|
||||
/ state.player_ship().total_hull()
|
||||
|
|
|
@ -347,6 +347,9 @@ fn init(state) {
|
|||
|
||||
|
||||
fn event(state, event) {
|
||||
// TODO: update on ship outfit change only
|
||||
update_ship_info(state);
|
||||
|
||||
if type_of(event) == "MouseHoverEvent" {
|
||||
let element = event.element();
|
||||
|
||||
|
@ -394,6 +397,24 @@ fn event(state, event) {
|
|||
return PlayerDirective::None;
|
||||
}
|
||||
|
||||
if element == "buy_button" {
|
||||
if selected_outfit != false {
|
||||
let outfit = ct::get_outfit(selected_outfit);
|
||||
if outfit.is_some() {
|
||||
return PlayerDirective::BuyOutfit(outfit, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if element == "sell_button" {
|
||||
if selected_outfit != false {
|
||||
let outfit = ct::get_outfit(selected_outfit);
|
||||
if outfit.is_some() {
|
||||
return PlayerDirective::SellOutfit(outfit, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
element.starts_with("outfit.backg.") &&
|
||||
event.element().split("outfit.backg.".len())[1] != selected_outfit
|
||||
|
@ -475,6 +496,41 @@ fn update_outfit_info(selected_outfit) {
|
|||
|
||||
let stats = "";
|
||||
let tlen = 20;
|
||||
|
||||
|
||||
{
|
||||
let s = "cost ";
|
||||
s.pad(tlen, " ");
|
||||
stats += s + outfit.cost();
|
||||
stats += "\n";
|
||||
}
|
||||
|
||||
{
|
||||
let s = "needs gun port ";
|
||||
s.pad(tlen, " ");
|
||||
if outfit.stat_is_gun() {
|
||||
stats += s + "yes";
|
||||
} else {
|
||||
stats += s + "no"
|
||||
}
|
||||
stats += "\n";
|
||||
}
|
||||
|
||||
{
|
||||
let s = outfit.required_space();
|
||||
for k in s.keys() {
|
||||
let v = s[k];
|
||||
let s = k + " space needed ";
|
||||
s.pad(tlen, " ");
|
||||
if v != 0 {
|
||||
stats += s + v;
|
||||
stats += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stats += "\n";
|
||||
|
||||
if outfit.stat_thrust() != 0 {
|
||||
let s = "thrust ";
|
||||
s.pad(tlen, " ");
|
||||
|
@ -527,8 +583,28 @@ fn update_ship_info(state) {
|
|||
let tlen = 20;
|
||||
|
||||
|
||||
{
|
||||
let u = ship.used_space();
|
||||
let t = ship.total_space();
|
||||
for k in u.keys() {
|
||||
let vu = u[k];
|
||||
let vt = t[k];
|
||||
let s = k + " space ";
|
||||
s.pad(tlen, " ");
|
||||
stats += s + (vt - vu) + "/" + vt;
|
||||
stats += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let s = "gun points ";
|
||||
s.pad(tlen, " ");
|
||||
stats += s + ship.free_gun_points() + "/" + ship.total_gun_points();
|
||||
stats += "\n\n";
|
||||
}
|
||||
|
||||
// TODO: outfits add mass
|
||||
// TODO: calculate radial acceleration
|
||||
// TODO: calculate acceleration
|
||||
{
|
||||
let s = "shield strength ";
|
||||
s.pad(tlen, " ");
|
||||
|
|
|
@ -24,6 +24,7 @@ pub(crate) mod syntax {
|
|||
pub thumbnail: ContentIndex,
|
||||
pub name: String,
|
||||
pub desc: String,
|
||||
pub cost: u32,
|
||||
pub engine: Option<Engine>,
|
||||
pub steering: Option<Steering>,
|
||||
pub space: outfitspace::syntax::OutfitSpace,
|
||||
|
@ -140,6 +141,9 @@ pub struct Outfit {
|
|||
/// This outfit's thumbnail
|
||||
pub thumbnail: Arc<Sprite>,
|
||||
|
||||
/// The cost of this outfit, in credits
|
||||
pub cost: u32,
|
||||
|
||||
/// How much space this outfit requires
|
||||
pub space: OutfitSpace,
|
||||
|
||||
|
@ -324,6 +328,7 @@ impl crate::Build for Outfit {
|
|||
let mut o = Self {
|
||||
index: ContentIndex::new(&outfit_name),
|
||||
display_name: outfit.name,
|
||||
cost: outfit.cost,
|
||||
thumbnail,
|
||||
gun,
|
||||
desc: outfit.desc,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ops::{Add, AddAssign, Sub, SubAssign},
|
||||
};
|
||||
|
||||
pub(crate) mod syntax {
|
||||
use serde::Deserialize;
|
||||
|
@ -44,6 +47,15 @@ impl OutfitSpace {
|
|||
&& self.weapon >= smaller.weapon
|
||||
&& self.engine >= smaller.engine
|
||||
}
|
||||
|
||||
/// Return a map of "space name" -> number
|
||||
pub fn to_hashmap(&self) -> HashMap<String, u32> {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("outfit".to_string(), self.outfit);
|
||||
m.insert("weapon".to_string(), self.weapon);
|
||||
m.insert("engine".to_string(), self.engine);
|
||||
m
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for OutfitSpace {
|
||||
|
|
|
@ -5,6 +5,7 @@ use galactica_system::phys::{PhysImage, PhysSim, PhysSimShipHandle, PhysStepReso
|
|||
use galactica_system::PlayerDirective;
|
||||
use galactica_util::timing::Timing;
|
||||
use nalgebra::Point2;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
|
@ -51,16 +52,6 @@ impl<'a> Game {
|
|||
.get(&ContentIndex::new("shield generator"))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
self.ct
|
||||
.outfits
|
||||
.get(&ContentIndex::new("blaster"))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
self.ct
|
||||
.outfits
|
||||
.get(&ContentIndex::new("blaster"))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
]);
|
||||
|
||||
return player;
|
||||
|
@ -131,9 +122,43 @@ impl<'a> Game {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn apply_directive(&mut self, directive: PlayerDirective, player: &PlayerAgent) {
|
||||
pub fn apply_directive(&mut self, directive: PlayerDirective, player: &mut PlayerAgent) {
|
||||
match directive {
|
||||
_ => self.phys_sim.apply_directive(directive, player),
|
||||
PlayerDirective::None => {}
|
||||
|
||||
PlayerDirective::BuyOutfit { outfit, count } => {
|
||||
let cost = outfit.cost * count;
|
||||
if player.credits >= cost {
|
||||
player.credits -= cost;
|
||||
let ship = self
|
||||
.phys_sim
|
||||
.get_ship_mut(&PhysSimShipHandle(player.ship.unwrap()))
|
||||
.unwrap();
|
||||
ship.add_outfits(iter::repeat(outfit).take(count as usize))
|
||||
}
|
||||
}
|
||||
|
||||
PlayerDirective::SellOutfit { outfit, count } => {
|
||||
let ship = self
|
||||
.phys_sim
|
||||
.get_ship_mut(&PhysSimShipHandle(player.ship.unwrap()))
|
||||
.unwrap();
|
||||
|
||||
if ship.get_data().get_outfits().has_outfit(&outfit, count) {
|
||||
for _ in 0..count {
|
||||
ship.remove_outfit(&outfit);
|
||||
}
|
||||
}
|
||||
|
||||
player.credits += outfit.cost * count;
|
||||
}
|
||||
|
||||
PlayerDirective::Engine(_)
|
||||
| PlayerDirective::Guns(_)
|
||||
| PlayerDirective::Land
|
||||
| PlayerDirective::TurnLeft(_)
|
||||
| PlayerDirective::TurnRight(_)
|
||||
| PlayerDirective::UnLand => self.phys_sim.apply_directive(directive, player),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ use log4rs::{
|
|||
Config,
|
||||
};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
|
@ -127,7 +128,7 @@ fn try_main() -> Result<()> {
|
|||
current_time: game.get_current_time(),
|
||||
ct: content.clone(),
|
||||
phys_img: PhysImage::new(),
|
||||
player: PlayerAgent::new(&content, p.0),
|
||||
player: RefCell::new(PlayerAgent::new(&content, p.0)),
|
||||
// TODO: this is a hack for testing.
|
||||
current_system: content.systems.values().next().unwrap().clone(),
|
||||
timing: game.get_timing().clone(),
|
||||
|
@ -184,13 +185,13 @@ fn try_main() -> Result<()> {
|
|||
},
|
||||
)
|
||||
.unwrap();
|
||||
game.apply_directive(directive, &input.player);
|
||||
game.apply_directive(directive, &mut input.player.borrow_mut());
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let directive = gpu
|
||||
.process_input(&input, InputEvent::MouseMove(position.cast()))
|
||||
.unwrap();
|
||||
game.apply_directive(directive, &input.player);
|
||||
game.apply_directive(directive, &mut input.player.borrow_mut());
|
||||
}
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
let down = state == &ElementState::Pressed;
|
||||
|
@ -201,7 +202,7 @@ fn try_main() -> Result<()> {
|
|||
};
|
||||
if let Some(event) = event {
|
||||
let directive = gpu.process_input(&input, event).unwrap();
|
||||
game.apply_directive(directive, &input.player);
|
||||
game.apply_directive(directive, &mut input.player.borrow_mut());
|
||||
}
|
||||
}
|
||||
WindowEvent::MouseWheel { delta, .. } => {
|
||||
|
@ -214,7 +215,7 @@ fn try_main() -> Result<()> {
|
|||
}),
|
||||
)
|
||||
.unwrap();
|
||||
game.apply_directive(directive, &input.player);
|
||||
game.apply_directive(directive, &mut input.player.borrow_mut());
|
||||
}
|
||||
WindowEvent::Resized(_) => {
|
||||
gpu.resize(&content);
|
||||
|
|
|
@ -29,13 +29,17 @@ pub struct PlayerAgent {
|
|||
/// Which ship this player is controlling
|
||||
pub ship: Option<ColliderHandle>,
|
||||
|
||||
/// What the player has selected
|
||||
/// What this player has selected
|
||||
pub selection: PlayerSelection,
|
||||
|
||||
/// The amount of money this player has
|
||||
pub credits: u32,
|
||||
}
|
||||
|
||||
impl PlayerAgent {
|
||||
pub fn new(ct: &Content, ship: ColliderHandle) -> Self {
|
||||
Self {
|
||||
credits: 1000,
|
||||
ship: Some(ship),
|
||||
selection: PlayerSelection::OrbitingBody(
|
||||
ct.systems
|
||||
|
|
|
@ -287,7 +287,7 @@ impl GPUState {
|
|||
|
||||
/// Main render function. Draws sprites on a window.
|
||||
pub fn render(&mut self, input: &Arc<RenderInput>) -> Result<(), wgpu::SurfaceError> {
|
||||
if let Some(ship) = input.player.ship {
|
||||
if let Some(ship) = input.player.borrow().ship {
|
||||
let o = input.phys_img.get_ship(&PhysSimShipHandle(ship));
|
||||
if let Some(o) = o {
|
||||
match o.ship.get_data().get_state() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
|
||||
use galactica_content::{Content, System};
|
||||
use galactica_playeragent::PlayerAgent;
|
||||
|
@ -9,7 +9,7 @@ use galactica_util::timing::Timing;
|
|||
#[derive(Debug)]
|
||||
pub struct RenderInput {
|
||||
/// Player ship data
|
||||
pub player: PlayerAgent,
|
||||
pub player: RefCell<PlayerAgent>,
|
||||
|
||||
/// The system we're currently in
|
||||
pub current_system: Arc<System>,
|
||||
|
|
|
@ -4,6 +4,7 @@ use rhai::{plugin::*, Dynamic, Module};
|
|||
#[allow(non_snake_case)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub mod player_directive_module {
|
||||
use crate::ui::api::OutfitState;
|
||||
use galactica_system::PlayerDirective;
|
||||
|
||||
pub const None: PlayerDirective = PlayerDirective::None;
|
||||
|
@ -25,4 +26,24 @@ pub mod player_directive_module {
|
|||
pub fn Guns(state: bool) -> PlayerDirective {
|
||||
PlayerDirective::Guns(state)
|
||||
}
|
||||
|
||||
pub fn BuyOutfit(outfit: OutfitState, count: i64) -> PlayerDirective {
|
||||
if count <= 0 {
|
||||
return PlayerDirective::None;
|
||||
}
|
||||
PlayerDirective::BuyOutfit {
|
||||
outfit: outfit.get_outfit().unwrap(),
|
||||
count: count as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn SellOutfit(outfit: OutfitState, count: i64) -> PlayerDirective {
|
||||
if count <= 0 {
|
||||
return PlayerDirective::None;
|
||||
}
|
||||
PlayerDirective::SellOutfit {
|
||||
outfit: outfit.get_outfit().unwrap(),
|
||||
count: count as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use galactica_content::{Content, Outfit};
|
||||
use galactica_content::{Content, Outfit, OutfitSpace};
|
||||
use log::error;
|
||||
use rhai::{CustomType, FnNamespace, FuncRegistration, ImmutableString, Module, TypeBuilder};
|
||||
use rhai::{
|
||||
CustomType, Dynamic, FnNamespace, FuncRegistration, ImmutableString, Map, Module, TypeBuilder,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn build_ct_module(ct_src: Arc<Content>) -> Module {
|
||||
|
@ -40,6 +42,10 @@ impl OutfitState {
|
|||
pub fn new_none() -> Self {
|
||||
Self { outfit: None }
|
||||
}
|
||||
|
||||
pub fn get_outfit(&self) -> Option<Arc<Outfit>> {
|
||||
self.outfit.as_ref().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for OutfitState {
|
||||
|
@ -71,6 +77,20 @@ impl CustomType for OutfitState {
|
|||
.map(|x| x.thumbnail.index.to_string())
|
||||
.unwrap_or("".to_string())
|
||||
})
|
||||
.with_fn("cost", |s: &mut Self| {
|
||||
s.outfit.as_ref().map(|x| x.cost).unwrap_or(0)
|
||||
})
|
||||
.with_fn("required_space", |s: &mut Self| {
|
||||
Map::from_iter(
|
||||
s.outfit
|
||||
.as_ref()
|
||||
.map(|x| x.space)
|
||||
.unwrap_or(OutfitSpace::new())
|
||||
.to_hashmap()
|
||||
.iter()
|
||||
.map(|(k, v)| (ImmutableString::from(k).into(), Dynamic::from(*v as i64))),
|
||||
)
|
||||
})
|
||||
//
|
||||
// Stat getters
|
||||
//
|
||||
|
@ -104,6 +124,9 @@ impl CustomType for OutfitState {
|
|||
.map(|x| x.stats.shield_delay)
|
||||
.unwrap_or(0.0)
|
||||
})
|
||||
.with_fn("stat_is_gun", |s: &mut Self| {
|
||||
s.outfit.as_ref().map(|x| x.gun.is_some()).unwrap_or(false)
|
||||
})
|
||||
.with_fn("stat_shield_dps", |s: &mut Self| {
|
||||
s.outfit
|
||||
.as_ref()
|
||||
|
|
|
@ -7,7 +7,7 @@ use galactica_util::to_degrees;
|
|||
use log::error;
|
||||
use nalgebra::Vector2;
|
||||
use rapier2d::dynamics::RigidBody;
|
||||
use rhai::{Array, CustomType, Dynamic, ImmutableString, TypeBuilder};
|
||||
use rhai::{Array, CustomType, Dynamic, ImmutableString, Map, TypeBuilder};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{functions::OutfitState, Color, UiVector};
|
||||
|
@ -94,14 +94,6 @@ impl CustomType for ShipState {
|
|||
s.get_content().thumbnail.index.clone().into()
|
||||
})
|
||||
.with_fn("landed_on", |s: &mut Self| s.landed_on())
|
||||
.with_fn("current_shields", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_shields()
|
||||
})
|
||||
.with_fn("total_hull", |s: &mut Self| s.get_content().hull)
|
||||
.with_fn("empty_mass", |s: &mut Self| s.get_content().mass)
|
||||
.with_fn("current_hull", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_hull()
|
||||
})
|
||||
.with_fn("get_size", |s: &mut Self| s.get_content().size)
|
||||
.with_fn("phys_uid", |s: &mut Self| format!("{}", s.get_ship().uid))
|
||||
.with_fn("get_pos", |s: &mut Self| {
|
||||
|
@ -114,7 +106,46 @@ impl CustomType for ShipState {
|
|||
Color::new(c[0], c[1], c[2], 1.0)
|
||||
})
|
||||
//
|
||||
// Stat getters
|
||||
// Ship stat getters
|
||||
//
|
||||
.with_fn("used_space", |s: &mut Self| {
|
||||
Map::from_iter(
|
||||
s.get_ship()
|
||||
.get_data()
|
||||
.get_outfits()
|
||||
.get_used_space()
|
||||
.to_hashmap()
|
||||
.iter()
|
||||
.map(|(k, v)| (ImmutableString::from(k).into(), Dynamic::from(*v as i64))),
|
||||
)
|
||||
})
|
||||
.with_fn("total_space", |s: &mut Self| {
|
||||
Map::from_iter(
|
||||
s.get_ship()
|
||||
.get_data()
|
||||
.get_outfits()
|
||||
.get_total_space()
|
||||
.to_hashmap()
|
||||
.iter()
|
||||
.map(|(k, v)| (ImmutableString::from(k).into(), Dynamic::from(*v as i64))),
|
||||
)
|
||||
})
|
||||
.with_fn("total_gun_points", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_outfits().total_gun_points() as i64
|
||||
})
|
||||
.with_fn("free_gun_points", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_outfits().free_gun_points() as i64
|
||||
})
|
||||
.with_fn("current_shields", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_shields()
|
||||
})
|
||||
.with_fn("total_hull", |s: &mut Self| s.get_content().hull)
|
||||
.with_fn("empty_mass", |s: &mut Self| s.get_content().mass)
|
||||
.with_fn("current_hull", |s: &mut Self| {
|
||||
s.get_ship().get_data().get_hull()
|
||||
})
|
||||
//
|
||||
// Outfit stat getters
|
||||
//
|
||||
.with_fn("stat_thrust", |s: &mut Self| {
|
||||
s.get_ship()
|
||||
|
@ -264,7 +295,12 @@ impl State {
|
|||
pub fn player_ship(&mut self) -> ShipState {
|
||||
ShipState {
|
||||
input: self.input.clone(),
|
||||
ship: self.input.player.ship.map(|x| PhysSimShipHandle(x)),
|
||||
ship: self
|
||||
.input
|
||||
.player
|
||||
.borrow()
|
||||
.ship
|
||||
.map(|x| PhysSimShipHandle(x)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -301,7 +301,7 @@ impl UiScriptExecutor {
|
|||
|
||||
// Send player state change events
|
||||
if {
|
||||
let player = input.player.ship;
|
||||
let player = input.player.borrow().ship;
|
||||
if let Some(player) = player {
|
||||
let ship = input.phys_img.get_ship(&PhysSimShipHandle(player)).unwrap();
|
||||
if self.last_player_state == 0
|
||||
|
|
|
@ -104,6 +104,7 @@ impl OutfitSet {
|
|||
if outfit.is_none() {
|
||||
*outfit = Some(o.clone());
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !added {
|
||||
|
@ -112,14 +113,15 @@ impl OutfitSet {
|
|||
}
|
||||
|
||||
self.used_space += o.space;
|
||||
|
||||
self.stats.add(&o.stats);
|
||||
|
||||
if o.stats.shield_generation != 0.0 {
|
||||
self.shield_generators.push(ShieldGenerator {
|
||||
outfit: o.clone(),
|
||||
delay: o.stats.shield_delay,
|
||||
generation: o.stats.shield_generation,
|
||||
});
|
||||
}
|
||||
|
||||
if self.outfits.contains_key(&o.index) {
|
||||
self.outfits.get_mut(&o.index).unwrap().1 += 1;
|
||||
|
@ -133,26 +135,32 @@ impl OutfitSet {
|
|||
pub(super) fn remove(&mut self, o: &Arc<Outfit>) -> OutfitRemoveResult {
|
||||
if !self.outfits.contains_key(&o.index) {
|
||||
return OutfitRemoveResult::NotExist;
|
||||
} else {
|
||||
}
|
||||
|
||||
let n = self.outfits.get_mut(&o.index).unwrap();
|
||||
if n.1 == 1u32 {
|
||||
self.outfits.remove(&o.index);
|
||||
} else {
|
||||
self.outfits.get_mut(&o.index).unwrap().1 -= 1;
|
||||
}
|
||||
|
||||
if o.gun.is_some() {
|
||||
let (_, x) = self
|
||||
.gun_points
|
||||
.iter_mut()
|
||||
.find(|(_, x)| x.is_some() && x.as_ref().unwrap().index == o.index)
|
||||
.unwrap();
|
||||
*x = None;
|
||||
}
|
||||
|
||||
self.used_space -= o.space;
|
||||
|
||||
self.stats.subtract(&o.stats);
|
||||
|
||||
{
|
||||
// This index will exist, since we checked the hashmap
|
||||
let index = self
|
||||
.shield_generators
|
||||
.iter()
|
||||
.position(|g| g.outfit.index == o.index)
|
||||
.unwrap();
|
||||
.position(|g| g.outfit.index == o.index);
|
||||
if let Some(index) = index {
|
||||
self.shield_generators.remove(index);
|
||||
}
|
||||
|
||||
|
@ -198,6 +206,29 @@ impl OutfitSet {
|
|||
&self.used_space
|
||||
}
|
||||
|
||||
/// Number of available (used & free) gun points
|
||||
pub fn total_gun_points(&self) -> usize {
|
||||
self.gun_points.len()
|
||||
}
|
||||
|
||||
/// Number of free gun points
|
||||
pub fn free_gun_points(&self) -> usize {
|
||||
self.iter_gun_points().filter(|(_, o)| o.is_none()).count()
|
||||
}
|
||||
|
||||
/// Does this set contain `count` of `outfit`?
|
||||
pub fn has_outfit(&self, outfit: &Arc<Outfit>, mut count: u32) -> bool {
|
||||
for i in self.iter_outfits() {
|
||||
if count <= 0 {
|
||||
return true;
|
||||
}
|
||||
if i.0.index == outfit.index {
|
||||
count -= 1;
|
||||
}
|
||||
}
|
||||
return count <= 0;
|
||||
}
|
||||
|
||||
/// Get the combined stats of all outfits in this set.
|
||||
/// There are two things to note here:
|
||||
/// First, shield_delay is always zero. That is handled
|
||||
|
|
|
@ -14,7 +14,7 @@ use rapier2d::{
|
|||
|
||||
use super::{autopilot, collapse::ShipCollapseSequence, controller::ShipController, ShipControls};
|
||||
use crate::{
|
||||
data::{ShipAutoPilot, ShipData, ShipPersonality, ShipState},
|
||||
data::{OutfitRemoveResult, ShipAutoPilot, ShipData, ShipPersonality, ShipState},
|
||||
phys::{
|
||||
get_phys_id,
|
||||
objects::{PhysEffect, PhysProjectile},
|
||||
|
@ -505,8 +505,8 @@ impl PhysShip {
|
|||
}
|
||||
|
||||
/// Add one outfit to this ship
|
||||
pub fn add_outfit(&mut self, o: Arc<Outfit>) {
|
||||
self.data.add_outfit(&o);
|
||||
pub fn add_outfit(&mut self, o: &Arc<Outfit>) {
|
||||
self.data.add_outfit(o);
|
||||
self.update_flares();
|
||||
}
|
||||
|
||||
|
@ -517,6 +517,13 @@ impl PhysShip {
|
|||
}
|
||||
self.update_flares();
|
||||
}
|
||||
|
||||
/// Remove one outfit from this ship
|
||||
pub fn remove_outfit(&mut self, o: &Arc<Outfit>) -> OutfitRemoveResult {
|
||||
let r = self.data.remove_outfit(o);
|
||||
self.update_flares();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/// Public immutable
|
||||
|
|
|
@ -192,7 +192,7 @@ impl PhysSim {
|
|||
}
|
||||
|
||||
/// Update a player ship's controls
|
||||
pub fn apply_directive(&mut self, directive: PlayerDirective, player: &PlayerAgent) {
|
||||
pub fn apply_directive(&mut self, directive: PlayerDirective, player: &mut PlayerAgent) {
|
||||
if player.ship.is_none() {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use galactica_content::Outfit;
|
||||
|
||||
/// An action the player wants to take in the game.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PlayerDirective {
|
||||
|
@ -21,4 +25,26 @@ pub enum PlayerDirective {
|
|||
|
||||
/// Take off from the planet we're landed on
|
||||
UnLand,
|
||||
|
||||
/// Buy an outfit.
|
||||
/// This directive is ignored if the player does not have enough
|
||||
/// credits to buy the given number of outfits.
|
||||
BuyOutfit {
|
||||
/// The outfit to buy
|
||||
outfit: Arc<Outfit>,
|
||||
|
||||
/// How many of this outfit to buy
|
||||
count: u32,
|
||||
},
|
||||
|
||||
/// Sell an outfit.
|
||||
/// This directive is ignored if the player does not have enough
|
||||
/// outfits to sell.
|
||||
SellOutfit {
|
||||
/// The outfit to sell
|
||||
outfit: Arc<Outfit>,
|
||||
|
||||
/// How many of this outfit to sell
|
||||
count: u32,
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue