Separate binary from game engine

This commit is contained in:
Timothy Warren 2022-02-10 11:54:57 -05:00
parent 73525db8dd
commit 4a8b791acb
12 changed files with 202 additions and 188 deletions

View File

@ -1,5 +1,5 @@
[package] [package]
name = "roguelike_tutorial" name = "tim_rogue"
version = "0.1.0" version = "0.1.0"
rust-version = "1.56" rust-version = "1.56"
edition = "2021" edition = "2021"

View File

@ -46,6 +46,6 @@ fix: $(call print-help, fix, Fixes some warnings, then runs the formatter)
make fmt make fmt
docs: $(call print-help, docs, Generates code docs) docs: $(call print-help, docs, Generates code docs)
cargo doc --features $(FEATURES) cargo doc --features $(FEATURES) --document-private-items
.phony: run-pi clean check run fmt fix lint docs build build-wasm check-wasm build-wasm-dev .phony: run-pi clean check run fmt fix lint docs build build-wasm check-wasm build-wasm-dev

View File

@ -73,4 +73,6 @@ If you want to see what else you can run with Makefile, run `make help`. This wi
* Added a macro to register components for `specs`, like was in the tutorial for saving/loading. * Added a macro to register components for `specs`, like was in the tutorial for saving/loading.
* Game state machine is moved to `src/state.rs` * Game state machine is moved to `src/state.rs`
* Colors (Bracket-lib `RGB` struct) have been converted to static values in `src/colors.rs`, to cut down on boilerplate and numbers of ways of generating color values. * Colors (Bracket-lib `RGB` struct) have been converted to static values in `src/colors.rs`, to cut down on boilerplate and numbers of ways of generating color values.
* All references to `rltk` have been converted to `bracket_lib`, as `rltk` was a facade in `bracket_lib` * All references to `rltk` have been converted to `bracket_lib`, as `rltk` was a facade in `bracket_lib`
* Made the crate a library and binary, with the binary just starting and running the game engine
* Submodules use named files as the module base, rather than `mod.rs`

View File

@ -10,6 +10,7 @@ use std::collections::{HashSet, VecDeque};
use std::sync::Mutex; use std::sync::Mutex;
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::lazy_static::lazy_static;
use ::specs::prelude::*; use ::specs::prelude::*;
pub use targeting::*; pub use targeting::*;

View File

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
use ::lazy_static::lazy_static;
lazy_static! { lazy_static! {
static ref EVENTS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new()); static ref EVENTS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
} }

View File

@ -1,6 +1,7 @@
use std::sync::Mutex; use std::sync::Mutex;
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::lazy_static::lazy_static;
use super::LogFragment; use super::LogFragment;
use crate::colors; use crate::colors;

185
src/lib.rs Normal file
View File

