overhaul: data-driven architecture
This commit is contained in:
parent
062d36f640
commit
f53b767376
19 changed files with 680 additions and 727 deletions
0
raws/entity_categories.json
Normal file
0
raws/entity_categories.json
Normal file
126
raws/items.json
Normal file
126
raws/items.json
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "potion_health",
|
||||||
|
"name": { "name": "potion of health", "plural": "potions of health" },
|
||||||
|
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "provides_healing": "12" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "potion_health_weak",
|
||||||
|
"name": { "name": "potion of lesser health", "plural": "potions of lesser health" },
|
||||||
|
"renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "provides_healing": "6" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_magicmissile",
|
||||||
|
"name": { "name": "scroll of magic missile", "plural": "scrolls of magic missile" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "ranged": "12", "damage": "10" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_fireball",
|
||||||
|
"name": { "name": "scroll of fireball", "plural": "scrolls of fireball" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_fireball_cursed",
|
||||||
|
"name": { "name": "cursed scroll of fireball", "plural": "cursed scrolls of fireball" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"],
|
||||||
|
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_confusion",
|
||||||
|
"name": { "name": "scroll of confusion", "plural": "scrolls of confusion" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "ranged": "10", "confusion": "4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_magicmap",
|
||||||
|
"name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE"],
|
||||||
|
"effects": { "magicmapper": "" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scroll_magicmap_cursed",
|
||||||
|
"name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" },
|
||||||
|
"renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["CONSUMABLE", "DESTRUCTIBLE", "CURSED"],
|
||||||
|
"effects": { "magicmapper": "" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "equip_dagger",
|
||||||
|
"name": { "name": "dagger", "plural": "daggers" },
|
||||||
|
"renderable": { "glyph": ")", "fg": "#808080", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["EQUIP_MELEE"],
|
||||||
|
"effects": { "melee_power_bonus": "1" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "equip_shortsword",
|
||||||
|
"name": { "name": "shortsword", "plural": "shortswords" },
|
||||||
|
"renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["EQUIP_MELEE"],
|
||||||
|
"effects": { "melee_power_bonus": "2" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "equip_smallshield",
|
||||||
|
"name": { "name": "buckler", "plural": "bucklers" },
|
||||||
|
"renderable": { "glyph": "[", "fg": "#808080", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["EQUIP_SHIELD"],
|
||||||
|
"effects": { "defence_bonus": "1" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "equip_mediumshield",
|
||||||
|
"name": { "name": "medium shield", "plural": "medium shield" },
|
||||||
|
"renderable": { "glyph": "[", "fg": "#C0C0C0", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["EQUIP_SHIELD"],
|
||||||
|
"effects": { "defence_bonus": "2", "melee_power_bonus": "-1" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wand_magicmissile",
|
||||||
|
"name": { "name": "wand of magic missile", "plural": "wands of magic missile" },
|
||||||
|
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["WAND"],
|
||||||
|
"effects": { "ranged": "12", "damage": "10" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wand_fireball",
|
||||||
|
"name": { "name": "wand of fireball", "plural": "wands of fireball" },
|
||||||
|
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["WAND"],
|
||||||
|
"effects": { "ranged": "10", "damage": "15", "aoe": "3" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wand_confusion",
|
||||||
|
"name": { "name": "wand of confusion", "plural": "wands of confusion" },
|
||||||
|
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["WAND"],
|
||||||
|
"effects": { "ranged": "10", "confusion": "4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wand_digging",
|
||||||
|
"name": { "name": "wand of digging", "plural": "wands of digging" },
|
||||||
|
"renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["WAND"],
|
||||||
|
"effects": { "ranged": "10", "digger": "" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "food_rations",
|
||||||
|
"name": { "name": "rations", "plural": "rations" },
|
||||||
|
"renderable": { "glyph": "%", "fg": "#FFA07A", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["FOOD", "CONSUMABLE"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "food_apple",
|
||||||
|
"name": { "name": "apple", "plural": "apples" },
|
||||||
|
"renderable": { "glyph": "%", "fg": "#008000", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["FOOD", "CONSUMABLE"]
|
||||||
|
}
|
||||||
|
]
|
||||||
26
raws/mobs.json
Normal file
26
raws/mobs.json
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "orc",
|
||||||
|
"name": "orc",
|
||||||
|
"renderable": { "glyph": "o", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||||
|
"flags": ["BLOCKS_TILE"],
|
||||||
|
"stats": { "max_hp": 8, "hp": 8, "defence": 0, "power": 3 },
|
||||||
|
"vision_range": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "goblin",
|
||||||
|
"name": "goblin",
|
||||||
|
"renderable": { "glyph": "g", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||||
|
"flags": ["BLOCKS_TILE"],
|
||||||
|
"stats": { "max_hp": 6, "hp": 6, "defence": 0, "power": 2 },
|
||||||
|
"vision_range": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "goblin_chieftain",
|
||||||
|
"name": "goblin chieftain",
|
||||||
|
"renderable": { "glyph": "G", "fg": "#00FF00", "bg": "#000000", "order": 1 },
|
||||||
|
"flags": ["BLOCKS_TILE"],
|
||||||
|
"stats": { "max_hp": 8, "hp": 8, "defence": 0, "power": 3 },
|
||||||
|
"vision_range": 12
|
||||||
|
}
|
||||||
|
]
|
||||||
22
raws/props.json
Normal file
22
raws/props.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "door",
|
||||||
|
"name": "door",
|
||||||
|
"renderable": { "glyph": "+", "fg": "#00FFFF", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["BLOCKS_TILE", "BLOCKS_VISIBILITY", "DOOR"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "trap_bear",
|
||||||
|
"name": "bear trap",
|
||||||
|
"renderable": { "glyph": "^", "fg": "#C0C0C0", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["HIDDEN", "ENTRY_TRIGGER", "SINGLE_ACTIVATION"],
|
||||||
|
"effects": { "damage": "6" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "trap_confusion",
|
||||||
|
"name": "magic trap",
|
||||||
|
"renderable": { "glyph": "^", "fg": "#800080", "bg": "#000000", "order": 2 },
|
||||||
|
"flags": ["HIDDEN", "ENTRY_TRIGGER", "SINGLE_ACTIVATION"],
|
||||||
|
"effects": { "confusion": "3" }
|
||||||
|
}
|
||||||
|
]
|
||||||
57
raws/spawn_tables.json
Normal file
57
raws/spawn_tables.json
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "equipment",
|
||||||
|
"table": [
|
||||||
|
{ "id": "equip_dagger", "weight": 4, "min": 0, "max": 100 },
|
||||||
|
{ "id": "equip_shortsword", "weight": 2, "min": 0, "max": 100 },
|
||||||
|
{ "id": "equip_smallshield", "weight": 4, "min": 0, "max": 100 },
|
||||||
|
{ "id": "equip_mediumshield", "weight": 2, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "potions",
|
||||||
|
"table": [
|
||||||
|
{ "id": "potion_health_weak", "weight": 6, "min": 0, "max": 100 },
|
||||||
|
{ "id": "potion_health", "weight": 3, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scrolls",
|
||||||
|
"table": [
|
||||||
|
{ "id": "scroll_fireball", "weight": 2, "min": 0, "max": 100 },
|
||||||
|
{ "id": "scroll_confusion", "weight": 2, "min": 0, "max": 100 },
|
||||||
|
{ "id": "scroll_magicmap", "weight": 2, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wands",
|
||||||
|
"table": [
|
||||||
|
{ "id": "wand_magicmissile", "weight": 1, "min": 0, "max": 100 },
|
||||||
|
{ "id": "wand_fireball", "weight": 1, "min": 0, "max": 100 },
|
||||||
|
{ "id": "wand_confusion", "weight": 1, "min": 0, "max": 100 },
|
||||||
|
{ "id": "wand_digging", "weight": 1, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "food",
|
||||||
|
"table": [
|
||||||
|
{ "id": "food_rations", "weight": 1, "min": 0, "max": 100 },
|
||||||
|
{ "id": "food_apple", "weight": 1, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mobs",
|
||||||
|
"table": [
|
||||||
|
{ "id": "goblin", "weight": 6, "min": 0, "max": 100 },
|
||||||
|
{ "id": "orc", "weight": 2, "min": 0, "max": 100 },
|
||||||
|
{ "id": "goblin_chieftain", "weight": 1, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "traps",
|
||||||
|
"table": [
|
||||||
|
{ "id": "trap_bear", "weight": 2, "min": 0, "max": 100 },
|
||||||
|
{ "id": "trap_confusion", "weight": 1, "min": 0, "max": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
180
raws/spawns.json
180
raws/spawns.json
|
|
@ -1,180 +0,0 @@
|
||||||
{
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "potion of health",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "!",
|
|
||||||
"fg": "#FF00FF",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": { "provides_healing": "8" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "potion of greater health",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "!",
|
|
||||||
"fg": "#FF00FF",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": { "provides_healing": "16" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "potion of superior health",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "!",
|
|
||||||
"fg": "#FF00FF",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": { "provides_healing": "32" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "scroll of magic missile",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "?",
|
|
||||||
"fg": "#00FFFF",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": {
|
|
||||||
"ranged": "12",
|
|
||||||
"damage": "10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "scroll of fireball",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "?",
|
|
||||||
"fg": "#FFA500",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": {
|
|
||||||
"ranged": "10",
|
|
||||||
"damage": "20",
|
|
||||||
"aoe": "3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "scroll of confusion",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "?",
|
|
||||||
"fg": "#A020F0",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": {
|
|
||||||
"ranged": "10",
|
|
||||||
"confusion": "4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "scroll of magic mapping",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "?",
|
|
||||||
"fg": "#4169E1",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": {
|
|
||||||
"magic_mapping": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "rations",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "%",
|
|
||||||
"fg": "#FFA07A",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"consumable": {
|
|
||||||
"effects": {
|
|
||||||
"food": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dagger",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": ")",
|
|
||||||
"fg": "#BEBEBE",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"weapon": {
|
|
||||||
"range": "melee",
|
|
||||||
"power_bonus": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "shortsword",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": ")",
|
|
||||||
"fg": "#D3D3D3",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"weapon": {
|
|
||||||
"range": "melee",
|
|
||||||
"power_bonus": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "buckler",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "[",
|
|
||||||
"fg": "#BEBEBE",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"shield": {
|
|
||||||
"defence_bonus": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "medium shield",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "[",
|
|
||||||
"fg": "#BEBEBE",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"shield": {
|
|
||||||
"power_bonus": -1,
|
|
||||||
"defence_bonus": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "large shield",
|
|
||||||
"renderable": {
|
|
||||||
"glyph": "[",
|
|
||||||
"fg": "#F5F5F5",
|
|
||||||
"bg": "#000000",
|
|
||||||
"order": 2
|
|
||||||
},
|
|
||||||
"shield": {
|
|
||||||
"power_bonus": -2,
|
|
||||||
"defence_bonus": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mobs": [],
|
|
||||||
"props": []
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::ops::{Add, Mul};
|
||||||
|
|
||||||
const SHOW_BOUNDARIES: bool = false;
|
const SHOW_BOUNDARIES: bool = false;
|
||||||
|
|
||||||
pub fn get_screen_bounds(ecs: &World, ctx: &mut Rltk) -> (i32, i32, i32, i32) {
|
pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32) {
|
||||||
let player_pos = ecs.fetch::<Point>();
|
let player_pos = ecs.fetch::<Point>();
|
||||||
//let (x_chars, y_chars) = ctx.get_char_size();
|
//let (x_chars, y_chars) = ctx.get_char_size();
|
||||||
let (x_chars, y_chars) = (80, 43);
|
let (x_chars, y_chars) = (80, 43);
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,12 @@ pub fn setup_log() {
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
Logger::new().log();
|
Logger::new().log();
|
||||||
}
|
}
|
||||||
Logger::new().append("Welcome!").colour(rltk::CYAN).append("Press [?] at any time to view controls").period().log();
|
Logger::new()
|
||||||
|
.append("Welcome!")
|
||||||
|
.colour(rltk::CYAN)
|
||||||
|
.append_n("Press [?] at any time to view controls")
|
||||||
|
.period()
|
||||||
|
.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_log() -> Vec<Vec<crate::gamelog::LogFragment>> {
|
pub fn clone_log() -> Vec<Vec<crate::gamelog::LogFragment>> {
|
||||||
|
|
|
||||||
|
|
@ -238,12 +238,13 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||||
for (item_entity, already_equipped, _name) in (&entities, &equipped, &names).join() {
|
for (item_entity, already_equipped, _name) in (&entities, &equipped, &names).join() {
|
||||||
if already_equipped.owner == target && already_equipped.slot == target_slot {
|
if already_equipped.owner == target && already_equipped.slot == target_slot {
|
||||||
to_unequip.push(item_entity);
|
to_unequip.push(item_entity);
|
||||||
if target == *player_entity {
|
/*if target == *player_entity {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger::new()
|
||||||
.append("You unequip the")
|
.append("You unequip the")
|
||||||
.item_name_n(&item_being_used.name)
|
.item_name_n(&item_being_used.name)
|
||||||
.period();
|
.period()
|
||||||
}
|
.log();
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for item in to_unequip.iter() {
|
for item in to_unequip.iter() {
|
||||||
|
|
@ -458,14 +459,25 @@ pub struct ItemRemoveSystem {}
|
||||||
|
|
||||||
impl<'a> System<'a> for ItemRemoveSystem {
|
impl<'a> System<'a> for ItemRemoveSystem {
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
type SystemData =
|
type SystemData = (
|
||||||
(Entities<'a>, WriteStorage<'a, WantsToRemoveItem>, WriteStorage<'a, Equipped>, WriteStorage<'a, InBackpack>);
|
Entities<'a>,
|
||||||
|
ReadExpect<'a, Entity>,
|
||||||
|
ReadStorage<'a, Name>,
|
||||||
|
WriteStorage<'a, WantsToRemoveItem>,
|
||||||
|
WriteStorage<'a, Equipped>,
|
||||||
|
WriteStorage<'a, InBackpack>,
|
||||||
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (entities, mut wants_remove, mut equipped, mut backpack) = data;
|
let (entities, player_entity, names, mut wants_remove, mut equipped, mut backpack) = data;
|
||||||
|
|
||||||
for (entity, to_remove) in (&entities, &wants_remove).join() {
|
for (entity, to_remove) in (&entities, &wants_remove).join() {
|
||||||
equipped.remove(to_remove.item);
|
equipped.remove(to_remove.item);
|
||||||
|
if let Some(name) = names.get(to_remove.item) {
|
||||||
|
if entity == *player_entity {
|
||||||
|
gamelog::Logger::new().append("You unequip the").item_name_n(&name.name).period().log();
|
||||||
|
}
|
||||||
|
}
|
||||||
backpack.insert(to_remove.item, InBackpack { owner: entity }).expect("Unable to insert backpack");
|
backpack.insert(to_remove.item, InBackpack { owner: entity }).expect("Unable to insert backpack");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ extern crate serde;
|
||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
mod components;
|
mod components;
|
||||||
|
pub mod raws;
|
||||||
pub use components::*;
|
pub use components::*;
|
||||||
mod map;
|
mod map;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
|
|
@ -543,6 +544,8 @@ fn main() -> rltk::BError {
|
||||||
gs.ecs.register::<SerializationHelper>();
|
gs.ecs.register::<SerializationHelper>();
|
||||||
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
||||||
|
|
||||||
|
raws::load_raws();
|
||||||
|
|
||||||
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
|
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
|
||||||
gs.ecs.insert(Map::new(1, 64, 64));
|
gs.ecs.insert(Map::new(1, 64, 64));
|
||||||
gs.ecs.insert(Point::new(0, 0));
|
gs.ecs.insert(Point::new(0, 0));
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ mod voronoi_spawning;
|
||||||
use common::*;
|
use common::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use voronoi_spawning::VoronoiSpawning;
|
use voronoi_spawning::VoronoiSpawning;
|
||||||
use wfc::WaveFunctionCollapseBuilder;
|
//use wfc::WaveFunctionCollapseBuilder;
|
||||||
mod room_exploder;
|
mod room_exploder;
|
||||||
use room_exploder::RoomExploder;
|
use room_exploder::RoomExploder;
|
||||||
mod room_corner_rounding;
|
mod room_corner_rounding;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
use super::{
|
use super::{spawner, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType};
|
||||||
spawner::equipment_table, spawner::food_table, spawner::potion_table, spawner::scroll_table, spawner::wand_table,
|
|
||||||
BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType,
|
|
||||||
};
|
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
pub mod prefab_levels;
|
pub mod prefab_levels;
|
||||||
pub mod prefab_sections;
|
pub mod prefab_sections;
|
||||||
|
|
@ -93,7 +90,7 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
'G' => {
|
'G' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "goblin chieftain".to_string()));
|
build_data.spawn_list.push((idx, "goblin_chieftain".to_string()));
|
||||||
}
|
}
|
||||||
'o' => {
|
'o' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
|
|
@ -101,30 +98,27 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
'^' => {
|
'^' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "bear trap".to_string()));
|
build_data.spawn_list.push((idx, "trap_bear".to_string()));
|
||||||
}
|
}
|
||||||
'%' => {
|
'%' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, food_table(build_data.map.depth).roll(rng)));
|
build_data.spawn_list.push((idx, spawner::food_table(build_data.map.depth).roll(rng)));
|
||||||
}
|
}
|
||||||
'!' => {
|
'!' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, potion_table(build_data.map.depth).roll(rng)));
|
build_data.spawn_list.push((idx, spawner::potion_table(build_data.map.depth).roll(rng)));
|
||||||
}
|
}
|
||||||
'/' => {
|
'/' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, wand_table(build_data.map.depth).roll(rng)));
|
build_data.spawn_list.push((idx, spawner::wand_table(build_data.map.depth).roll(rng)));
|
||||||
// Placeholder for wand spawn
|
|
||||||
}
|
}
|
||||||
'?' => {
|
'?' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, scroll_table(build_data.map.depth).roll(rng)));
|
build_data.spawn_list.push((idx, spawner::scroll_table(build_data.map.depth).roll(rng)));
|
||||||
// Placeholder for scroll spawn
|
|
||||||
}
|
}
|
||||||
')' => {
|
')' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, equipment_table(build_data.map.depth).roll(rng)));
|
build_data.spawn_list.push((idx, spawner::equipment_table(build_data.map.depth).roll(rng)));
|
||||||
// Placeholder for scroll spawn
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
rltk::console::log(format!("Unknown glyph '{}' when loading prefab", (ch as u8) as char));
|
rltk::console::log(format!("Unknown glyph '{}' when loading prefab", (ch as u8) as char));
|
||||||
|
|
|
||||||
25
src/raws/item_structs.rs
Normal file
25
src/raws/item_structs.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Item {
|
||||||
|
pub id: String,
|
||||||
|
pub name: Name,
|
||||||
|
pub renderable: Option<Renderable>,
|
||||||
|
pub flags: Option<Vec<String>>,
|
||||||
|
pub effects: Option<HashMap<String, String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Name {
|
||||||
|
pub name: String,
|
||||||
|
pub plural: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Renderable {
|
||||||
|
pub glyph: String,
|
||||||
|
pub fg: String,
|
||||||
|
pub bg: String,
|
||||||
|
pub order: i32,
|
||||||
|
}
|
||||||
20
src/raws/mob_structs.rs
Normal file
20
src/raws/mob_structs.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use super::Renderable;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Mob {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub renderable: Option<Renderable>,
|
||||||
|
pub flags: Option<Vec<String>>,
|
||||||
|
pub stats: MobStats,
|
||||||
|
pub vision_range: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct MobStats {
|
||||||
|
pub max_hp: i32,
|
||||||
|
pub hp: i32,
|
||||||
|
pub power: i32,
|
||||||
|
pub defence: i32,
|
||||||
|
}
|
||||||
62
src/raws/mod.rs
Normal file
62
src/raws/mod.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
mod rawmaster;
|
||||||
|
pub use rawmaster::*;
|
||||||
|
mod item_structs;
|
||||||
|
use item_structs::*;
|
||||||
|
mod mob_structs;
|
||||||
|
use mob_structs::*;
|
||||||
|
mod prop_structs;
|
||||||
|
use prop_structs::Prop;
|
||||||
|
mod spawn_table_structs;
|
||||||
|
use spawn_table_structs::*;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref RAWS: Mutex<RawMaster> = Mutex::new(RawMaster::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Raws {
|
||||||
|
pub items: Vec<Item>,
|
||||||
|
pub mobs: Vec<Mob>,
|
||||||
|
pub props: Vec<Prop>,
|
||||||
|
pub spawn_tables: Vec<SpawnTable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
rltk::embedded_resource!(RAW_ITEMS, "../../raws/items.json");
|
||||||
|
rltk::embedded_resource!(RAW_MOBS, "../../raws/mobs.json");
|
||||||
|
rltk::embedded_resource!(RAW_PROPS, "../../raws/props.json");
|
||||||
|
rltk::embedded_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
|
||||||
|
|
||||||
|
pub fn load_raws() {
|
||||||
|
rltk::link_resource!(RAW_ITEMS, "../../raws/items.json");
|
||||||
|
rltk::link_resource!(RAW_MOBS, "../../raws/mobs.json");
|
||||||
|
rltk::link_resource!(RAW_PROPS, "../../raws/props.json");
|
||||||
|
rltk::link_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
|
||||||
|
|
||||||
|
let decoded_raws = get_decoded_raws();
|
||||||
|
RAWS.lock().unwrap().load(decoded_raws);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_decoded_raws() -> Raws {
|
||||||
|
// Get items from file
|
||||||
|
let mut raw_data = rltk::embedding::EMBED.lock().get_resource("../../raws/items.json".to_string()).unwrap();
|
||||||
|
let mut raw_string = std::str::from_utf8(&raw_data).expect("Unable to convert to a valid UTF-8 string.");
|
||||||
|
let items: Vec<Item> = serde_json::from_str(&raw_string).expect("Unable to parse items.json");
|
||||||
|
// Get mobs from file
|
||||||
|
raw_data = rltk::embedding::EMBED.lock().get_resource("../../raws/mobs.json".to_string()).unwrap();
|
||||||
|
raw_string = std::str::from_utf8(&raw_data).expect("Unable to convert to a valid UTF-8 string.");
|
||||||
|
let mobs: Vec<Mob> = serde_json::from_str(&raw_string).expect("Unable to parse mobs.json");
|
||||||
|
// Get props from file
|
||||||
|
raw_data = rltk::embedding::EMBED.lock().get_resource("../../raws/props.json".to_string()).unwrap();
|
||||||
|
raw_string = std::str::from_utf8(&raw_data).expect("Unable to convert to a valid UTF-8 string.");
|
||||||
|
let props: Vec<Prop> = serde_json::from_str(&raw_string).expect("Unable to parse props.json");
|
||||||
|
// Get spawntables from file
|
||||||
|
raw_data = rltk::embedding::EMBED.lock().get_resource("../../raws/spawn_tables.json".to_string()).unwrap();
|
||||||
|
raw_string = std::str::from_utf8(&raw_data).expect("Unable to convert to a valid UTF-8 string.");
|
||||||
|
let spawn_tables: Vec<SpawnTable> = serde_json::from_str(&raw_string).expect("Unable to parse spawn_tables.json");
|
||||||
|
|
||||||
|
// Create combined raws
|
||||||
|
let raws = Raws { items, mobs, props, spawn_tables };
|
||||||
|
return raws;
|
||||||
|
}
|
||||||
12
src/raws/prop_structs.rs
Normal file
12
src/raws/prop_structs.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
use super::Renderable;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Prop {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub renderable: Option<Renderable>,
|
||||||
|
pub flags: Option<Vec<String>>,
|
||||||
|
pub effects: Option<HashMap<String, String>>,
|
||||||
|
}
|
||||||
248
src/raws/rawmaster.rs
Normal file
248
src/raws/rawmaster.rs
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
use super::Raws;
|
||||||
|
use crate::components::*;
|
||||||
|
use crate::random_table::RandomTable;
|
||||||
|
use specs::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub enum SpawnType {
|
||||||
|
AtPosition { x: i32, y: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RawMaster {
|
||||||
|
raws: Raws,
|
||||||
|
item_index: HashMap<String, usize>,
|
||||||
|
mob_index: HashMap<String, usize>,
|
||||||
|
prop_index: HashMap<String, usize>,
|
||||||
|
table_index: HashMap<String, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawMaster {
|
||||||
|
pub fn empty() -> RawMaster {
|
||||||
|
RawMaster {
|
||||||
|
raws: Raws { items: Vec::new(), mobs: Vec::new(), props: Vec::new(), spawn_tables: Vec::new() },
|
||||||
|
item_index: HashMap::new(),
|
||||||
|
mob_index: HashMap::new(),
|
||||||
|
prop_index: HashMap::new(),
|
||||||
|
table_index: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&mut self, raws: Raws) {
|
||||||
|
self.raws = raws;
|
||||||
|
self.item_index = HashMap::new();
|
||||||
|
for (i, item) in self.raws.items.iter().enumerate() {
|
||||||
|
self.item_index.insert(item.id.clone(), i);
|
||||||
|
}
|
||||||
|
for (i, mob) in self.raws.mobs.iter().enumerate() {
|
||||||
|
self.mob_index.insert(mob.id.clone(), i);
|
||||||
|
}
|
||||||
|
for (i, prop) in self.raws.props.iter().enumerate() {
|
||||||
|
self.prop_index.insert(prop.id.clone(), i);
|
||||||
|
}
|
||||||
|
for (i, table) in self.raws.spawn_tables.iter().enumerate() {
|
||||||
|
self.table_index.insert(table.id.clone(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_named_entity(
|
||||||
|
raws: &RawMaster,
|
||||||
|
new_entity: EntityBuilder,
|
||||||
|
key: &str,
|
||||||
|
pos: SpawnType,
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
) -> Option<Entity> {
|
||||||
|
if raws.item_index.contains_key(key) {
|
||||||
|
return spawn_named_item(raws, new_entity, key, pos);
|
||||||
|
} else if raws.mob_index.contains_key(key) {
|
||||||
|
return spawn_named_mob(raws, new_entity, key, pos, rng);
|
||||||
|
} else if raws.prop_index.contains_key(key) {
|
||||||
|
return spawn_named_prop(raws, new_entity, key, pos);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_named_item(raws: &RawMaster, new_entity: EntityBuilder, key: &str, pos: SpawnType) -> Option<Entity> {
|
||||||
|
if raws.item_index.contains_key(key) {
|
||||||
|
let item_template = &raws.raws.items[raws.item_index[key]];
|
||||||
|
let mut eb = new_entity;
|
||||||
|
|
||||||
|
eb = eb.with(Name { name: item_template.name.name.clone(), plural: item_template.name.plural.clone() });
|
||||||
|
eb = eb.with(Item {});
|
||||||
|
eb = spawn_position(pos, eb);
|
||||||
|
|
||||||
|
if let Some(renderable) = &item_template.renderable {
|
||||||
|
eb = eb.with(get_renderable_component(renderable));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(flags) = &item_template.flags {
|
||||||
|
for flag in flags.iter() {
|
||||||
|
match flag.as_str() {
|
||||||
|
"CONSUMABLE" => eb = eb.with(Consumable {}),
|
||||||
|
"DESTRUCTIBLE" => eb = eb.with(Destructible {}),
|
||||||
|
"CURSED" => eb = eb.with(Cursed {}),
|
||||||
|
"EQUIP_MELEE" => eb = eb.with(Equippable { slot: EquipmentSlot::Melee }),
|
||||||
|
"EQUIP_SHIELD" => eb = eb.with(Equippable { slot: EquipmentSlot::Shield }),
|
||||||
|
"WAND" => eb = eb.with(Wand { uses: 3, max_uses: 3 }),
|
||||||
|
"FOOD" => eb = eb.with(ProvidesNutrition {}),
|
||||||
|
_ => rltk::console::log(format!("Unrecognised flag: {}", flag.as_str())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(effects_list) = &item_template.effects {
|
||||||
|
for effect in effects_list.iter() {
|
||||||
|
let effect_name = effect.0.as_str();
|
||||||
|
match effect_name {
|
||||||
|
"provides_healing" => eb = eb.with(ProvidesHealing { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"ranged" => eb = eb.with(Ranged { range: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"damage" => eb = eb.with(InflictsDamage { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"aoe" => eb = eb.with(AOE { radius: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"confusion" => eb = eb.with(Confusion { turns: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"melee_power_bonus" => eb = eb.with(MeleePowerBonus { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"defence_bonus" => eb = eb.with(DefenceBonus { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"magicmapper" => eb = eb.with(MagicMapper {}),
|
||||||
|
"digger" => eb = eb.with(Digger {}),
|
||||||
|
_ => rltk::console::log(format!("Warning: effect {} not implemented.", effect_name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(eb.build());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_named_mob(
|
||||||
|
raws: &RawMaster,
|
||||||
|
new_entity: EntityBuilder,
|
||||||
|
key: &str,
|
||||||
|
pos: SpawnType,
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
) -> Option<Entity> {
|
||||||
|
if raws.mob_index.contains_key(key) {
|
||||||
|
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
||||||
|
|
||||||
|
// New entity with a position, name, combatstats, and viewshed
|
||||||
|
let mut eb = new_entity;
|
||||||
|
eb = spawn_position(pos, eb);
|
||||||
|
eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() });
|
||||||
|
eb = eb.with(Monster {});
|
||||||
|
let rolled_hp = roll_hit_dice(rng, 1, mob_template.stats.max_hp);
|
||||||
|
eb = eb.with(CombatStats {
|
||||||
|
max_hp: rolled_hp,
|
||||||
|
hp: rolled_hp,
|
||||||
|
power: mob_template.stats.power,
|
||||||
|
defence: mob_template.stats.defence,
|
||||||
|
});
|
||||||
|
eb = eb.with(Viewshed { visible_tiles: Vec::new(), range: mob_template.vision_range, dirty: true });
|
||||||
|
|
||||||
|
if let Some(renderable) = &mob_template.renderable {
|
||||||
|
eb = eb.with(get_renderable_component(renderable));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(flags) = &mob_template.flags {
|
||||||
|
for flag in flags.iter() {
|
||||||
|
match flag.as_str() {
|
||||||
|
"BLOCKS_TILE" => eb = eb.with(BlocksTile {}),
|
||||||
|
_ => rltk::console::log(format!("Unrecognised flag: {}", flag.as_str())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(eb.build());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn roll_hit_dice(rng: &mut rltk::RandomNumberGenerator, n: i32, d: i32) -> i32 {
|
||||||
|
let mut rolled_hp: i32 = 0;
|
||||||
|
|
||||||
|
for _i in 0..n {
|
||||||
|
rolled_hp += rng.roll_dice(1, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rolled_hp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_named_prop(raws: &RawMaster, new_entity: EntityBuilder, key: &str, pos: SpawnType) -> Option<Entity> {
|
||||||
|
if raws.prop_index.contains_key(key) {
|
||||||
|
let prop_template = &raws.raws.props[raws.prop_index[key]];
|
||||||
|
|
||||||
|
let mut eb = new_entity;
|
||||||
|
eb = spawn_position(pos, eb);
|
||||||
|
if let Some(renderable) = &prop_template.renderable {
|
||||||
|
eb = eb.with(get_renderable_component(renderable));
|
||||||
|
}
|
||||||
|
eb = eb.with(Name { name: prop_template.name.clone(), plural: prop_template.name.clone() });
|
||||||
|
|
||||||
|
if let Some(flags) = &prop_template.flags {
|
||||||
|
for flag in flags.iter() {
|
||||||
|
match flag.as_str() {
|
||||||
|
"HIDDEN" => eb = eb.with(Hidden {}),
|
||||||
|
"BLOCKS_TILE" => eb = eb.with(BlocksTile {}),
|
||||||
|
"BLOCKS_VISIBILITY" => eb = eb.with(BlocksVisibility {}),
|
||||||
|
"ENTRY_TRIGGER" => eb = eb.with(EntryTrigger {}),
|
||||||
|
"SINGLE_ACTIVATION" => eb = eb.with(SingleActivation {}),
|
||||||
|
"DOOR" => eb = eb.with(Door { open: false }),
|
||||||
|
_ => rltk::console::log(format!("Unrecognised flag: {}", flag.as_str())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(effects_list) = &prop_template.effects {
|
||||||
|
for effect in effects_list.iter() {
|
||||||
|
let effect_name = effect.0.as_str();
|
||||||
|
match effect_name {
|
||||||
|
"damage" => eb = eb.with(InflictsDamage { amount: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
"confusion" => eb = eb.with(Confusion { turns: effect.1.parse::<i32>().unwrap() }),
|
||||||
|
_ => rltk::console::log(format!("Warning: effect {} not implemented.", effect_name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(eb.build());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_position(pos: SpawnType, new_entity: EntityBuilder) -> EntityBuilder {
|
||||||
|
let mut eb = new_entity;
|
||||||
|
|
||||||
|
match pos {
|
||||||
|
SpawnType::AtPosition { x, y } => {
|
||||||
|
eb = eb.with(Position { x, y });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eb
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_renderable_component(renderable: &super::item_structs::Renderable) -> crate::components::Renderable {
|
||||||
|
crate::components::Renderable {
|
||||||
|
glyph: rltk::to_cp437(renderable.glyph.chars().next().unwrap()),
|
||||||
|
fg: rltk::RGB::from_hex(&renderable.fg).expect("Invalid RGB"),
|
||||||
|
bg: rltk::RGB::from_hex(&renderable.bg).expect("Invalid RGB"),
|
||||||
|
render_order: renderable.order,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn table_by_name(raws: &RawMaster, key: &str, depth: i32) -> RandomTable {
|
||||||
|
if raws.table_index.contains_key(key) {
|
||||||
|
let spawn_table = &raws.raws.spawn_tables[raws.table_index[key]];
|
||||||
|
|
||||||
|
use super::SpawnTableEntry;
|
||||||
|
|
||||||
|
let available_options: Vec<&SpawnTableEntry> =
|
||||||
|
spawn_table.table.iter().filter(|a| depth >= a.min && depth <= a.max).collect();
|
||||||
|
|
||||||
|
let mut rt = RandomTable::new();
|
||||||
|
for e in available_options.iter() {
|
||||||
|
rt = rt.add(e.id.clone(), e.weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
} else {
|
||||||
|
return RandomTable::new().add("debug", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/raws/spawn_table_structs.rs
Normal file
15
src/raws/spawn_table_structs.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct SpawnTable {
|
||||||
|
pub id: String,
|
||||||
|
pub table: Vec<SpawnTableEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct SpawnTableEntry {
|
||||||
|
pub id: String,
|
||||||
|
pub weight: i32,
|
||||||
|
pub min: i32,
|
||||||
|
pub max: i32,
|
||||||
|
}
|
||||||
554
src/spawner.rs
554
src/spawner.rs
|
|
@ -1,11 +1,8 @@
|
||||||
use super::{
|
use super::{
|
||||||
random_table::RandomTable, Attribute, Attributes, BlocksTile, BlocksVisibility, CombatStats, Confusion, Consumable,
|
random_table::RandomTable, raws, Attribute, Attributes, CombatStats, HungerClock, HungerState, Map, Name, Player,
|
||||||
Cursed, DefenceBonus, Destructible, Digger, Door, EntryTrigger, EquipmentSlot, Equippable, Hidden, HungerClock,
|
Position, Rect, Renderable, SerializeMe, TileType, Viewshed,
|
||||||
HungerState, InflictsDamage, Item, MagicMapper, Map, MeleePowerBonus, Mind, Monster, Name, Player, Position,
|
|
||||||
ProvidesHealing, ProvidesNutrition, Ranged, Rect, Renderable, SerializeMe, SingleActivation, TileType, Viewshed,
|
|
||||||
Wand, AOE,
|
|
||||||
};
|
};
|
||||||
use rltk::{console, RandomNumberGenerator, RGB};
|
use rltk::{RandomNumberGenerator, RGB};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use specs::saveload::{MarkedBuilder, SimpleMarker};
|
use specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -38,45 +35,6 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn monster<S: ToString>(ecs: &mut World, x: i32, y: i32, glyph: rltk::FontCharType, name: S, hit_die: i32, power: i32) {
|
|
||||||
let rolled_hp = roll_hit_dice(ecs, 1, hit_die);
|
|
||||||
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable { glyph: glyph, fg: RGB::named(rltk::GREEN), bg: RGB::named(rltk::BLACK), render_order: 1 })
|
|
||||||
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
|
|
||||||
.with(Monster {})
|
|
||||||
.with(Mind {})
|
|
||||||
.with(Name { name: name.to_string(), plural: format!("{}s", name.to_string()) })
|
|
||||||
.with(BlocksTile {})
|
|
||||||
.with(CombatStats { max_hp: rolled_hp, hp: rolled_hp, defence: 0, power: power })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn orc(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
monster(ecs, x, y, rltk::to_cp437('o'), "orc", 8, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn goblin(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
monster(ecs, x, y, rltk::to_cp437('g'), "goblin", 6, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn goblin_chieftain(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
monster(ecs, x, y, rltk::to_cp437('G'), "goblin chieftain", 8, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn roll_hit_dice(ecs: &mut World, n: i32, d: i32) -> i32 {
|
|
||||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
|
||||||
let mut rolled_hp: i32 = 0;
|
|
||||||
|
|
||||||
for _i in 0..n {
|
|
||||||
rolled_hp += rng.roll_dice(1, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rolled_hp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consts
|
// Consts
|
||||||
const MAX_ENTITIES: i32 = 4;
|
const MAX_ENTITIES: i32 = 4;
|
||||||
|
|
||||||
|
|
@ -140,48 +98,26 @@ pub fn spawn_region(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns a named entity (name in tuple.1) at the location in (tuple.0)
|
||||||
pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let width = map.width as usize;
|
let width = map.width as usize;
|
||||||
std::mem::drop(map);
|
|
||||||
let x = (*spawn.0 % width) as i32;
|
let x = (*spawn.0 % width) as i32;
|
||||||
let y = (*spawn.0 / width) as i32;
|
let y = (*spawn.0 / width) as i32;
|
||||||
|
std::mem::drop(map);
|
||||||
|
|
||||||
match spawn.1.as_ref() {
|
let spawn_result = raws::spawn_named_entity(
|
||||||
// Monsters
|
&raws::RAWS.lock().unwrap(),
|
||||||
"goblin" => goblin(ecs, x, y),
|
ecs.create_entity(),
|
||||||
"goblin chieftain" => goblin_chieftain(ecs, x, y),
|
&spawn.1,
|
||||||
"orc" => orc(ecs, x, y),
|
raws::SpawnType::AtPosition { x, y },
|
||||||
// Equipment
|
&mut rltk::RandomNumberGenerator::new(),
|
||||||
"dagger" => dagger(ecs, x, y),
|
);
|
||||||
"shortsword" => shortsword(ecs, x, y),
|
if spawn_result.is_some() {
|
||||||
"buckler" => buckler(ecs, x, y),
|
return;
|
||||||
"shield" => shield(ecs, x, y),
|
|
||||||
// Potions
|
|
||||||
"weak health potion" => weak_health_potion(ecs, x, y),
|
|
||||||
"health potion" => health_potion(ecs, x, y),
|
|
||||||
// Scrolls
|
|
||||||
"fireball scroll" => fireball_scroll(ecs, x, y),
|
|
||||||
"cursed fireball scroll" => cursed_fireball_scroll(ecs, x, y),
|
|
||||||
"confusion scroll" => confusion_scroll(ecs, x, y),
|
|
||||||
"magic missile scroll" => magic_missile_scroll(ecs, x, y),
|
|
||||||
"magic map scroll" => magic_map_scroll(ecs, x, y),
|
|
||||||
"cursed magic map scroll" => cursed_magic_map_scroll(ecs, x, y),
|
|
||||||
// Wands
|
|
||||||
"magic missile wand" => magic_missile_wand(ecs, x, y),
|
|
||||||
"fireball wand" => fireball_wand(ecs, x, y),
|
|
||||||
"confusion wand" => confusion_wand(ecs, x, y),
|
|
||||||
"digging wand" => digging_wand(ecs, x, y),
|
|
||||||
// Food
|
|
||||||
"rations" => rations(ecs, x, y),
|
|
||||||
"apple" => apple(ecs, x, y),
|
|
||||||
// Traps
|
|
||||||
"bear trap" => bear_trap(ecs, x, y),
|
|
||||||
"confusion trap" => confusion_trap(ecs, x, y),
|
|
||||||
// Other
|
|
||||||
"door" => door(ecs, x, y),
|
|
||||||
_ => console::log(format!("Tried to spawn nothing ({}). Bugfix needed!", spawn.1)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rltk::console::log(format!("WARNING: We don't know how to spawn [{}]!", spawn.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12 mobs : 6 items : 2 food : 1 trap
|
// 12 mobs : 6 items : 2 food : 1 trap
|
||||||
|
|
@ -193,15 +129,6 @@ fn debug_table() -> RandomTable {
|
||||||
return RandomTable::new().add("debug", 1);
|
return RandomTable::new().add("debug", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6 goblins : 1 goblin chief : 2 orcs
|
|
||||||
fn mob_table(map_depth: i32) -> RandomTable {
|
|
||||||
return RandomTable::new()
|
|
||||||
// Monsters
|
|
||||||
.add("goblin", 6)
|
|
||||||
.add("goblin chieftain", 1)
|
|
||||||
.add("orc", 2 + map_depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6 equipment : 10 potions : 10 scrolls : 2 cursed scrolls
|
// 6 equipment : 10 potions : 10 scrolls : 2 cursed scrolls
|
||||||
fn item_table(map_depth: i32) -> RandomTable {
|
fn item_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new()
|
return RandomTable::new()
|
||||||
|
|
@ -215,451 +142,30 @@ fn item_table(map_depth: i32) -> RandomTable {
|
||||||
.add_table(wand_table(map_depth));
|
.add_table(wand_table(map_depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn equipment_table(_map_depth: i32) -> RandomTable {
|
pub fn equipment_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("dagger", 4).add("shortsword", 2).add("buckler", 4).add("shield", 2);
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "equipment", map_depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn potion_table(_map_depth: i32) -> RandomTable {
|
pub fn potion_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("weak health potion", 14).add("health potion", 6);
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "potions", map_depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_table(_map_depth: i32) -> RandomTable {
|
pub fn scroll_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new()
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "scrolls", map_depth)
|
||||||
.add("fireball scroll", 2)
|
|
||||||
.add("cursed fireball scroll", 2)
|
|
||||||
.add("confusion scroll", 4)
|
|
||||||
.add("magic missile scroll", 6)
|
|
||||||
.add("magic map scroll", 4)
|
|
||||||
.add("cursed magic map scroll", 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wand_table(_map_depth: i32) -> RandomTable {
|
pub fn wand_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new()
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "wands", map_depth)
|
||||||
.add("magic missile wand", 1)
|
|
||||||
.add("fireball wand", 1)
|
|
||||||
.add("confusion wand", 1)
|
|
||||||
.add("digging wand", 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn food_table(_map_depth: i32) -> RandomTable {
|
pub fn food_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("rations", 1).add("apple", 1);
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "food", map_depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trap_table(_map_depth: i32) -> RandomTable {
|
pub fn mob_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("bear trap", 2).add("confusion trap", 1);
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "mobs", map_depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn door(ecs: &mut World, x: i32, y: i32) {
|
pub fn trap_table(map_depth: i32) -> RandomTable {
|
||||||
ecs.create_entity()
|
raws::table_by_name(&raws::RAWS.lock().unwrap(), "traps", map_depth)
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('+'),
|
|
||||||
fg: RGB::from_f32(0., 1., 1.), // Same colour as stairs, should probably define this somewhere.
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "door".to_string(), plural: "doors".to_string() })
|
|
||||||
.with(BlocksTile {})
|
|
||||||
.with(BlocksVisibility {})
|
|
||||||
.with(Door { open: false })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn health_potion(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('!'),
|
|
||||||
fg: RGB::named(rltk::MAGENTA2),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "potion of health".to_string(), plural: "potions of health".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(ProvidesHealing { amount: 12 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn weak_health_potion(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('!'),
|
|
||||||
fg: RGB::named(rltk::MAGENTA),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "potion of lesser health".to_string(), plural: "potions of lesser health".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(ProvidesHealing { amount: 6 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
fn poison_potion(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('i'),
|
|
||||||
fg: RGB::named(rltk::GREEN),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "potion of ... health?".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(ProvidesHealing { amount: -12 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Scrolls
|
|
||||||
// ~10 range should be considered average here.
|
|
||||||
fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::BLUE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "scroll of magic missile".to_string(), plural: "scrolls of magic missile".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 12 }) // Long range - as far as default vision range
|
|
||||||
.with(InflictsDamage { amount: 10 }) // Low~ damage
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fireball_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::ORANGE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "scroll of fireball".to_string(), plural: "scrolls of fireball".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(InflictsDamage { amount: 20 })
|
|
||||||
.with(AOE { radius: 3 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursed_fireball_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::ORANGE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "cursed scroll of fireball".to_string(), plural: "cursed scrolls of fireball".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Cursed {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(InflictsDamage { amount: 20 })
|
|
||||||
.with(AOE { radius: 3 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confusion_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::PURPLE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "scroll of confusion".to_string(), plural: "scrolls of confusion".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(Confusion { turns: 4 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn magic_map_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::ROYALBLUE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "scroll of magic mapping".to_string(), plural: "scrolls of magic mapping".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(MagicMapper {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursed_magic_map_scroll(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('?'),
|
|
||||||
fg: RGB::named(rltk::ROYALBLUE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name {
|
|
||||||
name: "cursed scroll of magic mapping".to_string(),
|
|
||||||
plural: "cursed scrolls of magic mapping".to_string(),
|
|
||||||
})
|
|
||||||
.with(Item {})
|
|
||||||
.with(Cursed {})
|
|
||||||
.with(MagicMapper {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.with(Destructible {})
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// EQUIPMENT
|
|
||||||
fn dagger(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437(')'),
|
|
||||||
fg: RGB::named(rltk::GREY),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "dagger".to_string(), plural: "daggers".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Equippable { slot: EquipmentSlot::Melee })
|
|
||||||
.with(MeleePowerBonus { amount: 1 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
fn shortsword(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437(')'),
|
|
||||||
fg: RGB::named(rltk::LIGHTGREY),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "shortsword".to_string(), plural: "shortswords".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Equippable { slot: EquipmentSlot::Melee })
|
|
||||||
.with(MeleePowerBonus { amount: 2 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buckler(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('['),
|
|
||||||
fg: RGB::named(rltk::GREY),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "buckler".to_string(), plural: "bucklers".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(DefenceBonus { amount: 1 })
|
|
||||||
.with(Equippable { slot: EquipmentSlot::Shield })
|
|
||||||
.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('['),
|
|
||||||
fg: RGB::named(rltk::LIGHTGREY),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "shield".to_string(), plural: "shields".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(DefenceBonus { amount: 2 })
|
|
||||||
.with(MeleePowerBonus { amount: -1 })
|
|
||||||
.with(Equippable { slot: EquipmentSlot::Shield })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FOOD
|
|
||||||
|
|
||||||
fn rations(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('%'),
|
|
||||||
fg: RGB::named(rltk::LIGHT_SALMON),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "rations".to_string(), plural: "rations".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(ProvidesNutrition {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apple(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('%'),
|
|
||||||
fg: RGB::named(rltk::GREEN),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "apple".to_string(), plural: "apples".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(ProvidesNutrition {})
|
|
||||||
.with(Consumable {})
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// WANDS
|
|
||||||
|
|
||||||
fn fireball_wand(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('/'),
|
|
||||||
fg: RGB::named(rltk::ORANGE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "wand of fireball".to_string(), plural: "wands of fireball".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Wand { uses: 3, max_uses: 3 })
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(InflictsDamage { amount: 20 })
|
|
||||||
.with(AOE { radius: 3 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn magic_missile_wand(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('/'),
|
|
||||||
fg: RGB::named(rltk::BLUE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "wand of magic missile".to_string(), plural: "wands of magic missile".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Wand { uses: 3, max_uses: 3 })
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 12 }) // Long range - as far as default vision range
|
|
||||||
.with(InflictsDamage { amount: 10 }) // Low~ damage
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confusion_wand(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('/'),
|
|
||||||
fg: RGB::named(rltk::PURPLE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "wand of confusion".to_string(), plural: "wands of confusion".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Wand { uses: 3, max_uses: 3 })
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(Confusion { turns: 4 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn digging_wand(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('/'),
|
|
||||||
fg: RGB::named(rltk::PURPLE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "wand of digging".to_string(), plural: "wands of digging".to_string() })
|
|
||||||
.with(Item {})
|
|
||||||
.with(Wand { uses: 3, max_uses: 3 })
|
|
||||||
.with(Destructible {})
|
|
||||||
.with(Ranged { range: 10 })
|
|
||||||
.with(Digger {})
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRAPS
|
|
||||||
fn bear_trap(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('^'),
|
|
||||||
fg: RGB::named(rltk::GREY),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "bear trap".to_string(), plural: "bear traps".to_string() })
|
|
||||||
.with(Hidden {})
|
|
||||||
.with(EntryTrigger {})
|
|
||||||
.with(SingleActivation {})
|
|
||||||
.with(InflictsDamage { amount: 6 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confusion_trap(ecs: &mut World, x: i32, y: i32) {
|
|
||||||
ecs.create_entity()
|
|
||||||
.with(Position { x, y })
|
|
||||||
.with(Renderable {
|
|
||||||
glyph: rltk::to_cp437('^'),
|
|
||||||
fg: RGB::named(rltk::PURPLE),
|
|
||||||
bg: RGB::named(rltk::BLACK),
|
|
||||||
render_order: 2,
|
|
||||||
})
|
|
||||||
.with(Name { name: "magic trap".to_string(), plural: "magic traps".to_string() })
|
|
||||||
.with(Hidden {})
|
|
||||||
.with(EntryTrigger {})
|
|
||||||
.with(SingleActivation {})
|
|
||||||
.with(Confusion { turns: 3 })
|
|
||||||
.marked::<SimpleMarker<SerializeMe>>()
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue