Finished section 1
This commit is contained in:
parent
fb5b70ce3b
commit
aad1402f81
@ -135,3 +135,41 @@ pub struct SerializeMe;
|
||||
pub struct SerializationHelper {
|
||||
pub map: super::map::Map,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum EquipmentSlot {
|
||||
Melee,
|
||||
Shield,
|
||||
Head,
|
||||
Shoulder,
|
||||
Chest,
|
||||
Legs,
|
||||
Hands,
|
||||
Feet,
|
||||
}
|
||||
|
||||
#[derive(Component, Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct Equippable {
|
||||
pub slot: EquipmentSlot,
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct Equipped {
|
||||
pub owner: Entity,
|
||||
pub slot: EquipmentSlot,
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct MeleePowerBonus {
|
||||
pub power: i32,
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct DefenseBonus {
|
||||
pub defense: i32,
|
||||
}
|
||||
|
||||
#[derive(Component, ConvertSaveload, Clone)]
|
||||
pub struct WantsToRemoveItem {
|
||||
pub item: Entity,
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::gamelog::GameLog;
|
||||
use crate::Name;
|
||||
use rltk::console;
|
||||
use specs::prelude::*;
|
||||
|
||||
use crate::{Name, RunState};
|
||||
use crate::components::{CombatStats, Player, SufferDamage};
|
||||
use crate::gamelog::GameLog;
|
||||
|
||||
pub struct DamageSystem {}
|
||||
|
||||
@ -44,7 +44,10 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||
dead.push(entity)
|
||||
}
|
||||
|
||||
Some(_) => console::log("You are dead"),
|
||||
Some(_) => {
|
||||
let mut runstate = ecs.write_resource::<RunState>();
|
||||
*runstate = RunState::GameOver;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
111
src/gui.rs
111
src/gui.rs
@ -1,14 +1,14 @@
|
||||
use rltk::Rltk;
|
||||
use rltk::RGB;
|
||||
use rltk::{Rltk};
|
||||
use rltk::{Point, VirtualKeyCode};
|
||||
use rltk::RGB;
|
||||
use specs::prelude::*;
|
||||
|
||||
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
|
||||
use crate::{Equipped, Map};
|
||||
use crate::gamelog::GameLog;
|
||||
use crate::Map;
|
||||
use crate::Name;
|
||||
use crate::Player;
|
||||
use crate::Position;
|
||||
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
|
||||
|
||||
pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||
ctx.draw_box(
|
||||
@ -514,3 +514,106 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
|
||||
selected: MainMenuSelection::NewGame,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
|
||||
let player_entity = gs.ecs.fetch::<Entity>();
|
||||
let names = gs.ecs.read_storage::<Name>();
|
||||
let backpack = gs.ecs.read_storage::<Equipped>();
|
||||
let entities = gs.ecs.entities();
|
||||
|
||||
let inventory = (&backpack, &names)
|
||||
.join()
|
||||
.filter(|item| item.0.owner == *player_entity);
|
||||
let count = inventory.count();
|
||||
|
||||
let mut y = (25 - (count / 2)) as i32;
|
||||
ctx.draw_box(
|
||||
15,
|
||||
y - 2,
|
||||
31,
|
||||
(count + 3) as i32,
|
||||
RGB::named(rltk::WHITE),
|
||||
RGB::named(rltk::BLACK),
|
||||
);
|
||||
ctx.print_color(
|
||||
18,
|
||||
y - 2,
|
||||
RGB::named(rltk::YELLOW),
|
||||
RGB::named(rltk::BLACK),
|
||||
"Remove Which Item?",
|
||||
);
|
||||
ctx.print_color(
|
||||
18,
|
||||
y + count as i32 + 1,
|
||||
RGB::named(rltk::YELLOW),
|
||||
RGB::named(rltk::BLACK),
|
||||
"ESCAPE to cancel",
|
||||
);
|
||||
|
||||
let mut equippable: Vec<Entity> = Vec::new();
|
||||
let mut j = 0;
|
||||
for (entity, _pack, name) in (&entities, &backpack, &names)
|
||||
.join()
|
||||
.filter(|item| item.1.owner == *player_entity)
|
||||
{
|
||||
ctx.set(
|
||||
17,
|
||||
y,
|
||||
RGB::named(rltk::WHITE),
|
||||
RGB::named(rltk::BLACK),
|
||||
rltk::to_cp437('('),
|
||||
);
|
||||
ctx.set(
|
||||
18,
|
||||
y,
|
||||
RGB::named(rltk::YELLOW),
|
||||
RGB::named(rltk::BLACK),
|
||||
97 + j as rltk::FontCharType,
|
||||
);
|
||||
ctx.set(
|
||||
19,
|
||||
y,
|
||||
RGB::named(rltk::WHITE),
|
||||
RGB::named(rltk::BLACK),
|
||||
rltk::to_cp437(')'),
|
||||
);
|
||||
|
||||
ctx.print(21, y, &name.name.to_string());
|
||||
equippable.push(entity);
|
||||
y += 1;
|
||||
j += 1;
|
||||
}
|
||||
|
||||
match ctx.key {
|
||||
None => (ItemMenuResult::NoResponse, None),
|
||||
Some(key) => match key {
|
||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||
_ => {
|
||||
let selection = rltk::letter_to_option(key);
|
||||
if selection > -1 && selection < count as i32 {
|
||||
return (
|
||||
ItemMenuResult::Selected,
|
||||
Some(equippable[selection as usize]),
|
||||
);
|
||||
}
|
||||
(ItemMenuResult::NoResponse, None)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum GameOverResult { NoSelection, QuitToMenu }
|
||||
|
||||
pub fn game_over(ctx: &mut Rltk) -> GameOverResult {
|
||||
ctx.print_color_centered(15, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Your journey has ended!");
|
||||
ctx.print_color_centered(17, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "One day, we'll tell you all about how you did.");
|
||||
ctx.print_color_centered(18, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "That day, sadly, is not in this chapter..");
|
||||
|
||||
ctx.print_color_centered(20, RGB::named(rltk::MAGENTA), RGB::named(rltk::BLACK), "Press any key to return to the menu.");
|
||||
|
||||
match ctx.key {
|
||||
None => GameOverResult::NoSelection,
|
||||
Some(_) => GameOverResult::QuitToMenu
|
||||
}
|
||||
}
|
@ -2,14 +2,15 @@ use specs::prelude::*;
|
||||
|
||||
use crate::gamelog::GameLog;
|
||||
use crate::{
|
||||
AreaOfEffect, CombatStats, Confusion, Consumable, InBackpack, InflictsDamage, Map, Name,
|
||||
Position, ProvidesHealing, Ranged, SufferDamage, WantsToDropItem, WantsToPickupItem,
|
||||
WantsToUseItem,
|
||||
AreaOfEffect, CombatStats, Confusion, Consumable, Equippable, Equipped, InBackpack,
|
||||
InflictsDamage, Map, Name, Position, ProvidesHealing, Ranged, SufferDamage, WantsToDropItem,
|
||||
WantsToPickupItem, WantsToRemoveItem, WantsToUseItem,
|
||||
};
|
||||
|
||||
pub struct ItemCollectionSystem {}
|
||||
|
||||
impl<'a> System<'a> for ItemCollectionSystem {
|
||||
#[allow(clippy::complexity)]
|
||||
type SystemData = (
|
||||
ReadExpect<'a, Entity>,
|
||||
WriteExpect<'a, GameLog>,
|
||||
@ -49,6 +50,7 @@ impl<'a> System<'a> for ItemCollectionSystem {
|
||||
pub struct ItemUseSystem {}
|
||||
|
||||
impl<'a> System<'a> for ItemUseSystem {
|
||||
#[allow(clippy::complexity)]
|
||||
type SystemData = (
|
||||
ReadExpect<'a, Entity>,
|
||||
WriteExpect<'a, GameLog>,
|
||||
@ -64,6 +66,9 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
WriteStorage<'a, SufferDamage>,
|
||||
ReadStorage<'a, AreaOfEffect>,
|
||||
WriteStorage<'a, Confusion>,
|
||||
ReadStorage<'a, Equippable>,
|
||||
WriteStorage<'a, Equipped>,
|
||||
WriteStorage<'a, InBackpack>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
@ -82,6 +87,9 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
mut suffer_damage,
|
||||
aoe,
|
||||
mut confused,
|
||||
equippable,
|
||||
mut equipped,
|
||||
mut backpack,
|
||||
) = data;
|
||||
|
||||
for (entity, use_item) in (&entities, &wants_use).join() {
|
||||
@ -116,6 +124,43 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(item_equippable) = equippable.get(use_item.item) {
|
||||
let target_slot = item_equippable.slot;
|
||||
let target = targets[0];
|
||||
let mut to_unequip: Vec<Entity> = Vec::new();
|
||||
for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() {
|
||||
if already_equipped.owner == target && already_equipped.slot == target_slot {
|
||||
to_unequip.push(item_entity);
|
||||
if target == *player_entity {
|
||||
game_log.entries.push(format!("You unequip {}.", name.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
for item in to_unequip.iter() {
|
||||
equipped.remove(*item);
|
||||
backpack
|
||||
.insert(*item, InBackpack { owner: target })
|
||||
.expect("Unable to insert item into backpack");
|
||||
}
|
||||
|
||||
equipped
|
||||
.insert(
|
||||
use_item.item,
|
||||
Equipped {
|
||||
owner: target,
|
||||
slot: target_slot,
|
||||
},
|
||||
)
|
||||
.expect("Unable to equip item");
|
||||
backpack.remove(use_item.item);
|
||||
if target == *player_entity {
|
||||
game_log.entries.push(format!(
|
||||
"You equip item {}.",
|
||||
names.get(use_item.item).unwrap().name
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(item_damages) = inflicts_damage.get(use_item.item) {
|
||||
used_item = false;
|
||||
for mob in targets.iter() {
|
||||
@ -242,3 +287,26 @@ impl<'a> System<'a> for ItemDropSystem {
|
||||
wants_drop.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemRemoveSystem {}
|
||||
|
||||
impl<'a> System<'a> for ItemRemoveSystem {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, WantsToRemoveItem>,
|
||||
WriteStorage<'a, Equipped>,
|
||||
WriteStorage<'a, InBackpack>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (entities, mut wants_to_remove_item, mut equipped, mut backpack) = data;
|
||||
for (entity, to_remove) in (&entities, &wants_to_remove_item).join() {
|
||||
equipped.remove(to_remove.item);
|
||||
backpack
|
||||
.insert(to_remove.item, InBackpack { owner: entity })
|
||||
.expect("Unable to insert item into backpack");
|
||||
}
|
||||
|
||||
wants_to_remove_item.clear();
|
||||
}
|
||||
}
|
||||
|
96
src/main.rs
96
src/main.rs
@ -14,7 +14,7 @@ use player::*;
|
||||
use visibility_system::*;
|
||||
|
||||
use crate::gamelog::GameLog;
|
||||
use crate::inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemUseSystem};
|
||||
use crate::inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem};
|
||||
|
||||
mod components;
|
||||
mod damage_system;
|
||||
@ -49,25 +49,75 @@ pub enum RunState {
|
||||
},
|
||||
SaveGame,
|
||||
NextLevel,
|
||||
ShowRemoveItem,
|
||||
GameOver,
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub ecs: World,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub 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("Deletion failed");
|
||||
}
|
||||
|
||||
// Build a new map and place the player
|
||||
let worldmap;
|
||||
{
|
||||
let mut worldmap_resource = self.ecs.write_resource::<Map>();
|
||||
*worldmap_resource = Map::new_map_rooms_and_corridors(1);
|
||||
worldmap = worldmap_resource.clone();
|
||||
}
|
||||
|
||||
// Spawn bad guys
|
||||
for room in worldmap.rooms.iter().skip(1) {
|
||||
spawner::spawn_room(&mut self.ecs, room, 1);
|
||||
}
|
||||
|
||||
// Place the player and update resources
|
||||
let (player_x, player_y) = worldmap.rooms[0].center();
|
||||
let player_entity = spawner::player(&mut self.ecs, player_x, player_y);
|
||||
let mut player_position = self.ecs.write_resource::<Point>();
|
||||
*player_position = Point::new(player_x, player_y);
|
||||
let mut position_components = self.ecs.write_storage::<Position>();
|
||||
let mut player_entity_writer = self.ecs.write_resource::<Entity>();
|
||||
*player_entity_writer = player_entity;
|
||||
let player_pos_comp = position_components.get_mut(player_entity);
|
||||
if let Some(player_pos_comp) = player_pos_comp {
|
||||
player_pos_comp.x = player_x;
|
||||
player_pos_comp.y = player_y;
|
||||
}
|
||||
|
||||
// Mark the player's visibility as dirty
|
||||
let mut viewshed_components = self.ecs.write_storage::<Viewshed>();
|
||||
let vs = viewshed_components.get_mut(player_entity);
|
||||
if let Some(vs) = vs {
|
||||
vs.dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn entities_to_remove_on_level_change(&mut self) -> Vec<Entity> {
|
||||
let entities = self.ecs.entities();
|
||||
let player = self.ecs.read_storage::<Player>();
|
||||
let backpack = self.ecs.read_storage::<InBackpack>();
|
||||
let player_entity = self.ecs.fetch::<Entity>();
|
||||
let equipped = self.ecs.read_storage::<Equipped>();
|
||||
|
||||
let mut to_delete: Vec<Entity> = Vec::new();
|
||||
for entity in entities.join() {
|
||||
let mut should_delete = true;
|
||||
|
||||
let p = player.get(entity);
|
||||
if let Some(p) = p {
|
||||
if let Some(_p) = p {
|
||||
should_delete = false;
|
||||
}
|
||||
|
||||
@ -78,6 +128,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(eq) = equipped.get(entity) {
|
||||
if eq.owner == *player_entity {
|
||||
should_delete = false;
|
||||
}
|
||||
}
|
||||
|
||||
if should_delete {
|
||||
to_delete.push(entity);
|
||||
}
|
||||
@ -162,6 +218,9 @@ impl State {
|
||||
let mut drop_items = ItemDropSystem {};
|
||||
drop_items.run_now(&self.ecs);
|
||||
|
||||
let mut remove_items = ItemRemoveSystem {};
|
||||
remove_items.run_now(&self.ecs);
|
||||
|
||||
self.ecs.maintain();
|
||||
}
|
||||
}
|
||||
@ -309,6 +368,34 @@ impl GameState for State {
|
||||
self.goto_next_level();
|
||||
new_run_state = RunState::PreRun;
|
||||
}
|
||||
RunState::ShowRemoveItem => {
|
||||
let result = gui::remove_item_menu(self, ctx);
|
||||
match result.0 {
|
||||
gui::ItemMenuResult::Cancel => new_run_state = 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");
|
||||
new_run_state = RunState::PlayerTurn;
|
||||
}
|
||||
}
|
||||
}
|
||||
RunState::GameOver => {
|
||||
let result = gui::game_over(ctx);
|
||||
match result {
|
||||
gui::GameOverResult::NoSelection => {}
|
||||
gui::GameOverResult::QuitToMenu => {
|
||||
self.game_over_cleanup();
|
||||
new_run_state = RunState::MainMenu { menu_selection: gui::MainMenuSelection::NewGame };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@ -354,6 +441,11 @@ fn main() -> rltk::BError {
|
||||
gs.ecs.register::<Confusion>();
|
||||
gs.ecs.register::<SimpleMarker<SerializeMe>>();
|
||||
gs.ecs.register::<SerializationHelper>();
|
||||
gs.ecs.register::<Equippable>();
|
||||
gs.ecs.register::<Equipped>();
|
||||
gs.ecs.register::<MeleePowerBonus>();
|
||||
gs.ecs.register::<DefenseBonus>();
|
||||
gs.ecs.register::<WantsToRemoveItem>();
|
||||
|
||||
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
||||
|
||||
|
@ -2,6 +2,7 @@ use specs::prelude::*;
|
||||
|
||||
use crate::components::{CombatStats, Name, SufferDamage, WantsToMelee};
|
||||
use crate::gamelog::GameLog;
|
||||
use crate::{DefenseBonus, Equipped, MeleePowerBonus};
|
||||
|
||||
pub struct MeleeCombatSystem {}
|
||||
|
||||
@ -13,20 +14,54 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||
ReadStorage<'a, Name>,
|
||||
ReadStorage<'a, CombatStats>,
|
||||
WriteStorage<'a, SufferDamage>,
|
||||
ReadStorage<'a, MeleePowerBonus>,
|
||||
ReadStorage<'a, DefenseBonus>,
|
||||
ReadStorage<'a, Equipped>,
|
||||
);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
let (entities, mut log, mut wants_melee, names, combat_stats, mut inflict_damage) = data;
|
||||
let (
|
||||
entities,
|
||||
mut log,
|
||||
mut wants_melee,
|
||||
names,
|
||||
combat_stats,
|
||||
mut inflict_damage,
|
||||
melee_bonus,
|
||||
defense_bonus,
|
||||
equipped,
|
||||
) = data;
|
||||
|
||||
for (_entity, wants_melee, name, stats) in
|
||||
for (entity, wants_melee, name, stats) in
|
||||
(&entities, &wants_melee, &names, &combat_stats).join()
|
||||
{
|
||||
if stats.hp > 0 {
|
||||
let mut offensive_bonus = 0;
|
||||
for (_item_entity, power_bonus, equipped_by) in
|
||||
(&entities, &melee_bonus, &equipped).join()
|
||||
{
|
||||
if equipped_by.owner == entity {
|
||||
offensive_bonus += power_bonus.power;
|
||||
}
|
||||
}
|
||||
|
||||
let target_stats = combat_stats.get(wants_melee.target).unwrap();
|
||||
if target_stats.hp > 0 {
|
||||
let target_name = names.get(wants_melee.target).unwrap();
|
||||
|
||||
let damage = i32::max(0, stats.power - target_stats.defense);
|
||||
let mut defensive_bonus = 0;
|
||||
for (_item_entity, defense_bonus, equipped_by) in
|
||||
(&entities, &defense_bonus, &equipped).join()
|
||||
{
|
||||
if equipped_by.owner == wants_melee.target {
|
||||
defensive_bonus += defense_bonus.defense;
|
||||
}
|
||||
}
|
||||
|
||||
let damage = i32::max(
|
||||
0,
|
||||
(stats.power + offensive_bonus) - (target_stats.defense + defensive_bonus),
|
||||
);
|
||||
|
||||
if damage == 0 {
|
||||
log.entries.push(format!(
|
||||
|
@ -109,6 +109,7 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
VirtualKeyCode::I => return RunState::ShowInventory,
|
||||
VirtualKeyCode::D => return RunState::ShowDropItem,
|
||||
VirtualKeyCode::Escape => return RunState::SaveGame,
|
||||
VirtualKeyCode::R => return RunState::ShowRemoveItem,
|
||||
VirtualKeyCode::Period => {
|
||||
if try_next_level(&mut gs.ecs) {
|
||||
return RunState::NextLevel;
|
||||
@ -132,7 +133,7 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
||||
for tile in viewshed.visible_tiles.iter() {
|
||||
let idx = worldmap_resource.xy_idx(tile.x, tile.y);
|
||||
for entity_id in worldmap_resource.tile_content[idx].iter() {
|
||||
if let Some(mob) = monsters.get(*entity_id) {
|
||||
if let Some(_mob) = monsters.get(*entity_id) {
|
||||
can_heal = true;
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,10 @@ impl RandomTable {
|
||||
}
|
||||
|
||||
pub fn add<S: ToString>(mut self, name: S, weight: i32) -> RandomTable {
|
||||
self.total_weight += weight;
|
||||
self.entries.push(RandomEntry::new(name, weight));
|
||||
if weight > 0 {
|
||||
self.total_weight += weight;
|
||||
self.entries.push(RandomEntry::new(name, weight));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,12 @@ pub fn save_game(ecs: &mut World) {
|
||||
WantsToPickupItem,
|
||||
WantsToUseItem,
|
||||
WantsToDropItem,
|
||||
SerializationHelper
|
||||
SerializationHelper,
|
||||
Equippable,
|
||||
Equipped,
|
||||
MeleePowerBonus,
|
||||
DefenseBonus,
|
||||
WantsToRemoveItem
|
||||
);
|
||||
}
|
||||
|
||||
@ -145,7 +150,12 @@ pub fn load_game(ecs: &mut World) {
|
||||
WantsToPickupItem,
|
||||
WantsToUseItem,
|
||||
WantsToDropItem,
|
||||
SerializationHelper
|
||||
SerializationHelper,
|
||||
Equippable,
|
||||
Equipped,
|
||||
MeleePowerBonus,
|
||||
DefenseBonus,
|
||||
WantsToRemoveItem
|
||||
);
|
||||
}
|
||||
|
||||
|
194
src/spawner.rs
194
src/spawner.rs
@ -7,9 +7,9 @@ use specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||
use crate::random_table::RandomTable;
|
||||
use crate::rect::Rect;
|
||||
use crate::{
|
||||
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, InflictsDamage, Item, Monster,
|
||||
Name, Player, Position, ProvidesHealing, Ranged, Renderable, SerializeMe, Viewshed, MAP_WIDTH,
|
||||
MAX_ITEMS, MAX_MONSTER,
|
||||
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, DefenseBonus, EquipmentSlot,
|
||||
Equippable, InflictsDamage, Item, MeleePowerBonus, Monster, Name, Player, Position,
|
||||
ProvidesHealing, Ranged, Renderable, SerializeMe, Viewshed, MAP_WIDTH, MAX_ITEMS, MAX_MONSTER,
|
||||
};
|
||||
|
||||
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
@ -117,6 +117,14 @@ pub fn spawn_room(ecs: &mut World, room: &Rect, map_depth: i32) {
|
||||
"Fireball Scroll" => fireball_scroll(ecs, x, y),
|
||||
"Confusion Scroll" => confusion_scroll(ecs, x, y),
|
||||
"Magic Missile Scroll" => magic_missile_scroll(ecs, x, y),
|
||||
"Dagger" => dagger(ecs, x, y),
|
||||
"Longsword" => longsword(ecs, x, y),
|
||||
"Shield" => shield(ecs, x, y),
|
||||
"Tower Shield" => tower_shield(ecs, x, y),
|
||||
"Helmet" => helmet(ecs, x, y),
|
||||
"Breastplate" => breastplate(ecs, x, y),
|
||||
"Leggings" => leggings(ecs, x, y),
|
||||
"Sabatons" => sabatons(ecs, x, y),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -210,4 +218,184 @@ pub fn room_table(map_depth: i32) -> RandomTable {
|
||||
.add("Fireball Scroll", 2 + map_depth)
|
||||
.add("Confusion Scroll", 2 + map_depth)
|
||||
.add("Magic Missile Scroll", 4)
|
||||
.add("Dagger", 3)
|
||||
.add("Longsword", map_depth - 1)
|
||||
.add("Shield", 3)
|
||||
.add("Tower Shield", map_depth - 1)
|
||||
.add("Helmet", map_depth - 2)
|
||||
.add("Breastplate", map_depth - 3)
|
||||
.add("Leggings", map_depth - 4)
|
||||
.add("Sabatons", map_depth - 4)
|
||||
}
|
||||
|
||||
fn dagger(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('/'),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Dagger".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Melee,
|
||||
})
|
||||
.with(MeleePowerBonus { power: 2 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
fn longsword(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('/'),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Longsword".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Melee,
|
||||
})
|
||||
.with(MeleePowerBonus { power: 4 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
fn shield(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('('),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Shield".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Shield,
|
||||
})
|
||||
.with(DefenseBonus { defense: 1 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
fn tower_shield(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('('),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Tower Shield".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Shield,
|
||||
})
|
||||
.with(DefenseBonus { defense: 3 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
fn helmet(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('^'),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Helmet".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Head,
|
||||
})
|
||||
.with(DefenseBonus { defense: 1 })
|
||||
.with(MeleePowerBonus { power: 1 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
fn breastplate(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('x'),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Breastplate".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Chest,
|
||||
})
|
||||
.with(DefenseBonus { defense: 2 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
fn leggings(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437('"'),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Leggings".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Legs,
|
||||
})
|
||||
.with(DefenseBonus { defense: 1 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
||||
fn sabatons(ecs: &mut World, x: i32, y: i32) {
|
||||
ecs.create_entity()
|
||||
.with(Position { x, y })
|
||||
.with(Renderable {
|
||||
glyph: rltk::to_cp437(','),
|
||||
render_order: 2,
|
||||
fg: RGB::named(rltk::CYAN),
|
||||
bg: RGB::named(rltk::BLACK),
|
||||
})
|
||||
.with(Item {})
|
||||
.with(Name {
|
||||
name: "Sabatons".to_string(),
|
||||
})
|
||||
.with(Equippable {
|
||||
slot: EquipmentSlot::Feet,
|
||||
})
|
||||
.with(DefenseBonus { defense: 1 })
|
||||
.with(MeleePowerBonus { power: 1 })
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user