Move state management out of main file
This commit is contained in:
parent
878ee5b480
commit
485151e37c
521
src/main.rs
521
src/main.rs
@ -23,32 +23,21 @@ mod rex_assets;
|
|||||||
pub mod saveload_system;
|
pub mod saveload_system;
|
||||||
mod spatial;
|
mod spatial;
|
||||||
mod spawner;
|
mod spawner;
|
||||||
|
mod state;
|
||||||
mod trigger_system;
|
mod trigger_system;
|
||||||
mod visibility_system;
|
mod visibility_system;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use ::rltk::{GameState, Point, RandomNumberGenerator, Rltk};
|
use ::rltk::{Point, RandomNumberGenerator};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
use ::specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
|
use ::specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
|
||||||
use components::*;
|
use components::*;
|
||||||
use damage_system::DamageSystem;
|
|
||||||
pub use game_log::GameLog;
|
pub use game_log::GameLog;
|
||||||
use gui::{show_cheat_mode, CheatMenuResult};
|
|
||||||
use hunger_system::HungerSystem;
|
|
||||||
use inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem};
|
|
||||||
use lighting_system::LightingSystem;
|
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
use map_indexing_system::MapIndexingSystem;
|
|
||||||
use melee_combat_system::MeleeCombatSystem;
|
|
||||||
use movement_system::MovementSystem;
|
|
||||||
use particle_system::ParticleSpawnSystem;
|
|
||||||
use player::*;
|
|
||||||
use raws::*;
|
|
||||||
pub use rect::Rect;
|
pub use rect::Rect;
|
||||||
use trigger_system::TriggerSystem;
|
pub use state::*;
|
||||||
use visibility_system::VisibilitySystem;
|
|
||||||
|
|
||||||
/// Cut down on the amount of syntax to register components
|
/// Cut down on the amount of syntax to register components
|
||||||
macro_rules! register {
|
macro_rules! register {
|
||||||
@ -61,510 +50,6 @@ macro_rules! register {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHOW_MAPGEN_VISUALIZER: bool = false;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
|
||||||
pub enum VendorMode {
|
|
||||||
Buy,
|
|
||||||
Sell,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
|
||||||
pub enum RunState {
|
|
||||||
AwaitingInput,
|
|
||||||
PreRun,
|
|
||||||
Ticking,
|
|
||||||
ShowInventory,
|
|
||||||
ShowDropItem,
|
|
||||||
ShowTargeting {
|
|
||||||
range: i32,
|
|
||||||
item: Entity,
|
|
||||||
},
|
|
||||||
MainMenu {
|
|
||||||
menu_selection: gui::MainMenuSelection,
|
|
||||||
},
|
|
||||||
SaveGame,
|
|
||||||
NextLevel,
|
|
||||||
PreviousLevel,
|
|
||||||
TownPortal,
|
|
||||||
ShowRemoveItem,
|
|
||||||
GameOver,
|
|
||||||
MagicMapReveal {
|
|
||||||
row: i32,
|
|
||||||
},
|
|
||||||
MapGeneration,
|
|
||||||
ShowCheatMenu,
|
|
||||||
ShowVendor {
|
|
||||||
vendor: Entity,
|
|
||||||
mode: VendorMode,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct State {
|
|
||||||
pub ecs: World,
|
|
||||||
mapgen_next_state: Option<RunState>,
|
|
||||||
mapgen_history: Vec<Map>,
|
|
||||||
mapgen_index: usize,
|
|
||||||
mapgen_timer: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn new() -> Self {
|
|
||||||
State {
|
|
||||||
ecs: World::new(),
|
|
||||||
mapgen_next_state: Some(RunState::MainMenu {
|
|
||||||
menu_selection: gui::MainMenuSelection::NewGame,
|
|
||||||
}),
|
|
||||||
mapgen_index: 0,
|
|
||||||
mapgen_history: Vec::new(),
|
|
||||||
mapgen_timer: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_systems(&mut self) {
|
|
||||||
let mut mapindex = MapIndexingSystem {};
|
|
||||||
mapindex.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut vis = VisibilitySystem {};
|
|
||||||
vis.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut encumbrance = ai::EncumbranceSystem {};
|
|
||||||
encumbrance.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut initiative = ai::InitiativeSystem {};
|
|
||||||
initiative.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut turnstatus = ai::TurnStatusSystem {};
|
|
||||||
turnstatus.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut quipper = ai::QuipSystem {};
|
|
||||||
quipper.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut adjacent = ai::AdjacentAI {};
|
|
||||||
adjacent.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut visible = ai::VisibleAI {};
|
|
||||||
visible.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut approach = ai::ApproachAI {};
|
|
||||||
approach.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut flee = ai::FleeAI {};
|
|
||||||
flee.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut chase = ai::ChaseAI {};
|
|
||||||
chase.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut defaultmove = ai::DefaultMoveAI {};
|
|
||||||
defaultmove.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut moving = MovementSystem {};
|
|
||||||
moving.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut triggers = TriggerSystem {};
|
|
||||||
triggers.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut melee = MeleeCombatSystem {};
|
|
||||||
melee.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut damage = DamageSystem {};
|
|
||||||
damage.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut pickup = ItemCollectionSystem {};
|
|
||||||
pickup.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut items = ItemUseSystem {};
|
|
||||||
items.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut drop_items = ItemDropSystem {};
|
|
||||||
drop_items.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut item_remove = ItemRemoveSystem {};
|
|
||||||
item_remove.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut hunger = HungerSystem {};
|
|
||||||
hunger.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut particles = ParticleSpawnSystem {};
|
|
||||||
particles.run_now(&self.ecs);
|
|
||||||
|
|
||||||
let mut lighting = LightingSystem {};
|
|
||||||
lighting.run_now(&self.ecs);
|
|
||||||
|
|
||||||
self.ecs.maintain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GameState for State {
|
|
||||||
fn tick(&mut self, ctx: &mut Rltk) {
|
|
||||||
let mut newrunstate;
|
|
||||||
{
|
|
||||||
let runstate = self.ecs.fetch::<RunState>();
|
|
||||||
newrunstate = *runstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.cls();
|
|
||||||
particle_system::cull_dead_particles(&mut self.ecs, ctx);
|
|
||||||
|
|
||||||
match newrunstate {
|
|
||||||
RunState::MainMenu { .. } => {}
|
|
||||||
RunState::GameOver { .. } => {}
|
|
||||||
_ => {
|
|
||||||
camera::render_camera(&self.ecs, ctx);
|
|
||||||
gui::draw_ui(&self.ecs, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match newrunstate {
|
|
||||||
RunState::MapGeneration => {
|
|
||||||
if !SHOW_MAPGEN_VISUALIZER {
|
|
||||||
newrunstate = self.mapgen_next_state.unwrap();
|
|
||||||
}
|
|
||||||
ctx.cls();
|
|
||||||
if self.mapgen_index < self.mapgen_history.len() {
|
|
||||||
camera::render_debug_map(&self.mapgen_history[self.mapgen_index], ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mapgen_timer += ctx.frame_time_ms;
|
|
||||||
if self.mapgen_timer > 300.0 {
|
|
||||||
self.mapgen_timer = 0.0;
|
|
||||||
self.mapgen_index += 1;
|
|
||||||
if self.mapgen_index >= self.mapgen_history.len() {
|
|
||||||
newrunstate = self.mapgen_next_state.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::PreRun => {
|
|
||||||
self.run_systems();
|
|
||||||
self.ecs.maintain();
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
}
|
|
||||||
RunState::AwaitingInput => {
|
|
||||||
newrunstate = player_input(self, ctx);
|
|
||||||
}
|
|
||||||
RunState::Ticking => {
|
|
||||||
while newrunstate == RunState::Ticking {
|
|
||||||
self.run_systems();
|
|
||||||
self.ecs.maintain();
|
|
||||||
|
|
||||||
newrunstate = match *self.ecs.fetch::<RunState>() {
|
|
||||||
RunState::AwaitingInput => RunState::AwaitingInput,
|
|
||||||
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
|
||||||
RunState::TownPortal => RunState::TownPortal,
|
|
||||||
_ => RunState::Ticking,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::ShowInventory => {
|
|
||||||
let result = gui::show_inventory(self, ctx);
|
|
||||||
match result.0 {
|
|
||||||
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
|
||||||
gui::ItemMenuResult::Selected => {
|
|
||||||
let item_entity = result.1.unwrap();
|
|
||||||
let is_ranged = self.ecs.read_storage::<Ranged>();
|
|
||||||
|
|
||||||
if let Some(is_item_ranged) = is_ranged.get(item_entity) {
|
|
||||||
newrunstate = RunState::ShowTargeting {
|
|
||||||
range: is_item_ranged.range,
|
|
||||||
item: item_entity,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
|
||||||
intent
|
|
||||||
.insert(
|
|
||||||
*self.ecs.fetch::<Entity>(),
|
|
||||||
WantsToUseItem {
|
|
||||||
item: item_entity,
|
|
||||||
target: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("failed to add intent to use item");
|
|
||||||
|
|
||||||
newrunstate = RunState::Ticking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::ShowDropItem => {
|
|
||||||
let result = gui::drop_item_menu(self, ctx);
|
|
||||||
match result.0 {
|
|
||||||
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
|
||||||
gui::ItemMenuResult::Selected => {
|
|
||||||
let item_entity = result.1.unwrap();
|
|
||||||
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
|
|
||||||
intent
|
|
||||||
.insert(
|
|
||||||
*self.ecs.fetch::<Entity>(),
|
|
||||||
WantsToDropItem { item: item_entity },
|
|
||||||
)
|
|
||||||
.expect("failed to add intent to drop item");
|
|
||||||
|
|
||||||
newrunstate = RunState::Ticking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::ShowRemoveItem => {
|
|
||||||
let result = gui::remove_item_menu(self, ctx);
|
|
||||||
match result.0 {
|
|
||||||
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
|
||||||
gui::ItemMenuResult::Selected => {
|
|
||||||
let item_entity = result.1.unwrap();
|
|
||||||
let mut intent = self.ecs.write_storage::<WantsToRemoveItem>();
|
|
||||||
intent
|
|
||||||
.insert(
|
|
||||||
*self.ecs.fetch::<Entity>(),
|
|
||||||
WantsToRemoveItem { item: item_entity },
|
|
||||||
)
|
|
||||||
.expect("Unable to insert intent to remove item");
|
|
||||||
|
|
||||||
newrunstate = RunState::Ticking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::ShowTargeting { range, item } => {
|
|
||||||
let result = gui::ranged_target(self, ctx, range);
|
|
||||||
match result.0 {
|
|
||||||
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
|
||||||
gui::ItemMenuResult::Selected => {
|
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
|
||||||
|
|
||||||
intent
|
|
||||||
.insert(
|
|
||||||
*self.ecs.fetch::<Entity>(),
|
|
||||||
WantsToUseItem {
|
|
||||||
item,
|
|
||||||
target: result.1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("failed to add intent to use item");
|
|
||||||
|
|
||||||
newrunstate = RunState::Ticking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::MainMenu { .. } => match gui::main_menu(self, ctx) {
|
|
||||||
gui::MainMenuResult::NoSelection { selected } => {
|
|
||||||
newrunstate = RunState::MainMenu {
|
|
||||||
menu_selection: selected,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gui::MainMenuResult::Selected { selected } => match selected {
|
|
||||||
gui::MainMenuSelection::NewGame => newrunstate = RunState::PreRun,
|
|
||||||
gui::MainMenuSelection::LoadGame => {
|
|
||||||
saveload_system::load_game(&mut self.ecs);
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
saveload_system::delete_save();
|
|
||||||
}
|
|
||||||
gui::MainMenuSelection::Quit => {
|
|
||||||
::std::process::exit(0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
RunState::GameOver => match gui::game_over(ctx) {
|
|
||||||
gui::GameOverResult::NoSelection => {}
|
|
||||||
gui::GameOverResult::QuitToMenu => {
|
|
||||||
self.game_over_cleanup();
|
|
||||||
newrunstate = RunState::MainMenu {
|
|
||||||
menu_selection: gui::MainMenuSelection::NewGame,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RunState::SaveGame => {
|
|
||||||
saveload_system::save_game(&mut self.ecs);
|
|
||||||
|
|
||||||
newrunstate = RunState::MainMenu {
|
|
||||||
menu_selection: gui::MainMenuSelection::LoadGame,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::NextLevel => {
|
|
||||||
self.goto_level(1);
|
|
||||||
newrunstate = RunState::PreRun;
|
|
||||||
}
|
|
||||||
RunState::PreviousLevel => {
|
|
||||||
self.goto_level(-1);
|
|
||||||
self.mapgen_next_state = Some(RunState::PreRun);
|
|
||||||
newrunstate = RunState::MapGeneration;
|
|
||||||
}
|
|
||||||
RunState::MagicMapReveal { row } => {
|
|
||||||
let mut map = self.ecs.fetch_mut::<Map>();
|
|
||||||
for x in 0..map.width {
|
|
||||||
let idx = map.xy_idx(x as i32, row);
|
|
||||||
map.revealed_tiles[idx] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if row == map.height - 1 {
|
|
||||||
newrunstate = RunState::Ticking;
|
|
||||||
} else {
|
|
||||||
newrunstate = RunState::MagicMapReveal { row: row + 1 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::ShowCheatMenu => match show_cheat_mode(self, ctx) {
|
|
||||||
CheatMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
CheatMenuResult::NoResponse => {}
|
|
||||||
CheatMenuResult::TeleportToExit => {
|
|
||||||
self.goto_level(1);
|
|
||||||
self.mapgen_next_state = Some(RunState::PreRun);
|
|
||||||
|
|
||||||
newrunstate = RunState::MapGeneration
|
|
||||||
}
|
|
||||||
CheatMenuResult::Heal => {
|
|
||||||
let player = self.ecs.fetch::<Entity>();
|
|
||||||
let mut pools = self.ecs.write_storage::<Pools>();
|
|
||||||
let mut player_pools = pools.get_mut(*player).unwrap();
|
|
||||||
player_pools.hit_points.current = player_pools.hit_points.max;
|
|
||||||
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
}
|
|
||||||
CheatMenuResult::Reveal => {
|
|
||||||
let mut map = self.ecs.fetch_mut::<Map>();
|
|
||||||
for v in map.revealed_tiles.iter_mut() {
|
|
||||||
*v = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
}
|
|
||||||
CheatMenuResult::GodMode => {
|
|
||||||
let player = self.ecs.fetch::<Entity>();
|
|
||||||
let mut pools = self.ecs.write_storage::<Pools>();
|
|
||||||
let mut player_pools = pools.get_mut(*player).unwrap();
|
|
||||||
player_pools.god_mode = true;
|
|
||||||
|
|
||||||
newrunstate = RunState::AwaitingInput;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RunState::ShowVendor { vendor, mode } => {
|
|
||||||
let result = gui::show_vendor_menu(self, ctx, vendor, mode);
|
|
||||||
match result.0 {
|
|
||||||
gui::VendorResult::Cancel => newrunstate = RunState::AwaitingInput,
|
|
||||||
gui::VendorResult::NoResponse => {}
|
|
||||||
gui::VendorResult::Sell => {
|
|
||||||
let price = self
|
|
||||||
.ecs
|
|
||||||
.read_storage::<Item>()
|
|
||||||
.get(result.1.unwrap())
|
|
||||||
.unwrap()
|
|
||||||
.base_value
|
|
||||||
* 0.8;
|
|
||||||
self.ecs
|
|
||||||
.write_storage::<Pools>()
|
|
||||||
.get_mut(*self.ecs.fetch::<Entity>())
|
|
||||||
.unwrap()
|
|
||||||
.gold += price;
|
|
||||||
self.ecs
|
|
||||||
.delete_entity(result.1.unwrap())
|
|
||||||
.expect("Unable to delete sold item");
|
|
||||||
}
|
|
||||||
gui::VendorResult::Buy => {
|
|
||||||
let tag = result.2.unwrap();
|
|
||||||
let price = result.3.unwrap();
|
|
||||||
let mut pools = self.ecs.write_storage::<Pools>();
|
|
||||||
let player_pools = pools.get_mut(*self.ecs.fetch::<Entity>()).unwrap();
|
|
||||||
if player_pools.gold >= price {
|
|
||||||
player_pools.gold -= price;
|
|
||||||
std::mem::drop(pools);
|
|
||||||
|
|
||||||
let player_entity = *self.ecs.fetch::<Entity>();
|
|
||||||
spawn_named_item(
|
|
||||||
&RAWS.lock().unwrap(),
|
|
||||||
&mut self.ecs,
|
|
||||||
&tag,
|
|
||||||
SpawnType::Carried { by: player_entity },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gui::VendorResult::BuyMode => {
|
|
||||||
newrunstate = RunState::ShowVendor {
|
|
||||||
vendor,
|
|
||||||
mode: VendorMode::Buy,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gui::VendorResult::SellMode => {
|
|
||||||
newrunstate = RunState::ShowVendor {
|
|
||||||
vendor,
|
|
||||||
mode: VendorMode::Sell,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RunState::TownPortal => {
|
|
||||||
// Spawn the portal
|
|
||||||
spawner::spawn_town_portal(&mut self.ecs);
|
|
||||||
|
|
||||||
// Transition
|
|
||||||
let map_depth = self.ecs.fetch::<Map>().depth;
|
|
||||||
let destination_offset = 0 - (map_depth - 1);
|
|
||||||
self.goto_level(destination_offset);
|
|
||||||
self.mapgen_next_state = Some(RunState::PreRun);
|
|
||||||
|
|
||||||
newrunstate = RunState::MapGeneration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut runwriter = self.ecs.write_resource::<RunState>();
|
|
||||||
*runwriter = newrunstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
damage_system::delete_the_dead(&mut self.ecs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn goto_level(&mut self, offset: i32) {
|
|
||||||
freeze_level_entities(&mut self.ecs);
|
|
||||||
|
|
||||||
// Build a new map and place the player
|
|
||||||
let current_depth = self.ecs.fetch::<Map>().depth;
|
|
||||||
self.generate_world_map(current_depth + offset, offset);
|
|
||||||
|
|
||||||
// Notify the player
|
|
||||||
let mut gamelog = self.ecs.fetch_mut::<GameLog>();
|
|
||||||
gamelog.append("You change level.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn game_over_cleanup(&mut self) {
|
|
||||||
// Delete everything
|
|
||||||
let mut to_delete = Vec::new();
|
|
||||||
for e in self.ecs.entities().join() {
|
|
||||||
to_delete.push(e);
|
|
||||||
}
|
|
||||||
for del in to_delete.iter() {
|
|
||||||
self.ecs
|
|
||||||
.delete_entity(*del)
|
|
||||||
.expect("Failed to delete entity");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn a new player
|
|
||||||
{
|
|
||||||
let player_entity = spawner::player(&mut self.ecs, 0, 0);
|
|
||||||
let mut player_entity_writer = self.ecs.write_resource::<Entity>();
|
|
||||||
*player_entity_writer = player_entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the world maps
|
|
||||||
self.ecs.insert(map::MasterDungeonMap::new());
|
|
||||||
|
|
||||||
// Build a new map and place the player
|
|
||||||
self.generate_world_map(1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_world_map(&mut self, new_depth: i32, offset: i32) {
|
|
||||||
self.mapgen_index = 0;
|
|
||||||
self.mapgen_timer = 0.0;
|
|
||||||
self.mapgen_history.clear();
|
|
||||||
|
|
||||||
if let Some(history) = map::level_transition(&mut self.ecs, new_depth, offset) {
|
|
||||||
self.mapgen_history = history;
|
|
||||||
} else {
|
|
||||||
map::thaw_level_entities(&mut self.ecs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> ::rltk::BError {
|
fn main() -> ::rltk::BError {
|
||||||
let context = ::rltk::RltkBuilder::simple(80, 60)
|
let context = ::rltk::RltkBuilder::simple(80, 60)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
533
src/state.rs
Normal file
533
src/state.rs
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
use ::rltk::{GameState, Point, Rltk};
|
||||||
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::*;
|
||||||
|
use crate::damage_system::{self, DamageSystem};
|
||||||
|
use crate::game_log::GameLog;
|
||||||
|
use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection};
|
||||||
|
use crate::hunger_system::HungerSystem;
|
||||||
|
use crate::inventory_system::{
|
||||||
|
ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem,
|
||||||
|
};
|
||||||
|
use crate::lighting_system::LightingSystem;
|
||||||
|
use crate::map::{self, *};
|
||||||
|
use crate::map_indexing_system::MapIndexingSystem;
|
||||||
|
use crate::melee_combat_system::MeleeCombatSystem;
|
||||||
|
use crate::movement_system::MovementSystem;
|
||||||
|
use crate::particle_system::{self, ParticleSpawnSystem};
|
||||||
|
use crate::player::*;
|
||||||
|
use crate::raws::*;
|
||||||
|
use crate::trigger_system::TriggerSystem;
|
||||||
|
use crate::visibility_system::VisibilitySystem;
|
||||||
|
use crate::{ai, camera, saveload_system, spawner};
|
||||||
|
|
||||||
|
pub const SHOW_MAPGEN_VISUALIZER: bool = false;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
pub enum VendorMode {
|
||||||
|
Buy,
|
||||||
|
Sell,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
pub enum RunState {
|
||||||
|
AwaitingInput,
|
||||||
|
PreRun,
|
||||||
|
Ticking,
|
||||||
|
ShowInventory,
|
||||||
|
ShowDropItem,
|
||||||
|
ShowTargeting { range: i32, item: Entity },
|
||||||
|
MainMenu { menu_selection: MainMenuSelection },
|
||||||
|
SaveGame,
|
||||||
|
NextLevel,
|
||||||
|
PreviousLevel,
|
||||||
|
TownPortal,
|
||||||
|
ShowRemoveItem,
|
||||||
|
GameOver,
|
||||||
|
MagicMapReveal { row: i32 },
|
||||||
|
MapGeneration,
|
||||||
|
ShowCheatMenu,
|
||||||
|
ShowVendor { vendor: Entity, mode: VendorMode },
|
||||||
|
TeleportingToOtherLevel { x: i32, y: i32, depth: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
pub ecs: World,
|
||||||
|
mapgen_next_state: Option<RunState>,
|
||||||
|
mapgen_history: Vec<Map>,
|
||||||
|
mapgen_index: usize,
|
||||||
|
mapgen_timer: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
State {
|
||||||
|
ecs: World::new(),
|
||||||
|
mapgen_next_state: Some(RunState::MainMenu {
|
||||||
|
menu_selection: MainMenuSelection::NewGame,
|
||||||
|
}),
|
||||||
|
mapgen_index: 0,
|
||||||
|
mapgen_history: Vec::new(),
|
||||||
|
mapgen_timer: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_systems(&mut self) {
|
||||||
|
let mut mapindex = MapIndexingSystem {};
|
||||||
|
mapindex.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut vis = VisibilitySystem {};
|
||||||
|
vis.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut encumbrance = ai::EncumbranceSystem {};
|
||||||
|
encumbrance.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut initiative = ai::InitiativeSystem {};
|
||||||
|
initiative.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut turnstatus = ai::TurnStatusSystem {};
|
||||||
|
turnstatus.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut quipper = ai::QuipSystem {};
|
||||||
|
quipper.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut adjacent = ai::AdjacentAI {};
|
||||||
|
adjacent.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut visible = ai::VisibleAI {};
|
||||||
|
visible.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut approach = ai::ApproachAI {};
|
||||||
|
approach.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut flee = ai::FleeAI {};
|
||||||
|
flee.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut chase = ai::ChaseAI {};
|
||||||
|
chase.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut defaultmove = ai::DefaultMoveAI {};
|
||||||
|
defaultmove.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut moving = MovementSystem {};
|
||||||
|
moving.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut triggers = TriggerSystem {};
|
||||||
|
triggers.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut melee = MeleeCombatSystem {};
|
||||||
|
melee.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut damage = DamageSystem {};
|
||||||
|
damage.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut pickup = ItemCollectionSystem {};
|
||||||
|
pickup.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut items = ItemUseSystem {};
|
||||||
|
items.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut drop_items = ItemDropSystem {};
|
||||||
|
drop_items.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut item_remove = ItemRemoveSystem {};
|
||||||
|
item_remove.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut hunger = HungerSystem {};
|
||||||
|
hunger.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut particles = ParticleSpawnSystem {};
|
||||||
|
particles.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut lighting = LightingSystem {};
|
||||||
|
lighting.run_now(&self.ecs);
|
||||||
|
|
||||||
|
self.ecs.maintain();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn goto_level(&mut self, offset: i32) {
|
||||||
|
freeze_level_entities(&mut self.ecs);
|
||||||
|
|
||||||
|
// Build a new map and place the player
|
||||||
|
let current_depth = self.ecs.fetch::<Map>().depth;
|
||||||
|
self.generate_world_map(current_depth + offset, offset);
|
||||||
|
|
||||||
|
// Notify the player
|
||||||
|
let mut gamelog = self.ecs.fetch_mut::<GameLog>();
|
||||||
|
gamelog.append("You change level.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn game_over_cleanup(&mut self) {
|
||||||
|
// Delete everything
|
||||||
|
let mut to_delete = Vec::new();
|
||||||
|
for e in self.ecs.entities().join() {
|
||||||
|
to_delete.push(e);
|
||||||
|
}
|
||||||
|
for del in to_delete.iter() {
|
||||||
|
self.ecs
|
||||||
|
.delete_entity(*del)
|
||||||
|
.expect("Failed to delete entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn a new player
|
||||||
|
{
|
||||||
|
let player_entity = spawner::player(&mut self.ecs, 0, 0);
|
||||||
|
let mut player_entity_writer = self.ecs.write_resource::<Entity>();
|
||||||
|
*player_entity_writer = player_entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the world maps
|
||||||
|
self.ecs.insert(map::MasterDungeonMap::new());
|
||||||
|
|
||||||
|
// Build a new map and place the player
|
||||||
|
self.generate_world_map(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_world_map(&mut self, new_depth: i32, offset: i32) {
|
||||||
|
self.mapgen_index = 0;
|
||||||
|
self.mapgen_timer = 0.0;
|
||||||
|
self.mapgen_history.clear();
|
||||||
|
|
||||||
|
if let Some(history) = map::level_transition(&mut self.ecs, new_depth, offset) {
|
||||||
|
self.mapgen_history = history;
|
||||||
|
} else {
|
||||||
|
map::thaw_level_entities(&mut self.ecs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameState for State {
|
||||||
|
fn tick(&mut self, ctx: &mut Rltk) {
|
||||||
|
let mut newrunstate;
|
||||||
|
{
|
||||||
|
let runstate = self.ecs.fetch::<RunState>();
|
||||||
|
newrunstate = *runstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cls();
|
||||||
|
particle_system::cull_dead_particles(&mut self.ecs, ctx);
|
||||||
|
|
||||||
|
match newrunstate {
|
||||||
|
RunState::MainMenu { .. } => {}
|
||||||
|
RunState::GameOver { .. } => {}
|
||||||
|
_ => {
|
||||||
|
camera::render_camera(&self.ecs, ctx);
|
||||||
|
gui::draw_ui(&self.ecs, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match newrunstate {
|
||||||
|
RunState::MapGeneration => {
|
||||||
|
if !SHOW_MAPGEN_VISUALIZER {
|
||||||
|
newrunstate = self.mapgen_next_state.unwrap();
|
||||||
|
}
|
||||||
|
ctx.cls();
|
||||||
|
if self.mapgen_index < self.mapgen_history.len() {
|
||||||
|
camera::render_debug_map(&self.mapgen_history[self.mapgen_index], ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mapgen_timer += ctx.frame_time_ms;
|
||||||
|
if self.mapgen_timer > 300.0 {
|
||||||
|
self.mapgen_timer = 0.0;
|
||||||
|
self.mapgen_index += 1;
|
||||||
|
if self.mapgen_index >= self.mapgen_history.len() {
|
||||||
|
newrunstate = self.mapgen_next_state.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::PreRun => {
|
||||||
|
self.run_systems();
|
||||||
|
self.ecs.maintain();
|
||||||
|
newrunstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
RunState::AwaitingInput => {
|
||||||
|
newrunstate = player_input(self, ctx);
|
||||||
|
}
|
||||||
|
RunState::Ticking => {
|
||||||
|
while newrunstate == RunState::Ticking {
|
||||||
|
self.run_systems();
|
||||||
|
self.ecs.maintain();
|
||||||
|
|
||||||
|
newrunstate = match *self.ecs.fetch::<RunState>() {
|
||||||
|
RunState::AwaitingInput => RunState::AwaitingInput,
|
||||||
|
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
||||||
|
RunState::TownPortal => RunState::TownPortal,
|
||||||
|
RunState::TeleportingToOtherLevel { x, y, depth } => {
|
||||||
|
RunState::TeleportingToOtherLevel { x, y, depth }
|
||||||
|
}
|
||||||
|
_ => RunState::Ticking,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::ShowInventory => {
|
||||||
|
let result = gui::show_inventory(self, ctx);
|
||||||
|
match result.0 {
|
||||||
|
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
|
gui::ItemMenuResult::Selected => {
|
||||||
|
let item_entity = result.1.unwrap();
|
||||||
|
let is_ranged = self.ecs.read_storage::<Ranged>();
|
||||||
|
|
||||||
|
if let Some(is_item_ranged) = is_ranged.get(item_entity) {
|
||||||
|
newrunstate = RunState::ShowTargeting {
|
||||||
|
range: is_item_ranged.range,
|
||||||
|
item: item_entity,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
|
intent
|
||||||
|
.insert(
|
||||||
|
*self.ecs.fetch::<Entity>(),
|
||||||
|
WantsToUseItem {
|
||||||
|
item: item_entity,
|
||||||
|
target: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("failed to add intent to use item");
|
||||||
|
|
||||||
|
newrunstate = RunState::Ticking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::ShowDropItem => {
|
||||||
|
let result = gui::drop_item_menu(self, ctx);
|
||||||
|
match result.0 {
|
||||||
|
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
|
gui::ItemMenuResult::Selected => {
|
||||||
|
let item_entity = result.1.unwrap();
|
||||||
|
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
|
||||||
|
intent
|
||||||
|
.insert(
|
||||||
|
*self.ecs.fetch::<Entity>(),
|
||||||
|
WantsToDropItem { item: item_entity },
|
||||||
|
)
|
||||||
|
.expect("failed to add intent to drop item");
|
||||||
|
|
||||||
|
newrunstate = RunState::Ticking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::ShowRemoveItem => {
|
||||||
|
let result = gui::remove_item_menu(self, ctx);
|
||||||
|
match result.0 {
|
||||||
|
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
|
gui::ItemMenuResult::Selected => {
|
||||||
|
let item_entity = result.1.unwrap();
|
||||||
|
let mut intent = self.ecs.write_storage::<WantsToRemoveItem>();
|
||||||
|
intent
|
||||||
|
.insert(
|
||||||
|
*self.ecs.fetch::<Entity>(),
|
||||||
|
WantsToRemoveItem { item: item_entity },
|
||||||
|
)
|
||||||
|
.expect("Unable to insert intent to remove item");
|
||||||
|
|
||||||
|
newrunstate = RunState::Ticking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::ShowTargeting { range, item } => {
|
||||||
|
let result = gui::ranged_target(self, ctx, range);
|
||||||
|
match result.0 {
|
||||||
|
gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
|
gui::ItemMenuResult::Selected => {
|
||||||
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
|
|
||||||
|
intent
|
||||||
|
.insert(
|
||||||
|
*self.ecs.fetch::<Entity>(),
|
||||||
|
WantsToUseItem {
|
||||||
|
item,
|
||||||
|
target: result.1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("failed to add intent to use item");
|
||||||
|
|
||||||
|
newrunstate = RunState::Ticking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::MainMenu { .. } => match gui::main_menu(self, ctx) {
|
||||||
|
gui::MainMenuResult::NoSelection { selected } => {
|
||||||
|
newrunstate = RunState::MainMenu {
|
||||||
|
menu_selection: selected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gui::MainMenuResult::Selected { selected } => match selected {
|
||||||
|
gui::MainMenuSelection::NewGame => newrunstate = RunState::PreRun,
|
||||||
|
gui::MainMenuSelection::LoadGame => {
|
||||||
|
saveload_system::load_game(&mut self.ecs);
|
||||||
|
newrunstate = RunState::AwaitingInput;
|
||||||
|
saveload_system::delete_save();
|
||||||
|
}
|
||||||
|
gui::MainMenuSelection::Quit => {
|
||||||
|
::std::process::exit(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RunState::GameOver => match gui::game_over(ctx) {
|
||||||
|
gui::GameOverResult::NoSelection => {}
|
||||||
|
gui::GameOverResult::QuitToMenu => {
|
||||||
|
self.game_over_cleanup();
|
||||||
|
newrunstate = RunState::MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection::NewGame,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RunState::SaveGame => {
|
||||||
|
saveload_system::save_game(&mut self.ecs);
|
||||||
|
|
||||||
|
newrunstate = RunState::MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection::LoadGame,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::NextLevel => {
|
||||||
|
self.goto_level(1);
|
||||||
|
newrunstate = RunState::PreRun;
|
||||||
|
}
|
||||||
|
RunState::PreviousLevel => {
|
||||||
|
self.goto_level(-1);
|
||||||
|
self.mapgen_next_state = Some(RunState::PreRun);
|
||||||
|
newrunstate = RunState::MapGeneration;
|
||||||
|
}
|
||||||
|
RunState::MagicMapReveal { row } => {
|
||||||
|
let mut map = self.ecs.fetch_mut::<Map>();
|
||||||
|
for x in 0..map.width {
|
||||||
|
let idx = map.xy_idx(x as i32, row);
|
||||||
|
map.revealed_tiles[idx] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if row == map.height - 1 {
|
||||||
|
newrunstate = RunState::Ticking;
|
||||||
|
} else {
|
||||||
|
newrunstate = RunState::MagicMapReveal { row: row + 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::ShowCheatMenu => match show_cheat_mode(self, ctx) {
|
||||||
|
CheatMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
CheatMenuResult::NoResponse => {}
|
||||||
|
CheatMenuResult::TeleportToExit => {
|
||||||
|
self.goto_level(1);
|
||||||
|
self.mapgen_next_state = Some(RunState::PreRun);
|
||||||
|
|
||||||
|
newrunstate = RunState::MapGeneration
|
||||||
|
}
|
||||||
|
CheatMenuResult::Heal => {
|
||||||
|
let player = self.ecs.fetch::<Entity>();
|
||||||
|
let mut pools = self.ecs.write_storage::<Pools>();
|
||||||
|
let mut player_pools = pools.get_mut(*player).unwrap();
|
||||||
|
player_pools.hit_points.current = player_pools.hit_points.max;
|
||||||
|
|
||||||
|
newrunstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
CheatMenuResult::Reveal => {
|
||||||
|
let mut map = self.ecs.fetch_mut::<Map>();
|
||||||
|
for v in map.revealed_tiles.iter_mut() {
|
||||||
|
*v = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
newrunstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
CheatMenuResult::GodMode => {
|
||||||
|
let player = self.ecs.fetch::<Entity>();
|
||||||
|
let mut pools = self.ecs.write_storage::<Pools>();
|
||||||
|
let mut player_pools = pools.get_mut(*player).unwrap();
|
||||||
|
player_pools.god_mode = true;
|
||||||
|
|
||||||
|
newrunstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RunState::ShowVendor { vendor, mode } => {
|
||||||
|
let result = gui::show_vendor_menu(self, ctx, vendor, mode);
|
||||||
|
match result.0 {
|
||||||
|
gui::VendorResult::Cancel => newrunstate = RunState::AwaitingInput,
|
||||||
|
gui::VendorResult::NoResponse => {}
|
||||||
|
gui::VendorResult::Sell => {
|
||||||
|
let price = self
|
||||||
|
.ecs
|
||||||
|
.read_storage::<Item>()
|
||||||
|
.get(result.1.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.base_value
|
||||||
|
* 0.8;
|
||||||
|
self.ecs
|
||||||
|
.write_storage::<Pools>()
|
||||||
|
.get_mut(*self.ecs.fetch::<Entity>())
|
||||||
|
.unwrap()
|
||||||
|
.gold += price;
|
||||||
|
self.ecs
|
||||||
|
.delete_entity(result.1.unwrap())
|
||||||
|
.expect("Unable to delete sold item");
|
||||||
|
}
|
||||||
|
gui::VendorResult::Buy => {
|
||||||
|
let tag = result.2.unwrap();
|
||||||
|
let price = result.3.unwrap();
|
||||||
|
let mut pools = self.ecs.write_storage::<Pools>();
|
||||||
|
let player_pools = pools.get_mut(*self.ecs.fetch::<Entity>()).unwrap();
|
||||||
|
if player_pools.gold >= price {
|
||||||
|
player_pools.gold -= price;
|
||||||
|
std::mem::drop(pools);
|
||||||
|
|
||||||
|
let player_entity = *self.ecs.fetch::<Entity>();
|
||||||
|
spawn_named_item(
|
||||||
|
&RAWS.lock().unwrap(),
|
||||||
|
&mut self.ecs,
|
||||||
|
&tag,
|
||||||
|
SpawnType::Carried { by: player_entity },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gui::VendorResult::BuyMode => {
|
||||||
|
newrunstate = RunState::ShowVendor {
|
||||||
|
vendor,
|
||||||
|
mode: VendorMode::Buy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gui::VendorResult::SellMode => {
|
||||||
|
newrunstate = RunState::ShowVendor {
|
||||||
|
vendor,
|
||||||
|
mode: VendorMode::Sell,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RunState::TownPortal => {
|
||||||
|
// Spawn the portal
|
||||||
|
spawner::spawn_town_portal(&mut self.ecs);
|
||||||
|
|
||||||
|
// Transition
|
||||||
|
let map_depth = self.ecs.fetch::<Map>().depth;
|
||||||
|
let destination_offset = 0 - (map_depth - 1);
|
||||||
|
self.goto_level(destination_offset);
|
||||||
|
self.mapgen_next_state = Some(RunState::PreRun);
|
||||||
|
|
||||||
|
newrunstate = RunState::MapGeneration;
|
||||||
|
}
|
||||||
|
RunState::TeleportingToOtherLevel { x, y, depth } => {
|
||||||
|
self.goto_level(depth - 1);
|
||||||
|
let player_entity = self.ecs.fetch::<Entity>();
|
||||||
|
if let Some(pos) = self.ecs.write_storage::<Position>().get_mut(*player_entity) {
|
||||||
|
pos.x = x;
|
||||||
|
pos.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ppos = self.ecs.fetch_mut::<Point>();
|
||||||
|
ppos.x = x;
|
||||||
|
ppos.y = y;
|
||||||
|
self.mapgen_next_state = Some(RunState::PreRun);
|
||||||
|
|
||||||
|
newrunstate = RunState::MapGeneration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut runwriter = self.ecs.write_resource::<RunState>();
|
||||||
|
*runwriter = newrunstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
damage_system::delete_the_dead(&mut self.ecs);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user