@ -0,0 +1,185 @@
//! Roguelike
//!
//! An implementation of a rogue-like dungeon-crawler game.
mod colors;
mod components;
mod damage_system;
mod effects;
mod gamelog;
mod gamesystem;
mod gui;
mod map;
mod map_builders;
mod player;
mod random_table;
pub mod raws;
mod rect;
mod rex_assets;
mod rng;
mod saveload_system;
mod spatial;
mod spawner;
mod state;
mod systems;
use ::bracket_lib::prelude::*;
use ::specs::prelude::*;
use ::specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
use components::*;
use map::*;
use rect::Rect;
use state::*;
/// Cut down on the amount of syntax to register components
///
/// Compare:
/// ```ignore
/// let mut game_state = State::new();
///
/// register!(state <- ComponentA, ComponentB, ...);
/// ```
///
/// Without macro:
/// ```ignore
/// let mut game_state = State::new();
///
/// state.ecs.register::<ComponentA>();
/// state.ecs.register::<ComponentB>();
/// ```
macro_rules! register {
// $state is needed to get the scope at the usage point
// $Type is the Component type that is being registered
($state: ident <- $( $Type: ty ),*,) => {
$(
$state.ecs.register::<$Type>();
)*
}
}
/// Register the Component Structs with Specs
fn register_components() -> State {
let mut state = State::new();
register!(
state <-
AlwaysTargetsSelf,
ApplyMove,
ApplyTeleport,
AreaOfEffect,
AttributeBonus,
Attributes,
BlocksTile,
BlocksVisibility,
Chasing,
Confusion,
Consumable,
CursedItem,
DamageOverTime,
DMSerializationHelper,
Door,
Duration,
EntityMoved,
EntryTrigger,
EquipmentChanged,
Equippable,
Equipped,
Faction,
Hidden,
HungerClock,
IdentifiedItem,
InBackpack,
InflictsDamage,
Initiative,
Item,
KnownSpells,
LightSource,
LootTable,
MagicItem,
MagicMapper,
MoveMode,
MyTurn,
Name,
NaturalAttackDefense,
ObfuscatedName,
OnDeath,
OtherLevelPosition,
ParticleLifetime,
Player,
Pools,
Position,
ProvidesFood,
ProvidesHealing,
ProvidesIdentification,
ProvidesMana,
ProvidesRemoveCurse,
Quips,
Ranged,
Renderable,
SerializationHelper,
SimpleMarker<SerializeMe>,
SingleActivation,
Skills,
Slow,
SpawnParticleBurst,
SpawnParticleLine,
SpecialAbilities,
SpellTemplate,
StatusEffect,
Target,
TeachesSpell,
TeleportTo,
TileSize,
TownPortal,
Vendor,
Viewshed,
WantsToApproach,
WantsToCastSpell,
WantsToDropItem,
WantsToFlee,
WantsToMelee,
WantsToPickupItem,
WantsToRemoveItem,
WantsToShoot,
WantsToUseItem,
Weapon,
Wearable,
);
state
}
/// Sets up the game.
///
/// * Creates the [`State`] object
/// * Registers [`components`](register!)
/// * Loads the dynamic game entities using the [`raws`](crate::raws::load_raws) module
/// * Generates the map builder environment
/// * Creates the [`Player`](crate::spawner::player)
/// * Generates the first [`map`](crate::state::State::generate_world_map)
pub fn init_state() -> State {
use systems::particle_system::ParticleBuilder;
let mut state = register_components();
state
.ecs
.insert(SimpleMarkerAllocator::<SerializeMe>::new());
raws::load_raws();
state.ecs.insert(MasterDungeonMap::new());
state.ecs.insert(Map::new(1, 64, 64, "New Map"));
state.ecs.insert(Point::zero());
let player_entity = spawner::player(&mut state.ecs, 0, 0);
state.ecs.insert(player_entity);
state.ecs.insert(RunState::MapGeneration {});
state.ecs.insert(ParticleBuilder::new());
state.ecs.insert(rex_assets::RexAssets::new());
state.generate_world_map(1, 0);
state
}

View File

@ -1,188 +1,4 @@
//! Roguelike
//!
//! An implementation of a rogue-like dungeon-crawler game.
#[macro_use]
extern crate lazy_static;
mod colors;
mod components;
mod damage_system;
mod effects;
mod gamelog;
mod gamesystem;
mod gui;
mod map;
pub mod map_builders;
mod player;
mod random_table;
mod raws;
mod rect;
mod rex_assets;
mod rng;
mod saveload_system;
mod spatial;
mod spawner;
mod state;
mod systems;
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::specs::prelude::*;
use ::specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
use components::*;
pub use map::*;
pub use rect::Rect;
pub use state::*;
/// Cut down on the amount of syntax to register components
///
/// Compare:
/// ```ignore
/// let mut game_state = State::new();
///
/// register!(state <- ComponentA, ComponentB, ...);
/// ```
///
/// Without macro:
/// ```ignore
/// let mut game_state = State::new();
///
/// state.ecs.register::<ComponentA>();
/// state.ecs.register::<ComponentB>();
/// ```
macro_rules! register {
// $state is needed to get the scope at the usage point
// $Type is the Component type that is being registered
($state: ident <- $( $Type: ty ),*,) => {
$(
$state.ecs.register::<$Type>();
)*
}
}
/// Register the Component Structs with Specs
fn register_components(state: &mut State) {
register!(
state <-
AlwaysTargetsSelf,
ApplyMove,
ApplyTeleport,
AreaOfEffect,
AttributeBonus,
Attributes,
BlocksTile,
BlocksVisibility,
Chasing,
Confusion,
Consumable,
CursedItem,
DamageOverTime,
DMSerializationHelper,
Door,
Duration,
EntityMoved,
EntryTrigger,
EquipmentChanged,
Equippable,
Equipped,
Faction,
Hidden,
HungerClock,
IdentifiedItem,
InBackpack,
InflictsDamage,
Initiative,
Item,
KnownSpells,
LightSource,
LootTable,
MagicItem,
MagicMapper,
MoveMode,
MyTurn,
Name,
NaturalAttackDefense,
ObfuscatedName,
OnDeath,
OtherLevelPosition,
ParticleLifetime,
Player,
Pools,
Position,
ProvidesFood,
ProvidesHealing,
ProvidesIdentification,
ProvidesMana,
ProvidesRemoveCurse,
Quips,
Ranged,
Renderable,
SerializationHelper,
SimpleMarker<SerializeMe>,
SingleActivation,
Skills,
Slow,
SpawnParticleBurst,
SpawnParticleLine,
SpecialAbilities,
SpellTemplate,
StatusEffect,
Target,
TeachesSpell,
TeleportTo,
TileSize,
TownPortal,
Vendor,
Viewshed,
WantsToApproach,
WantsToCastSpell,
WantsToDropItem,
WantsToFlee,
WantsToMelee,
WantsToPickupItem,
WantsToRemoveItem,
WantsToShoot,
WantsToUseItem,
Weapon,
Wearable,
);
}
/// Sets up the game.
///
/// * Creates the [`State`] object
/// * Registers [`components`](register!)
/// * Loads the dynamic game entities using the [`raws`](crate::raws::load_raws) module
/// * Generates the map builder environment
/// * Creates the [`Player`](crate::spawner::player)
/// * Generates the first [`map`](crate::state::State::generate_world_map)
fn init_state() -> State {
use systems::particle_system::ParticleBuilder;
let mut state = State::new();
register_components(&mut state);
state
.ecs
.insert(SimpleMarkerAllocator::<SerializeMe>::new());
raws::load_raws();
state.ecs.insert(MasterDungeonMap::new());
state.ecs.insert(Map::new(1, 64, 64, "New Map"));
state.ecs.insert(Point::zero());
let player_entity = spawner::player(&mut state.ecs, 0, 0);
state.ecs.insert(player_entity);
state.ecs.insert(RunState::MapGeneration {});
state.ecs.insert(ParticleBuilder::new());
state.ecs.insert(rex_assets::RexAssets::new());
state.generate_world_map(1, 0);
state
}
/// The entry point /// The entry point
fn main() -> BError { fn main() -> BError {
@ -194,5 +10,5 @@ fn main() -> BError {
.with_vsync(false) .with_vsync(false)
.build()?; .build()?;
main_loop(context, init_state()) main_loop(context, ::tim_rogue::init_state())
} }

View File

@ -12,6 +12,7 @@ mod weapon_traits;
use std::sync::Mutex; use std::sync::Mutex;
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::lazy_static::lazy_static;
use ::serde::Deserialize; use ::serde::Deserialize;
pub use faction_structs::*; pub use faction_structs::*;
use item_structs::*; use item_structs::*;

View File

@ -1,6 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::lazy_static::lazy_static;
use ::regex::Regex; use ::regex::Regex;
use ::specs::prelude::*; use ::specs::prelude::*;
use ::specs::saveload::{MarkedBuilder, SimpleMarker}; use ::specs::saveload::{MarkedBuilder, SimpleMarker};

View File

@ -1,6 +1,8 @@
//! The random number generator, using a mutex to share the instance
use std::sync::Mutex; use std::sync::Mutex;
use ::bracket_lib::prelude::*; use ::bracket_lib::prelude::*;
use ::lazy_static::lazy_static;
lazy_static! { lazy_static! {
static ref RNG: Mutex<RandomNumberGenerator> = Mutex::new(RandomNumberGenerator::new()); static ref RNG: Mutex<RandomNumberGenerator> = Mutex::new(RandomNumberGenerator::new());
@ -11,10 +13,12 @@ pub fn reseed(seed: u64) {
*RNG.lock().unwrap() = RandomNumberGenerator::seeded(seed); *RNG.lock().unwrap() = RandomNumberGenerator::seeded(seed);
} }
/// Rolls `n` dice, with `die_type` sides
pub fn roll_dice(n: i32, die_type: i32) -> i32 { pub fn roll_dice(n: i32, die_type: i32) -> i32 {
RNG.lock().unwrap().roll_dice(n, die_type) RNG.lock().unwrap().roll_dice(n, die_type)
} }
/// Returns a number in the range given
pub fn range(min: i32, max: i32) -> i32 { pub fn range(min: i32, max: i32) -> i32 {
RNG.lock().unwrap().range(min, max) RNG.lock().unwrap().range(min, max)
} }

View File

@ -1,5 +1,6 @@
use std::sync::Mutex; use std::sync::Mutex;
use ::lazy_static::lazy_static;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::{tile_walkable, Map, RunState}; use crate::{tile_walkable, Map, RunState};