sorry - swapping from rustfmt to prettier-rust
This commit is contained in:
parent
281396f9ce
commit
c2c7e0bd52
93 changed files with 2797 additions and 2021 deletions
3
.prettierrc.json
Normal file
3
.prettierrc.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"printWidth": 120
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{ black_box, criterion_group, criterion_main, Criterion };
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
|
|
||||||
/// Benchmarks methods from rltk used to desaturate non-visible tiles.
|
/// Benchmarks methods from rltk used to desaturate non-visible tiles.
|
||||||
|
|
@ -6,7 +6,7 @@ use rltk::RGB;
|
||||||
// third alternative is directly setting the desaturated value, if it
|
// third alternative is directly setting the desaturated value, if it
|
||||||
// is known in advance.
|
// is known in advance.
|
||||||
fn nonvisible_benchmark(c: &mut Criterion) {
|
fn nonvisible_benchmark(c: &mut Criterion) {
|
||||||
let bg = black_box(RGB::from_f32(0.4, 0., 0.));
|
let bg = black_box(RGB::from_f32(0.4, 0.0, 0.0));
|
||||||
|
|
||||||
c.bench_function("rgb -> greyscale", |b| b.iter(|| bg.to_greyscale()));
|
c.bench_function("rgb -> greyscale", |b| b.iter(|| bg.to_greyscale()));
|
||||||
c.bench_function("rgb -> desaturate", |b| b.iter(|| bg.desaturate()));
|
c.bench_function("rgb -> desaturate", |b| b.iter(|| bg.desaturate()));
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
"renderable": { "glyph": "@", "fg": "#034efc", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "@", "fg": "#034efc", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["NEUTRAL", "RANDOM_PATH", "IS_HUMAN"],
|
"flags": ["NEUTRAL", "RANDOM_PATH", "IS_HUMAN"],
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"vision_range": 4,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
||||||
"equipped": ["equip_shortsword", "equip_body_leather"],
|
"equipped": ["equip_shortsword", "equip_body_leather"],
|
||||||
"quips": ["You wont catch me down the mine.", "Staying out of trouble?"]
|
"quips": ["You wont catch me down the mine.", "Staying out of trouble?"]
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
"renderable": { "glyph": "r", "fg": "#aa6000", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "r", "fg": "#aa6000", "bg": "#000000", "order": 1 },
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"bac": 6,
|
"bac": 6,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }],
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }],
|
||||||
"loot": { "table": "food", "chance": 0.1 }
|
"loot": { "table": "food", "chance": 0.1 }
|
||||||
},
|
},
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
"renderable": { "glyph": "c", "fg": "#BB6000", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "c", "fg": "#BB6000", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["HERBIVORE"],
|
"flags": ["HERBIVORE"],
|
||||||
"bac": 8,
|
"bac": 8,
|
||||||
"vision_range": 4,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -92,7 +92,7 @@
|
||||||
"renderable": { "glyph": "q", "fg": "#a57037", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "q", "fg": "#a57037", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["HERBIVORE"],
|
"flags": ["HERBIVORE"],
|
||||||
"bac": 8,
|
"bac": 8,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
"renderable": { "glyph": "q", "fg": "#e7e7e7", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "q", "fg": "#e7e7e7", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["HERBIVORE", "SMALL_GROUP"],
|
"flags": ["HERBIVORE", "SMALL_GROUP"],
|
||||||
"bac": 10,
|
"bac": 10,
|
||||||
"vision_range": 4,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
"renderable": { "glyph": "c", "fg": "#fae478", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "c", "fg": "#fae478", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["HERBIVORE"],
|
"flags": ["HERBIVORE"],
|
||||||
"bac": 10,
|
"bac": 10,
|
||||||
"vision_range": 4,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -121,7 +121,7 @@
|
||||||
"level": 3,
|
"level": 3,
|
||||||
"bac": 6,
|
"bac": 6,
|
||||||
"speed": 16,
|
"speed": 16,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [
|
"attacks": [
|
||||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d6" },
|
{ "name": "kicks", "hit_bonus": 0, "damage": "1d6" },
|
||||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }
|
{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }
|
||||||
|
|
@ -136,7 +136,7 @@
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"bac": 5,
|
"bac": 5,
|
||||||
"speed": 20,
|
"speed": 20,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [
|
"attacks": [
|
||||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d8" },
|
{ "name": "kicks", "hit_bonus": 0, "damage": "1d8" },
|
||||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }
|
{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
"level": 7,
|
"level": 7,
|
||||||
"bac": 4,
|
"bac": 4,
|
||||||
"speed": 24,
|
"speed": 24,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [
|
"attacks": [
|
||||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d10" },
|
{ "name": "kicks", "hit_bonus": 0, "damage": "1d10" },
|
||||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d4" }
|
{ "name": "bites", "hit_bonus": 0, "damage": "1d4" }
|
||||||
|
|
@ -163,7 +163,7 @@
|
||||||
"flags": ["SMALL_GROUP"],
|
"flags": ["SMALL_GROUP"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"bac": 7,
|
"bac": 7,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }],
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }],
|
||||||
"loot": { "table": "scrolls", "chance": 0.05 }
|
"loot": { "table": "scrolls", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -175,7 +175,7 @@
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"bac": 6,
|
"bac": 6,
|
||||||
"speed": 18,
|
"speed": 18,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"quips": ["<woof!>", "<bark!>", "<grrr..>"],
|
"quips": ["<woof!>", "<bark!>", "<grrr..>"],
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
||||||
},
|
},
|
||||||
|
|
@ -187,7 +187,7 @@
|
||||||
"level": 4,
|
"level": 4,
|
||||||
"bac": 5,
|
"bac": 5,
|
||||||
"speed": 16,
|
"speed": 16,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d6" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -198,7 +198,7 @@
|
||||||
"level": 6,
|
"level": 6,
|
||||||
"bac": 4,
|
"bac": 4,
|
||||||
"speed": 15,
|
"speed": 15,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "2d4" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "2d4" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -208,7 +208,7 @@
|
||||||
"flags": ["SMALL_GROUP", "IS_GNOME"],
|
"flags": ["SMALL_GROUP", "IS_GNOME"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "wands", "chance": 0.05 }
|
"loot": { "table": "wands", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
"flags": ["MINDLESS"],
|
"flags": ["MINDLESS"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 7,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d4" }],
|
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d4" }],
|
||||||
"loot": { "table": "wands", "chance": 0.05 }
|
"loot": { "table": "wands", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -230,7 +230,7 @@
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 9,
|
"speed": 9,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d4" }]
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d4" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -240,7 +240,7 @@
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 7,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d4" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d4" }],
|
||||||
"loot": { "table": "food", "chance": 0.05 }
|
"loot": { "table": "food", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -251,7 +251,7 @@
|
||||||
"flags": ["MINDLESS"],
|
"flags": ["MINDLESS"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 7,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d4" }],
|
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d4" }],
|
||||||
"loot": { "table": "scrolls", "chance": 0.05 }
|
"loot": { "table": "scrolls", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -262,7 +262,7 @@
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 8,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "food", "chance": 0.05 }
|
"loot": { "table": "food", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -274,7 +274,7 @@
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"bac": 9,
|
"bac": 9,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 8,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "potions", "chance": 0.05 }
|
"loot": { "table": "potions", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -286,7 +286,7 @@
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"bac": 10,
|
"bac": 10,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hacks", "hit_bonus": 0, "damage": "1d8" }],
|
"attacks": [{ "name": "hacks", "hit_bonus": 0, "damage": "1d8" }],
|
||||||
"equipped": ["equip_feet_iron"],
|
"equipped": ["equip_feet_iron"],
|
||||||
"loot": { "table": "equipment", "chance": 0.05 }
|
"loot": { "table": "equipment", "chance": 0.05 }
|
||||||
|
|
@ -299,7 +299,7 @@
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"bac": 9,
|
"bac": 9,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 8,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "claws", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "equipment", "chance": 0.05 }
|
"loot": { "table": "equipment", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -310,7 +310,7 @@
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"speed": 6,
|
"speed": 6,
|
||||||
"vision_range": 7,
|
"vision_range": 12,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "2d4" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "2d4" }],
|
||||||
"loot": { "table": "food", "chance": 0.05 }
|
"loot": { "table": "food", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -322,7 +322,7 @@
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"bac": 3,
|
"bac": 3,
|
||||||
"speed": 12,
|
"speed": 12,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }],
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }],
|
||||||
"loot": { "table": "scrolls", "chance": 0.05 }
|
"loot": { "table": "scrolls", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -332,7 +332,7 @@
|
||||||
"renderable": { "glyph": "d", "fg": "#AA5500", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "d", "fg": "#AA5500", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["CARNIVORE", "SMALL_GROUP"],
|
"flags": ["CARNIVORE", "SMALL_GROUP"],
|
||||||
"bac": 7,
|
"bac": 7,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -341,7 +341,7 @@
|
||||||
"renderable": { "glyph": "d", "fg": "#FF0000", "bg": "#000000", "order": 1 },
|
"renderable": { "glyph": "d", "fg": "#FF0000", "bg": "#000000", "order": 1 },
|
||||||
"flags": ["CARNIVORE"],
|
"flags": ["CARNIVORE"],
|
||||||
"bac": 7,
|
"bac": 7,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -351,7 +351,7 @@
|
||||||
"flags": ["CARNIVORE", "SMALL_GROUP"],
|
"flags": ["CARNIVORE", "SMALL_GROUP"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"bac": 7,
|
"bac": 7,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d4" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d4" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -361,7 +361,7 @@
|
||||||
"flags": ["CARNIVORE"],
|
"flags": ["CARNIVORE"],
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"bac": 4,
|
"bac": 4,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "2d4" }]
|
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "2d4" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -371,7 +371,7 @@
|
||||||
"flags": [],
|
"flags": [],
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"speed": 9,
|
"speed": 9,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d8" }],
|
||||||
"loot": { "table": "wands", "chance": 0.05 }
|
"loot": { "table": "wands", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -382,7 +382,7 @@
|
||||||
"flags": ["SMALL_GROUP"],
|
"flags": ["SMALL_GROUP"],
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"speed": 9,
|
"speed": 9,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "equipment", "chance": 0.05 }
|
"loot": { "table": "equipment", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -393,7 +393,7 @@
|
||||||
"flags": ["LARGE_GROUP"],
|
"flags": ["LARGE_GROUP"],
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"speed": 9,
|
"speed": 9,
|
||||||
"vision_range": 11,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "1d6" }],
|
||||||
"loot": { "table": "equipment", "chance": 0.05 }
|
"loot": { "table": "equipment", "chance": 0.05 }
|
||||||
},
|
},
|
||||||
|
|
@ -404,7 +404,7 @@
|
||||||
"flags": ["MULTIATTACK"],
|
"flags": ["MULTIATTACK"],
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"speed": 5,
|
"speed": 5,
|
||||||
"vision_range": 12,
|
"vision_range": 16,
|
||||||
"attacks": [
|
"attacks": [
|
||||||
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" },
|
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" },
|
||||||
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" }
|
{ "name": "hits", "hit_bonus": 0, "damage": "2d4" }
|
||||||
|
|
@ -419,7 +419,7 @@
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"bac": 5,
|
"bac": 5,
|
||||||
"speed": 10,
|
"speed": 10,
|
||||||
"vision_range": 8,
|
"vision_range": 16,
|
||||||
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "2d5" }],
|
"attacks": [{ "name": "hits", "hit_bonus": 0, "damage": "2d5" }],
|
||||||
"loot": { "table": "food", "chance": 0.05 }
|
"loot": { "table": "food", "chance": 0.05 }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{raws::Reaction, Faction, HasAncestry, Map, Position, TakingTurn, WantsToMelee};
|
use crate::{ raws::Reaction, Faction, HasAncestry, Map, Position, TakingTurn, WantsToMelee };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct AdjacentAI {}
|
pub struct AdjacentAI {}
|
||||||
|
|
@ -34,22 +34,22 @@ impl<'a> System<'a> for AdjacentAI {
|
||||||
evaluate(entity, idx + 1, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx + 1, &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y > 0 {
|
if pos.y > 0 {
|
||||||
evaluate(entity, idx - w as usize, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx - (w as usize), &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y < h - 1 {
|
if pos.y < h - 1 {
|
||||||
evaluate(entity, idx + w as usize, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx + (w as usize), &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y > 0 && pos.x > 0 {
|
if pos.y > 0 && pos.x > 0 {
|
||||||
evaluate(entity, (idx - w as usize) - 1, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx - (w as usize) - 1, &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y > 0 && pos.x < w - 1 {
|
if pos.y > 0 && pos.x < w - 1 {
|
||||||
evaluate(entity, (idx - w as usize) + 1, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx - (w as usize) + 1, &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y < h - 1 && pos.x > 0 {
|
if pos.y < h - 1 && pos.x > 0 {
|
||||||
evaluate(entity, (idx + w as usize) - 1, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx + (w as usize) - 1, &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
if pos.y < h - 1 && pos.x < w - 1 {
|
if pos.y < h - 1 && pos.x < w - 1 {
|
||||||
evaluate(entity, (idx + w as usize) + 1, &ancestries, &factions, &mut reactions);
|
evaluate(entity, idx + (w as usize) + 1, &ancestries, &factions, &mut reactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
|
|
@ -79,7 +79,7 @@ fn evaluate(
|
||||||
idx: usize,
|
idx: usize,
|
||||||
ancestries: &ReadStorage<HasAncestry>,
|
ancestries: &ReadStorage<HasAncestry>,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
reactions: &mut Vec<(Entity, Reaction)>,
|
reactions: &mut Vec<(Entity, Reaction)>
|
||||||
) {
|
) {
|
||||||
crate::spatial::for_each_tile_content(idx, |other_entity| {
|
crate::spatial::for_each_tile_content(idx, |other_entity| {
|
||||||
let result = crate::raws::get_reactions(
|
let result = crate::raws::get_reactions(
|
||||||
|
|
@ -87,7 +87,7 @@ fn evaluate(
|
||||||
other_entity,
|
other_entity,
|
||||||
&factions,
|
&factions,
|
||||||
&ancestries,
|
&ancestries,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
&crate::raws::RAWS.lock().unwrap()
|
||||||
);
|
);
|
||||||
reactions.push((other_entity, result));
|
reactions.push((other_entity, result));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToApproach};
|
use crate::{ EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToApproach };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -29,19 +29,23 @@ impl<'a> System<'a> for ApproachAI {
|
||||||
entities,
|
entities,
|
||||||
) = data;
|
) = data;
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, approach, mut viewshed, _turn) in
|
for (entity, mut pos, approach, mut viewshed, _turn) in (
|
||||||
(&entities, &mut positions, &wants_to_approach, &mut viewsheds, &turns).join()
|
&entities,
|
||||||
{
|
&mut positions,
|
||||||
|
&wants_to_approach,
|
||||||
|
&mut viewsheds,
|
||||||
|
&turns,
|
||||||
|
).join() {
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
let path = a_star_search(
|
let path = a_star_search(
|
||||||
map.xy_idx(pos.x, pos.y) as i32,
|
map.xy_idx(pos.x, pos.y) as i32,
|
||||||
map.xy_idx(approach.idx % map.width, approach.idx / map.width) as i32,
|
map.xy_idx(approach.idx % map.width, approach.idx / map.width) as i32,
|
||||||
&mut *map,
|
&mut *map
|
||||||
);
|
);
|
||||||
if path.success && path.steps.len() > 1 {
|
if path.success && path.steps.len() > 1 {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
pos.x = path.steps[1] as i32 % map.width;
|
pos.x = (path.steps[1] as i32) % map.width;
|
||||||
pos.y = path.steps[1] as i32 / map.width;
|
pos.y = (path.steps[1] as i32) / map.width;
|
||||||
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
crate::spatial::move_entity(entity, idx, new_idx);
|
crate::spatial::move_entity(entity, idx, new_idx);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Chasing, EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed};
|
use crate::{ Chasing, EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -48,20 +48,24 @@ impl<'a> System<'a> for ChaseAI {
|
||||||
// stored in the HashMap. If successful, follow the path. If not, remove
|
// stored in the HashMap. If successful, follow the path. If not, remove
|
||||||
// the chasing component.
|
// the chasing component.
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, _turn, mut pos, _chase, mut viewshed) in
|
for (entity, _turn, mut pos, _chase, mut viewshed) in (
|
||||||
(&entities, &turns, &mut positions, &chasing, &mut viewsheds).join()
|
&entities,
|
||||||
{
|
&turns,
|
||||||
|
&mut positions,
|
||||||
|
&chasing,
|
||||||
|
&mut viewsheds,
|
||||||
|
).join() {
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
let target_pos = targets[&entity];
|
let target_pos = targets[&entity];
|
||||||
let path = a_star_search(
|
let path = a_star_search(
|
||||||
map.xy_idx(pos.x, pos.y) as i32,
|
map.xy_idx(pos.x, pos.y) as i32,
|
||||||
map.xy_idx(target_pos.0, target_pos.1) as i32,
|
map.xy_idx(target_pos.0, target_pos.1) as i32,
|
||||||
&mut *map,
|
&mut *map
|
||||||
);
|
);
|
||||||
if path.success && path.steps.len() > 1 && path.steps.len() < MAX_CHASE_DISTANCE {
|
if path.success && path.steps.len() > 1 && path.steps.len() < MAX_CHASE_DISTANCE {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
pos.x = path.steps[1] as i32 % map.width;
|
pos.x = (path.steps[1] as i32) % map.width;
|
||||||
pos.y = path.steps[1] as i32 / map.width;
|
pos.y = (path.steps[1] as i32) / map.width;
|
||||||
entity_moved.insert(entity, EntityMoved {}).expect("Failed to insert EntityMoved");
|
entity_moved.insert(entity, EntityMoved {}).expect("Failed to insert EntityMoved");
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
crate::spatial::move_entity(entity, idx, new_idx);
|
crate::spatial::move_entity(entity, idx, new_idx);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{tile_walkable, EntityMoved, Map, MoveMode, Movement, Position, TakingTurn, Telepath, Viewshed};
|
use crate::{ tile_walkable, EntityMoved, Map, MoveMode, Movement, Position, TakingTurn, Telepath, Viewshed };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
// Rolling a 1d8+x to decide where to move, where x are the number
|
// Rolling a 1d8+x to decide where to move, where x are the number
|
||||||
|
|
@ -33,9 +33,13 @@ impl<'a> System<'a> for DefaultAI {
|
||||||
entities,
|
entities,
|
||||||
) = data;
|
) = data;
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, _turn, mut pos, mut move_mode, mut viewshed) in
|
for (entity, _turn, mut pos, mut move_mode, mut viewshed) in (
|
||||||
(&entities, &turns, &mut positions, &mut move_mode, &mut viewsheds).join()
|
&entities,
|
||||||
{
|
&turns,
|
||||||
|
&mut positions,
|
||||||
|
&mut move_mode,
|
||||||
|
&mut viewsheds,
|
||||||
|
).join() {
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
match &mut move_mode.mode {
|
match &mut move_mode.mode {
|
||||||
Movement::Static => {}
|
Movement::Static => {}
|
||||||
|
|
@ -44,25 +48,33 @@ impl<'a> System<'a> for DefaultAI {
|
||||||
let mut y = pos.y;
|
let mut y = pos.y;
|
||||||
let move_roll = rng.roll_dice(1, 8 + CHANCE_OF_REMAINING_STATIONARY);
|
let move_roll = rng.roll_dice(1, 8 + CHANCE_OF_REMAINING_STATIONARY);
|
||||||
match move_roll {
|
match move_roll {
|
||||||
1 => x -= 1,
|
1 => {
|
||||||
2 => x += 1,
|
x -= 1;
|
||||||
3 => y -= 1,
|
}
|
||||||
4 => y += 1,
|
2 => {
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
y -= 1;
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
5 => {
|
5 => {
|
||||||
x -= 1;
|
x -= 1;
|
||||||
y -= 1
|
y -= 1;
|
||||||
}
|
}
|
||||||
6 => {
|
6 => {
|
||||||
x += 1;
|
x += 1;
|
||||||
y -= 1
|
y -= 1;
|
||||||
}
|
}
|
||||||
7 => {
|
7 => {
|
||||||
x -= 1;
|
x -= 1;
|
||||||
y += 1
|
y += 1;
|
||||||
}
|
}
|
||||||
8 => {
|
8 => {
|
||||||
x += 1;
|
x += 1;
|
||||||
y += 1
|
y += 1;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +100,8 @@ impl<'a> System<'a> for DefaultAI {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
if path.len() > 1 {
|
if path.len() > 1 {
|
||||||
if !crate::spatial::is_blocked(path[1] as usize) {
|
if !crate::spatial::is_blocked(path[1] as usize) {
|
||||||
pos.x = path[1] as i32 % map.width;
|
pos.x = (path[1] as i32) % map.width;
|
||||||
pos.y = path[1] as i32 / map.width;
|
pos.y = (path[1] as i32) / map.width;
|
||||||
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
let new_idx = map.xy_idx(pos.x, pos.y);
|
||||||
crate::spatial::move_entity(entity, idx, new_idx);
|
crate::spatial::move_entity(entity, idx, new_idx);
|
||||||
|
|
@ -110,10 +122,12 @@ impl<'a> System<'a> for DefaultAI {
|
||||||
let path = rltk::a_star_search(
|
let path = rltk::a_star_search(
|
||||||
map.xy_idx(pos.x, pos.y) as i32,
|
map.xy_idx(pos.x, pos.y) as i32,
|
||||||
map.xy_idx(target_x, target_y) as i32,
|
map.xy_idx(target_x, target_y) as i32,
|
||||||
&mut *map,
|
&mut *map
|
||||||
);
|
);
|
||||||
if path.success && path.steps.len() > 1 {
|
if path.success && path.steps.len() > 1 {
|
||||||
move_mode.mode = Movement::RandomWaypoint { path: Some(path.steps) };
|
move_mode.mode = Movement::RandomWaypoint {
|
||||||
|
path: Some(path.steps),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{gamelog, Attributes, Burden, EquipmentChanged, Equipped, InBackpack, Item, Pools};
|
use crate::{ gamelog, Attributes, Burden, EquipmentChanged, Equipped, InBackpack, Item, Pools };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ impl<'a> System<'a> for EncumbranceSystem {
|
||||||
if let Some(attr) = attributes.get(*entity) {
|
if let Some(attr) = attributes.get(*entity) {
|
||||||
let carry_capacity_lbs =
|
let carry_capacity_lbs =
|
||||||
(attr.strength.base + attr.strength.modifiers) * CARRY_CAPACITY_PER_STRENGTH;
|
(attr.strength.base + attr.strength.modifiers) * CARRY_CAPACITY_PER_STRENGTH;
|
||||||
if pool.weight as i32 > 3 * carry_capacity_lbs {
|
if (pool.weight as i32) > 3 * carry_capacity_lbs {
|
||||||
// Overloaded
|
// Overloaded
|
||||||
burdened
|
burdened
|
||||||
.insert(*entity, Burden { level: crate::BurdenLevel::Overloaded })
|
.insert(*entity, Burden { level: crate::BurdenLevel::Overloaded })
|
||||||
|
|
@ -60,7 +60,7 @@ impl<'a> System<'a> for EncumbranceSystem {
|
||||||
if *entity == *player {
|
if *entity == *player {
|
||||||
gamelog::Logger::new().append("You're overloaded!").log();
|
gamelog::Logger::new().append("You're overloaded!").log();
|
||||||
}
|
}
|
||||||
} else if pool.weight as i32 > 2 * carry_capacity_lbs {
|
} else if (pool.weight as i32) > 2 * carry_capacity_lbs {
|
||||||
// Strained
|
// Strained
|
||||||
burdened
|
burdened
|
||||||
.insert(*entity, Burden { level: crate::BurdenLevel::Strained })
|
.insert(*entity, Burden { level: crate::BurdenLevel::Strained })
|
||||||
|
|
@ -68,7 +68,7 @@ impl<'a> System<'a> for EncumbranceSystem {
|
||||||
if *entity == *player {
|
if *entity == *player {
|
||||||
gamelog::Logger::new().append("You're strained.").log();
|
gamelog::Logger::new().append("You're strained.").log();
|
||||||
}
|
}
|
||||||
} else if pool.weight as i32 > carry_capacity_lbs {
|
} else if (pool.weight as i32) > carry_capacity_lbs {
|
||||||
// Burdened
|
// Burdened
|
||||||
burdened
|
burdened
|
||||||
.insert(*entity, Burden { level: crate::BurdenLevel::Burdened })
|
.insert(*entity, Burden { level: crate::BurdenLevel::Burdened })
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::config::entity::*;
|
use crate::config::entity::*;
|
||||||
use crate::{Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, TakingTurn, LOG_TICKS};
|
use crate::{ Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, TakingTurn, LOG_TICKS };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
// Every entity has a POTENTIAL equal to their speed.
|
// Every entity has a POTENTIAL equal to their speed.
|
||||||
let mut energy_potential: i32 = (energy.speed as f32 * burden_modifier) as i32;
|
let mut energy_potential: i32 = ((energy.speed as f32) * burden_modifier) as i32;
|
||||||
// Increment current energy by NORMAL_SPEED for every
|
// Increment current energy by NORMAL_SPEED for every
|
||||||
// whole number of NORMAL_SPEEDS in their POTENTIAL.
|
// whole number of NORMAL_SPEEDS in their POTENTIAL.
|
||||||
while energy_potential >= NORMAL_SPEED {
|
while energy_potential >= NORMAL_SPEED {
|
||||||
|
|
@ -103,10 +103,9 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
|
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
|
||||||
if LOG_TICKS {
|
if LOG_TICKS {
|
||||||
let name = if let Some(name) = names.get(entity) { &name.name } else { "Unknown entity" };
|
let name = if let Some(name) = names.get(entity) { &name.name } else { "Unknown entity" };
|
||||||
console::log(format!(
|
console::log(
|
||||||
"ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].",
|
format!("ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].", name, energy.current)
|
||||||
name, energy.current
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToFlee};
|
use crate::{ EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToFlee };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -29,9 +29,13 @@ impl<'a> System<'a> for FleeAI {
|
||||||
entities,
|
entities,
|
||||||
) = data;
|
) = data;
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, _turn, mut pos, fleeing, mut viewshed) in
|
for (entity, _turn, mut pos, fleeing, mut viewshed) in (
|
||||||
(&entities, &turns, &mut positions, &wants_to_flee, &mut viewsheds).join()
|
&entities,
|
||||||
{
|
&turns,
|
||||||
|
&mut positions,
|
||||||
|
&wants_to_flee,
|
||||||
|
&mut viewsheds,
|
||||||
|
).join() {
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
let my_idx = map.xy_idx(pos.x, pos.y);
|
let my_idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.populate_blocked();
|
map.populate_blocked();
|
||||||
|
|
@ -44,8 +48,8 @@ impl<'a> System<'a> for FleeAI {
|
||||||
if let Some(is_telepath) = telepaths.get_mut(entity) {
|
if let Some(is_telepath) = telepaths.get_mut(entity) {
|
||||||
is_telepath.dirty = true;
|
is_telepath.dirty = true;
|
||||||
}
|
}
|
||||||
pos.x = flee_target as i32 % map.width;
|
pos.x = (flee_target as i32) % map.width;
|
||||||
pos.y = flee_target as i32 / map.width;
|
pos.y = (flee_target as i32) / map.width;
|
||||||
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub use quip_system::QuipSystem;
|
||||||
mod regen_system;
|
mod regen_system;
|
||||||
pub use regen_system::RegenSystem;
|
pub use regen_system::RegenSystem;
|
||||||
mod encumbrance_system;
|
mod encumbrance_system;
|
||||||
pub use encumbrance_system::{EncumbranceSystem, CARRY_CAPACITY_PER_STRENGTH};
|
pub use encumbrance_system::{ EncumbranceSystem, CARRY_CAPACITY_PER_STRENGTH };
|
||||||
mod adjacent_ai_system;
|
mod adjacent_ai_system;
|
||||||
pub use adjacent_ai_system::AdjacentAI;
|
pub use adjacent_ai_system::AdjacentAI;
|
||||||
mod visible_ai_system;
|
mod visible_ai_system;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{gamelog, gui::renderable_colour, Name, Quips, Renderable, TakingTurn, Viewshed};
|
use crate::{ gamelog, gui::renderable_colour, Name, Quips, Renderable, TakingTurn, Viewshed };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -26,7 +26,8 @@ impl<'a> System<'a> for QuipSystem {
|
||||||
} else {
|
} else {
|
||||||
(rng.roll_dice(1, quip.available.len() as i32) - 1) as usize
|
(rng.roll_dice(1, quip.available.len() as i32) - 1) as usize
|
||||||
};
|
};
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity))
|
.colour(renderable_colour(&renderables, entity))
|
||||||
.append(&name.name)
|
.append(&name.name)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, gui::Class, Attributes, Clock, HasClass, Player, Pools, Position, RandomNumberGenerator, TakingTurn,
|
gamelog,
|
||||||
|
gui::Class,
|
||||||
|
Attributes,
|
||||||
|
Clock,
|
||||||
|
HasClass,
|
||||||
|
Player,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
RandomNumberGenerator,
|
||||||
|
TakingTurn,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -55,8 +64,8 @@ impl<'a> System<'a> for RegenSystem {
|
||||||
for (e, _p, pool) in (&entities, &positions, &mut pools).join() {
|
for (e, _p, pool) in (&entities, &positions, &mut pools).join() {
|
||||||
let is_wizard = if let Some(class) = classes.get(e) { class.name == Class::Wizard } else { false };
|
let is_wizard = if let Some(class) = classes.get(e) { class.name == Class::Wizard } else { false };
|
||||||
let numerator = if is_wizard { WIZARD_MP_REGEN_MOD } else { NONWIZARD_MP_REGEN_MOD };
|
let numerator = if is_wizard { WIZARD_MP_REGEN_MOD } else { NONWIZARD_MP_REGEN_MOD };
|
||||||
let multiplier: f32 = numerator as f32 / MP_REGEN_DIVISOR as f32;
|
let multiplier: f32 = (numerator as f32) / (MP_REGEN_DIVISOR as f32);
|
||||||
let mp_regen_tick = ((MP_REGEN_BASE - pool.level) as f32 * multiplier) as i32;
|
let mp_regen_tick = (((MP_REGEN_BASE - pool.level) as f32) * multiplier) as i32;
|
||||||
if current_turn % mp_regen_tick == 0 {
|
if current_turn % mp_regen_tick == 0 {
|
||||||
try_mana_regen_tick(pool, rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes)));
|
try_mana_regen_tick(pool, rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes)));
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +75,7 @@ impl<'a> System<'a> for RegenSystem {
|
||||||
|
|
||||||
fn get_player_hp_regen_turn(level: i32) -> i32 {
|
fn get_player_hp_regen_turn(level: i32) -> i32 {
|
||||||
if level < 10 {
|
if level < 10 {
|
||||||
return (42 / (level + 2)) + 1;
|
return 42 / (level + 2) + 1;
|
||||||
} else {
|
} else {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +95,7 @@ fn try_hp_regen_tick(pool: &mut Pools, amount: i32) {
|
||||||
|
|
||||||
fn get_mana_regen_per_tick(e: Entity, attributes: &ReadStorage<Attributes>) -> i32 {
|
fn get_mana_regen_per_tick(e: Entity, attributes: &ReadStorage<Attributes>) -> i32 {
|
||||||
let regen = if let Some(attributes) = attributes.get(e) {
|
let regen = if let Some(attributes) = attributes.get(e) {
|
||||||
((attributes.intelligence.bonus + attributes.wisdom.bonus) / 2) + MIN_MP_REGEN_PER_TURN
|
(attributes.intelligence.bonus + attributes.wisdom.bonus) / 2 + MIN_MP_REGEN_PER_TURN
|
||||||
} else {
|
} else {
|
||||||
MIN_MP_REGEN_PER_TURN
|
MIN_MP_REGEN_PER_TURN
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
effects::{add_effect, EffectType, Targets},
|
effects::{ add_effect, EffectType, Targets },
|
||||||
gamelog,
|
gamelog,
|
||||||
gui::renderable_colour,
|
gui::renderable_colour,
|
||||||
Clock, Confusion, Name, Renderable, TakingTurn,
|
Clock,
|
||||||
|
Confusion,
|
||||||
|
Name,
|
||||||
|
Renderable,
|
||||||
|
TakingTurn,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -63,7 +67,7 @@ impl<'a> System<'a> for TurnStatusSystem {
|
||||||
lifespan: 200.0,
|
lifespan: 200.0,
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
},
|
},
|
||||||
Targets::Entity { target: entity },
|
Targets::Entity { target: entity }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
not_my_turn.push(entity);
|
not_my_turn.push(entity);
|
||||||
|
|
@ -93,7 +97,7 @@ impl<'a> System<'a> for TurnStatusSystem {
|
||||||
lifespan: 200.0,
|
lifespan: 200.0,
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
},
|
},
|
||||||
Targets::Entity { target: entity },
|
Targets::Entity { target: entity }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
raws::Reaction, Chasing, Faction, HasAncestry, Map, Mind, Position, TakingTurn, Telepath, Viewshed,
|
raws::Reaction,
|
||||||
WantsToApproach, WantsToFlee,
|
Chasing,
|
||||||
|
Faction,
|
||||||
|
HasAncestry,
|
||||||
|
Map,
|
||||||
|
Mind,
|
||||||
|
Position,
|
||||||
|
TakingTurn,
|
||||||
|
Telepath,
|
||||||
|
Viewshed,
|
||||||
|
WantsToApproach,
|
||||||
|
WantsToFlee,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -70,10 +80,10 @@ impl<'a> System<'a> for VisibleAI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reactions.sort_by(|(a, _, _), (b, _, _)| {
|
reactions.sort_by(|(a, _, _), (b, _, _)| {
|
||||||
let (a_x, a_y) = (a % map.width as usize, a / map.width as usize);
|
let (a_x, a_y) = (a % (map.width as usize), a / (map.width as usize));
|
||||||
let dist_a = DistanceAlg::PythagorasSquared.distance2d(Point::new(a_x, a_y), Point::new(pos.x, pos.y));
|
let dist_a = DistanceAlg::PythagorasSquared.distance2d(Point::new(a_x, a_y), Point::new(pos.x, pos.y));
|
||||||
let dist_a_estimate = dist_a as i32;
|
let dist_a_estimate = dist_a as i32;
|
||||||
let (b_x, b_y) = (b % map.width as usize, b / map.width as usize);
|
let (b_x, b_y) = (b % (map.width as usize), b / (map.width as usize));
|
||||||
let dist_b = DistanceAlg::PythagorasSquared.distance2d(Point::new(b_x, b_y), Point::new(pos.x, pos.y));
|
let dist_b = DistanceAlg::PythagorasSquared.distance2d(Point::new(b_x, b_y), Point::new(pos.x, pos.y));
|
||||||
let dist_b_estimate = dist_b as i32;
|
let dist_b_estimate = dist_b as i32;
|
||||||
return dist_b_estimate.cmp(&dist_a_estimate);
|
return dist_b_estimate.cmp(&dist_a_estimate);
|
||||||
|
|
@ -110,7 +120,7 @@ fn evaluate(
|
||||||
ancestries: &ReadStorage<HasAncestry>,
|
ancestries: &ReadStorage<HasAncestry>,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
reactions: &mut Vec<(usize, Reaction, Entity)>,
|
reactions: &mut Vec<(usize, Reaction, Entity)>,
|
||||||
minds: Option<&ReadStorage<Mind>>,
|
minds: Option<&ReadStorage<Mind>>
|
||||||
) {
|
) {
|
||||||
crate::spatial::for_each_tile_content(idx, |other_entity| {
|
crate::spatial::for_each_tile_content(idx, |other_entity| {
|
||||||
let mut check = true;
|
let mut check = true;
|
||||||
|
|
@ -129,7 +139,7 @@ fn evaluate(
|
||||||
other_entity,
|
other_entity,
|
||||||
&factions,
|
&factions,
|
||||||
&ancestries,
|
&ancestries,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
&crate::raws::RAWS.lock().unwrap()
|
||||||
),
|
),
|
||||||
other_entity,
|
other_entity,
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Hidden, Map, Mind, Position, Prop, Renderable};
|
use super::{ Hidden, Map, Mind, Position, Prop, Renderable };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
|
|
@ -15,8 +15,8 @@ pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32, i
|
||||||
|
|
||||||
let min_x = player_pos.x - centre_x;
|
let min_x = player_pos.x - centre_x;
|
||||||
let min_y = player_pos.y - centre_y;
|
let min_y = player_pos.y - centre_y;
|
||||||
let max_x = min_x + x_chars as i32;
|
let max_x = min_x + (x_chars as i32);
|
||||||
let max_y = min_y + y_chars as i32;
|
let max_y = min_y + (y_chars as i32);
|
||||||
|
|
||||||
(min_x, max_x, min_y, max_y, x_offset, y_offset)
|
(min_x, max_x, min_y, max_y, x_offset, y_offset)
|
||||||
}
|
}
|
||||||
|
|
@ -33,8 +33,11 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
|
||||||
if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height {
|
if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height {
|
||||||
let idx = map.xy_idx(t_x, t_y);
|
let idx = map.xy_idx(t_x, t_y);
|
||||||
if map.revealed_tiles[idx] {
|
if map.revealed_tiles[idx] {
|
||||||
let (glyph, fg, bg) =
|
let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id(
|
||||||
crate::map::themes::get_tile_renderables_for_id(idx, &*map, Some(*ecs.fetch::<Point>()));
|
idx,
|
||||||
|
&*map,
|
||||||
|
Some(*ecs.fetch::<Point>())
|
||||||
|
);
|
||||||
ctx.set(x + x_offset, y + y_offset, fg, bg, glyph);
|
ctx.set(x + x_offset, y + y_offset, fg, bg, glyph);
|
||||||
}
|
}
|
||||||
} else if SHOW_BOUNDARIES {
|
} else if SHOW_BOUNDARIES {
|
||||||
|
|
@ -108,9 +111,9 @@ pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
|
||||||
let center_y = (y_chars / 2) as i32;
|
let center_y = (y_chars / 2) as i32;
|
||||||
|
|
||||||
let min_x = player_pos.x - center_x;
|
let min_x = player_pos.x - center_x;
|
||||||
let max_x = min_x + x_chars as i32;
|
let max_x = min_x + (x_chars as i32);
|
||||||
let min_y = player_pos.y - center_y;
|
let min_y = player_pos.y - center_y;
|
||||||
let max_y = min_y + y_chars as i32;
|
let max_y = min_y + (y_chars as i32);
|
||||||
|
|
||||||
let map_width = map.width;
|
let map_width = map.width;
|
||||||
let map_height = map.height;
|
let map_height = map.height;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::gui::Ancestry;
|
use crate::gui::Ancestry;
|
||||||
use crate::gui::Class;
|
use crate::gui::Class;
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
use specs::error::NoError;
|
use specs::error::NoError;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use specs::saveload::{ConvertSaveload, Marker};
|
use specs::saveload::{ ConvertSaveload, Marker };
|
||||||
use specs_derive::*;
|
use specs_derive::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -57,7 +57,9 @@ pub struct Faction {
|
||||||
pub enum Movement {
|
pub enum Movement {
|
||||||
Static,
|
Static,
|
||||||
Random,
|
Random,
|
||||||
RandomWaypoint { path: Option<Vec<usize>> },
|
RandomWaypoint {
|
||||||
|
path: Option<Vec<usize>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
|
@ -237,7 +239,7 @@ pub struct Beatitude {
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub weight: f32, // in lbs
|
pub weight: f32, // in lbs
|
||||||
pub value: f32, // base
|
pub value: f32, // base
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// prettier-ignore
|
||||||
|
#[rustfmt::skip]
|
||||||
pub const DEFAULT_VIEWSHED_STANDARD: i32 = 16; // Standard viewshed radius for almost all entities.
|
pub const DEFAULT_VIEWSHED_STANDARD: i32 = 16; // Standard viewshed radius for almost all entities.
|
||||||
|
|
||||||
pub const NORMAL_SPEED: i32 = 12; // Normal speed for almost all entities.
|
pub const NORMAL_SPEED: i32 = 12; // Normal speed for almost all entities.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,15 @@
|
||||||
use super::{
|
use super::{
|
||||||
gamelog, gui::renderable_colour, Equipped, InBackpack, Item, LootTable, Name, Player, Pools, Position, Renderable,
|
gamelog,
|
||||||
|
gui::renderable_colour,
|
||||||
|
Equipped,
|
||||||
|
InBackpack,
|
||||||
|
Item,
|
||||||
|
LootTable,
|
||||||
|
Name,
|
||||||
|
Player,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
Renderable,
|
||||||
RunState,
|
RunState,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
|
|
@ -24,7 +34,8 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
if let Some(victim_name) = victim_name {
|
if let Some(victim_name) = victim_name {
|
||||||
let item = items.get(entity);
|
let item = items.get(entity);
|
||||||
if let Some(_item) = item {
|
if let Some(_item) = item {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity))
|
.colour(renderable_colour(&renderables, entity))
|
||||||
.append(&victim_name.name)
|
.append(&victim_name.name)
|
||||||
|
|
@ -32,7 +43,8 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
.append("is destroyed!")
|
.append("is destroyed!")
|
||||||
.log();
|
.log();
|
||||||
} else {
|
} else {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity))
|
.colour(renderable_colour(&renderables, entity))
|
||||||
.append(&victim_name.name)
|
.append(&victim_name.name)
|
||||||
|
|
@ -41,7 +53,7 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dead.push(entity)
|
dead.push(entity);
|
||||||
}
|
}
|
||||||
// The player died, go to GameOver.
|
// The player died, go to GameOver.
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
|
|
@ -60,7 +72,7 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
&loot.0,
|
&loot.0,
|
||||||
None,
|
None,
|
||||||
crate::raws::SpawnType::AtPosition { x: loot.1.x, y: loot.1.y },
|
crate::raws::SpawnType::AtPosition { x: loot.1.x, y: loot.1.y },
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for item in items_to_delete {
|
for item in items_to_delete {
|
||||||
|
|
@ -104,8 +116,11 @@ fn handle_dead_entity_items(ecs: &mut World, dead: &Vec<Entity>) -> (Vec<Entity>
|
||||||
if let Some(table) = loot_tables.get(*victim) {
|
if let Some(table) = loot_tables.get(*victim) {
|
||||||
let roll: f32 = rng.rand();
|
let roll: f32 = rng.rand();
|
||||||
if roll < table.chance {
|
if roll < table.chance {
|
||||||
let potential_drop =
|
let potential_drop = crate::raws::roll_on_loot_table(
|
||||||
crate::raws::roll_on_loot_table(&crate::raws::RAWS.lock().unwrap(), &mut rng, &table.table);
|
&crate::raws::RAWS.lock().unwrap(),
|
||||||
|
&mut rng,
|
||||||
|
&table.table
|
||||||
|
);
|
||||||
if let Some(id) = potential_drop {
|
if let Some(id) = potential_drop {
|
||||||
if let Some(pos) = pos {
|
if let Some(pos) = pos {
|
||||||
to_spawn.push((id, pos.clone()));
|
to_spawn.push((id, pos.clone()));
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
use super::{add_effect, targeting, EffectSpawner, EffectType, Entity, Targets, World};
|
use super::{ add_effect, targeting, EffectSpawner, EffectType, Entity, Targets, World };
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog,
|
gamelog,
|
||||||
gamesystem::{hp_per_level, mana_per_level},
|
gamesystem::{ hp_per_level, mana_per_level },
|
||||||
Attributes, Confusion, Destructible, GrantsXP, Map, Player, Pools, DEFAULT_PARTICLE_LIFETIME,
|
Attributes,
|
||||||
|
Confusion,
|
||||||
|
Destructible,
|
||||||
|
GrantsXP,
|
||||||
|
Map,
|
||||||
|
Player,
|
||||||
|
Pools,
|
||||||
|
DEFAULT_PARTICLE_LIFETIME,
|
||||||
LONG_PARTICLE_LIFETIME,
|
LONG_PARTICLE_LIFETIME,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
|
|
@ -24,7 +31,7 @@ pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) {
|
||||||
lifespan: DEFAULT_PARTICLE_LIFETIME,
|
lifespan: DEFAULT_PARTICLE_LIFETIME,
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
},
|
},
|
||||||
Targets::Entity { target },
|
Targets::Entity { target }
|
||||||
);
|
);
|
||||||
if target_pool.hit_points.current < 1 {
|
if target_pool.hit_points.current < 1 {
|
||||||
super::DEAD_ENTITIES.lock().unwrap().push_back(target);
|
super::DEAD_ENTITIES.lock().unwrap().push_back(target);
|
||||||
|
|
@ -57,7 +64,7 @@ pub fn heal_damage(ecs: &mut World, heal: &EffectSpawner, target: Entity) {
|
||||||
lifespan: DEFAULT_PARTICLE_LIFETIME,
|
lifespan: DEFAULT_PARTICLE_LIFETIME,
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
},
|
},
|
||||||
Targets::Entity { target },
|
Targets::Entity { target }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +105,7 @@ pub fn bloodstain(ecs: &mut World, target: usize) {
|
||||||
// - If we're in bounds and the tile is unbloodied, bloody it and return.
|
// - If we're in bounds and the tile is unbloodied, bloody it and return.
|
||||||
// - If we ever leave bounds, return.
|
// - If we ever leave bounds, return.
|
||||||
// - Roll a dice on each failed attempt, with an increasing change to return (soft-capping max spread)
|
// - Roll a dice on each failed attempt, with an increasing change to return (soft-capping max spread)
|
||||||
if spread > 0 && spread < (map.height * map.width) {
|
if spread > 0 && spread < map.height * map.width {
|
||||||
if !map.bloodstains.contains(&(spread as usize)) {
|
if !map.bloodstains.contains(&(spread as usize)) {
|
||||||
map.bloodstains.insert(spread as usize);
|
map.bloodstains.insert(spread as usize);
|
||||||
return;
|
return;
|
||||||
|
|
@ -117,9 +124,9 @@ fn get_next_level_requirement(level: i32) -> i32 {
|
||||||
if level == 0 {
|
if level == 0 {
|
||||||
return 5;
|
return 5;
|
||||||
} else if level < 10 {
|
} else if level < 10 {
|
||||||
return 20 * 2_i32.pow(level as u32 - 1);
|
return 20 * (2_i32).pow((level as u32) - 1);
|
||||||
} else if level < 20 {
|
} else if level < 20 {
|
||||||
return 10000 * 2_i32.pow(level as u32 - 10);
|
return 10000 * (2_i32).pow((level as u32) - 10);
|
||||||
} else if level < 30 {
|
} else if level < 30 {
|
||||||
return 10000000 * (level - 19);
|
return 10000000 * (level - 19);
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +162,8 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
// If it was the PLAYER that levelled up:
|
// If it was the PLAYER that levelled up:
|
||||||
if ecs.read_storage::<Player>().get(source).is_some() {
|
if ecs.read_storage::<Player>().get(source).is_some() {
|
||||||
gamelog::record_event("player_level", 1);
|
gamelog::record_event("player_level", 1);
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("Welcome to experience level")
|
.append("Welcome to experience level")
|
||||||
.append(source_pools.level)
|
.append(source_pools.level)
|
||||||
.append(".")
|
.append(".")
|
||||||
|
|
@ -171,9 +179,9 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
fg: RGB::named(GOLD),
|
fg: RGB::named(GOLD),
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: LONG_PARTICLE_LIFETIME,
|
lifespan: LONG_PARTICLE_LIFETIME,
|
||||||
delay: i as f32 * 100.0,
|
delay: (i as f32) * 100.0,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(player_pos.x, player_pos.y - i) },
|
Targets::Tile { target: map.xy_idx(player_pos.x, player_pos.y - i) }
|
||||||
);
|
);
|
||||||
if i > 2 {
|
if i > 2 {
|
||||||
add_effect(
|
add_effect(
|
||||||
|
|
@ -183,9 +191,9 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
fg: RGB::named(GOLD),
|
fg: RGB::named(GOLD),
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: LONG_PARTICLE_LIFETIME,
|
lifespan: LONG_PARTICLE_LIFETIME,
|
||||||
delay: i as f32 * 100.0,
|
delay: (i as f32) * 100.0,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(player_pos.x + (i - 2), player_pos.y - i) },
|
Targets::Tile { target: map.xy_idx(player_pos.x + (i - 2), player_pos.y - i) }
|
||||||
);
|
);
|
||||||
add_effect(
|
add_effect(
|
||||||
None,
|
None,
|
||||||
|
|
@ -194,9 +202,9 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
fg: RGB::named(GOLD),
|
fg: RGB::named(GOLD),
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: LONG_PARTICLE_LIFETIME,
|
lifespan: LONG_PARTICLE_LIFETIME,
|
||||||
delay: i as f32 * 100.0,
|
delay: (i as f32) * 100.0,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(player_pos.x - (i - 2), player_pos.y - i) },
|
Targets::Tile { target: map.xy_idx(player_pos.x - (i - 2), player_pos.y - i) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -208,11 +216,11 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||||||
let hp_gained = hp_per_level(
|
let hp_gained = hp_per_level(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
source_attributes.constitution.base + source_attributes.constitution.modifiers,
|
source_attributes.constitution.base + source_attributes.constitution.modifiers
|
||||||
);
|
);
|
||||||
let mana_gained = mana_per_level(
|
let mana_gained = mana_per_level(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
source_attributes.intelligence.base + source_attributes.intelligence.modifiers,
|
source_attributes.intelligence.base + source_attributes.intelligence.modifiers
|
||||||
);
|
);
|
||||||
source_pools.hit_points.max += hp_gained;
|
source_pools.hit_points.max += hp_gained;
|
||||||
source_pools.hit_points.current += hp_gained;
|
source_pools.hit_points.current += hp_gained;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{EffectSpawner, EffectType};
|
use super::{ EffectSpawner, EffectType };
|
||||||
use crate::HungerClock;
|
use crate::HungerClock;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,24 +23,51 @@ lazy_static! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EffectType {
|
pub enum EffectType {
|
||||||
Damage { amount: i32 },
|
Damage {
|
||||||
Healing { amount: i32, increment_max: bool },
|
amount: i32,
|
||||||
Confusion { turns: i32 },
|
},
|
||||||
|
Healing {
|
||||||
|
amount: i32,
|
||||||
|
increment_max: bool,
|
||||||
|
},
|
||||||
|
Confusion {
|
||||||
|
turns: i32,
|
||||||
|
},
|
||||||
Bloodstain,
|
Bloodstain,
|
||||||
Particle { glyph: FontCharType, fg: RGB, bg: RGB, lifespan: f32, delay: f32 },
|
Particle {
|
||||||
|
glyph: FontCharType,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
lifespan: f32,
|
||||||
|
delay: f32,
|
||||||
|
},
|
||||||
EntityDeath,
|
EntityDeath,
|
||||||
ItemUse { item: Entity },
|
ItemUse {
|
||||||
ModifyNutrition { amount: i32 },
|
item: Entity,
|
||||||
TriggerFire { trigger: Entity },
|
},
|
||||||
|
ModifyNutrition {
|
||||||
|
amount: i32,
|
||||||
|
},
|
||||||
|
TriggerFire {
|
||||||
|
trigger: Entity,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Targets {
|
pub enum Targets {
|
||||||
Entity { target: Entity },
|
Entity {
|
||||||
EntityList { targets: Vec<Entity> },
|
target: Entity,
|
||||||
Tile { target: usize },
|
},
|
||||||
TileList { targets: Vec<usize> },
|
EntityList {
|
||||||
|
targets: Vec<Entity>,
|
||||||
|
},
|
||||||
|
Tile {
|
||||||
|
target: usize,
|
||||||
|
},
|
||||||
|
TileList {
|
||||||
|
targets: Vec<usize>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EffectSpawner {
|
pub struct EffectSpawner {
|
||||||
|
|
@ -61,7 +88,9 @@ pub fn run_effects_queue(ecs: &mut World) {
|
||||||
loop {
|
loop {
|
||||||
let dead_entity: Option<Entity> = DEAD_ENTITIES.lock().unwrap().pop_front();
|
let dead_entity: Option<Entity> = DEAD_ENTITIES.lock().unwrap().pop_front();
|
||||||
if let Some(dead_entity) = dead_entity {
|
if let Some(dead_entity) = dead_entity {
|
||||||
EFFECT_QUEUE.lock().unwrap().retain(|x| x.source != Some(dead_entity));
|
EFFECT_QUEUE.lock()
|
||||||
|
.unwrap()
|
||||||
|
.retain(|x| x.source != Some(dead_entity));
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +176,5 @@ fn affect_entity(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_noncursed(buc: &BUC) -> bool {
|
pub fn get_noncursed(buc: &BUC) -> bool {
|
||||||
if buc == &BUC::Cursed {
|
if buc == &BUC::Cursed { false } else { true }
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{add_effect, targeting, EffectSpawner, EffectType, Targets};
|
use super::{ add_effect, targeting, EffectSpawner, EffectType, Targets };
|
||||||
use crate::{Map, ParticleBuilder, SpawnParticleBurst, SpawnParticleLine, SpawnParticleSimple};
|
use crate::{ Map, ParticleBuilder, SpawnParticleBurst, SpawnParticleLine, SpawnParticleSimple };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub fn handle_simple_particles(ecs: &World, entity: Entity, target: &Targets) {
|
||||||
lifespan: part.lifetime_ms,
|
lifespan: part.lifetime_ms,
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
},
|
},
|
||||||
target.clone(),
|
target.clone()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -39,33 +39,33 @@ pub fn handle_burst_particles(ecs: &World, entity: Entity, target: &Targets) {
|
||||||
ecs,
|
ecs,
|
||||||
start_pos,
|
start_pos,
|
||||||
end_pos,
|
end_pos,
|
||||||
&SpawnParticleLine {
|
&(SpawnParticleLine {
|
||||||
glyph: part.head_glyph,
|
glyph: part.head_glyph,
|
||||||
tail_glyph: part.tail_glyph,
|
tail_glyph: part.tail_glyph,
|
||||||
colour: part.colour,
|
colour: part.colour,
|
||||||
trail_colour: part.trail_colour,
|
trail_colour: part.trail_colour,
|
||||||
lifetime_ms: part.trail_lifetime_ms, // 75.0 is good here.
|
lifetime_ms: part.trail_lifetime_ms, // 75.0 is good here.
|
||||||
trail_lifetime_ms: part.trail_lifetime_ms,
|
trail_lifetime_ms: part.trail_lifetime_ms,
|
||||||
},
|
})
|
||||||
);
|
);
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let line = line2d(
|
let line = line2d(
|
||||||
LineAlg::Bresenham,
|
LineAlg::Bresenham,
|
||||||
Point::new(start_pos % map.width, start_pos / map.width),
|
Point::new(start_pos % map.width, start_pos / map.width),
|
||||||
Point::new(end_pos % map.width, end_pos / map.width),
|
Point::new(end_pos % map.width, end_pos / map.width)
|
||||||
);
|
);
|
||||||
let burst_delay = line.len() as f32 * part.trail_lifetime_ms;
|
let burst_delay = (line.len() as f32) * part.trail_lifetime_ms;
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
add_effect(
|
add_effect(
|
||||||
None,
|
None,
|
||||||
EffectType::Particle {
|
EffectType::Particle {
|
||||||
glyph: part.glyph,
|
glyph: part.glyph,
|
||||||
fg: part.colour.lerp(part.lerp, i as f32 * 0.1),
|
fg: part.colour.lerp(part.lerp, (i as f32) * 0.1),
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: part.lifetime_ms / 10.0, // ~50-80 is good here.
|
lifespan: part.lifetime_ms / 10.0, // ~50-80 is good here.
|
||||||
delay: burst_delay + (i as f32 * part.lifetime_ms / 10.0), // above + burst_delay
|
delay: burst_delay + ((i as f32) * part.lifetime_ms) / 10.0, // above + burst_delay
|
||||||
},
|
},
|
||||||
target.clone(),
|
target.clone()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,27 +74,31 @@ pub fn handle_burst_particles(ecs: &World, entity: Entity, target: &Targets) {
|
||||||
|
|
||||||
fn get_centre(ecs: &World, target: &Targets) -> i32 {
|
fn get_centre(ecs: &World, target: &Targets) -> i32 {
|
||||||
match target {
|
match target {
|
||||||
Targets::Tile { target } => return *target as i32,
|
Targets::Tile { target } => {
|
||||||
|
return *target as i32;
|
||||||
|
}
|
||||||
Targets::TileList { targets } => {
|
Targets::TileList { targets } => {
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let (mut count, mut sum_x, mut sum_y) = (0, 0, 0);
|
let (mut count, mut sum_x, mut sum_y) = (0, 0, 0);
|
||||||
for target in targets {
|
for target in targets {
|
||||||
sum_x += *target as i32 % map.width;
|
sum_x += (*target as i32) % map.width;
|
||||||
sum_y += *target as i32 / map.width;
|
sum_y += (*target as i32) / map.width;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
let (mean_x, mean_y) = (sum_x / count, sum_y / count);
|
let (mean_x, mean_y) = (sum_x / count, sum_y / count);
|
||||||
let centre = map.xy_idx(mean_x, mean_y);
|
let centre = map.xy_idx(mean_x, mean_y);
|
||||||
return centre as i32;
|
return centre as i32;
|
||||||
}
|
}
|
||||||
Targets::Entity { target } => return targeting::entity_position(ecs, *target).unwrap() as i32,
|
Targets::Entity { target } => {
|
||||||
|
return targeting::entity_position(ecs, *target).unwrap() as i32;
|
||||||
|
}
|
||||||
Targets::EntityList { targets } => {
|
Targets::EntityList { targets } => {
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let (mut count, mut sum_x, mut sum_y) = (0, 0, 0);
|
let (mut count, mut sum_x, mut sum_y) = (0, 0, 0);
|
||||||
for target in targets {
|
for target in targets {
|
||||||
if let Some(pos) = targeting::entity_position(ecs, *target) {
|
if let Some(pos) = targeting::entity_position(ecs, *target) {
|
||||||
sum_x += pos as i32 % map.width;
|
sum_x += (pos as i32) % map.width;
|
||||||
sum_y += pos as i32 / map.width;
|
sum_y += (pos as i32) / map.width;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,11 +122,12 @@ pub fn handle_line_particles(ecs: &World, entity: Entity, target: &Targets) {
|
||||||
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Targets::EntityList { targets } => targets.iter().for_each(|target| {
|
Targets::EntityList { targets } =>
|
||||||
if let Some(end_pos) = targeting::entity_position(ecs, *target) {
|
targets.iter().for_each(|target| {
|
||||||
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
if let Some(end_pos) = targeting::entity_position(ecs, *target) {
|
||||||
}
|
spawn_line_particles(ecs, start_pos, end_pos as i32, part);
|
||||||
}),
|
}
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,9 +146,9 @@ fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleL
|
||||||
fg: part.colour,
|
fg: part.colour,
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: part.lifetime_ms,
|
lifespan: part.lifetime_ms,
|
||||||
delay: i as f32 * part.lifetime_ms,
|
delay: (i as f32) * part.lifetime_ms,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(pt.x, pt.y) },
|
Targets::Tile { target: map.xy_idx(pt.x, pt.y) }
|
||||||
);
|
);
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
add_effect(
|
add_effect(
|
||||||
|
|
@ -153,9 +158,9 @@ fn spawn_line_particles(ecs: &World, start: i32, end: i32, part: &SpawnParticleL
|
||||||
fg: part.trail_colour,
|
fg: part.trail_colour,
|
||||||
bg: RGB::named(BLACK),
|
bg: RGB::named(BLACK),
|
||||||
lifespan: part.trail_lifetime_ms,
|
lifespan: part.trail_lifetime_ms,
|
||||||
delay: i as f32 * part.lifetime_ms,
|
delay: (i as f32) * part.lifetime_ms,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(line[i - 1].x, line[i - 1].y) },
|
Targets::Tile { target: map.xy_idx(line[i - 1].x, line[i - 1].y) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Equipped, InBackpack, Map, Position};
|
use crate::{ Equipped, InBackpack, Map, Position };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,34 @@
|
||||||
use super::{add_effect, get_noncursed, messages::*, particles, spatial, EffectType, Entity, Targets, World};
|
use super::{ add_effect, get_noncursed, messages::*, particles, spatial, EffectType, Entity, Targets, World };
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, gui::item_colour_ecs, gui::obfuscate_name_ecs, gui::renderable_colour, Beatitude, Charges, Confusion,
|
gamelog,
|
||||||
Consumable, Destructible, Equipped, Hidden, InBackpack, InflictsDamage, Item, MagicMapper, MasterDungeonMap, Name,
|
gui::item_colour_ecs,
|
||||||
ObfuscatedName, Player, Prop, ProvidesHealing, ProvidesIdentify, ProvidesNutrition, ProvidesRemoveCurse,
|
gui::obfuscate_name_ecs,
|
||||||
RandomNumberGenerator, Renderable, RunState, SingleActivation, BUC,
|
gui::renderable_colour,
|
||||||
|
Beatitude,
|
||||||
|
Charges,
|
||||||
|
Confusion,
|
||||||
|
Consumable,
|
||||||
|
Destructible,
|
||||||
|
Equipped,
|
||||||
|
Hidden,
|
||||||
|
InBackpack,
|
||||||
|
InflictsDamage,
|
||||||
|
Item,
|
||||||
|
MagicMapper,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Player,
|
||||||
|
Prop,
|
||||||
|
ProvidesHealing,
|
||||||
|
ProvidesIdentify,
|
||||||
|
ProvidesNutrition,
|
||||||
|
ProvidesRemoveCurse,
|
||||||
|
RandomNumberGenerator,
|
||||||
|
Renderable,
|
||||||
|
RunState,
|
||||||
|
SingleActivation,
|
||||||
|
BUC,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -85,7 +110,7 @@ fn event_trigger(source: Option<Entity>, entity: Entity, target: &Targets, ecs:
|
||||||
fn handle_restore_nutrition(
|
fn handle_restore_nutrition(
|
||||||
ecs: &mut World,
|
ecs: &mut World,
|
||||||
event: &mut EventInfo,
|
event: &mut EventInfo,
|
||||||
mut logger: gamelog::Logger,
|
mut logger: gamelog::Logger
|
||||||
) -> (gamelog::Logger, bool) {
|
) -> (gamelog::Logger, bool) {
|
||||||
if ecs.read_storage::<ProvidesNutrition>().get(event.entity).is_some() {
|
if ecs.read_storage::<ProvidesNutrition>().get(event.entity).is_some() {
|
||||||
let amount = match event.buc {
|
let amount = match event.buc {
|
||||||
|
|
@ -131,7 +156,7 @@ fn handle_healing(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::L
|
||||||
add_effect(
|
add_effect(
|
||||||
event.source,
|
event.source,
|
||||||
EffectType::Healing { amount: roll, increment_max: get_noncursed(&event.buc) },
|
EffectType::Healing { amount: roll, increment_max: get_noncursed(&event.buc) },
|
||||||
event.target.clone(),
|
event.target.clone()
|
||||||
);
|
);
|
||||||
for target in get_entity_targets(&event.target) {
|
for target in get_entity_targets(&event.target) {
|
||||||
if ecs.read_storage::<Prop>().get(target).is_some() || ecs.read_storage::<Item>().get(target).is_some() {
|
if ecs.read_storage::<Prop>().get(target).is_some() || ecs.read_storage::<Item>().get(target).is_some() {
|
||||||
|
|
@ -238,11 +263,13 @@ fn handle_identify(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(_e, _i, bp, _o, name)| {
|
.filter(|(_e, _i, bp, _o, name)| {
|
||||||
bp.owner == event.source.unwrap()
|
bp.owner == event.source.unwrap() &&
|
||||||
&& (!dm.identified_items.contains(&name.name.clone())
|
(!dm.identified_items.contains(&name.name.clone()) ||
|
||||||
|| !beatitudes.get(event.source.unwrap()).map(|beatitude| beatitude.known).unwrap_or(true))
|
!beatitudes
|
||||||
})
|
.get(event.source.unwrap())
|
||||||
{
|
.map(|beatitude| beatitude.known)
|
||||||
|
.unwrap_or(true))
|
||||||
|
}) {
|
||||||
to_identify.push((e, name.name.clone()));
|
to_identify.push((e, name.name.clone()));
|
||||||
}
|
}
|
||||||
for item in to_identify {
|
for item in to_identify {
|
||||||
|
|
@ -276,8 +303,7 @@ fn handle_remove_curse(ecs: &mut World, event: &mut EventInfo, mut logger: gamel
|
||||||
&ecs.read_storage::<Beatitude>(),
|
&ecs.read_storage::<Beatitude>(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(_e, _i, bp, b)| bp.owner == event.source.unwrap() && b.buc == BUC::Cursed)
|
.filter(|(_e, _i, bp, b)| bp.owner == event.source.unwrap() && b.buc == BUC::Cursed) {
|
||||||
{
|
|
||||||
to_decurse.push(entity);
|
to_decurse.push(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -291,14 +317,15 @@ fn handle_remove_curse(ecs: &mut World, event: &mut EventInfo, mut logger: gamel
|
||||||
&ecs.read_storage::<Beatitude>(),
|
&ecs.read_storage::<Beatitude>(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(_e, _i, e, b)| e.owner == event.source.unwrap() && b.buc == BUC::Cursed)
|
.filter(|(_e, _i, e, b)| e.owner == event.source.unwrap() && b.buc == BUC::Cursed) {
|
||||||
{
|
|
||||||
to_decurse.push(entity);
|
to_decurse.push(entity);
|
||||||
}
|
}
|
||||||
if to_decurse.len() == 0 {
|
if to_decurse.len() == 0 {
|
||||||
match event.buc {
|
match event.buc {
|
||||||
BUC::Uncursed => select_single(ecs, RunState::ShowRemoveCurse),
|
BUC::Uncursed => select_single(ecs, RunState::ShowRemoveCurse),
|
||||||
BUC::Blessed => logger = logger.append(REMOVECURSE_BLESSED_FAILED),
|
BUC::Blessed => {
|
||||||
|
logger = logger.append(REMOVECURSE_BLESSED_FAILED);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
return (logger, true);
|
return (logger, true);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{append_entry, LogFragment};
|
use super::{ append_entry, LogFragment };
|
||||||
use crate::BUC;
|
use crate::BUC;
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{events, LogFragment, Logger};
|
use super::{ events, LogFragment, Logger };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
|
@ -23,50 +23,55 @@ pub fn print_log(console: &mut Box<dyn Console>, pos: Point, _descending: bool,
|
||||||
let mut y = pos.y;
|
let mut y = pos.y;
|
||||||
let mut x = pos.x;
|
let mut x = pos.x;
|
||||||
// Reverse the log, take the number we want to show, and iterate through them
|
// Reverse the log, take the number we want to show, and iterate through them
|
||||||
LOG.lock().unwrap().iter().rev().take(len).for_each(|log| {
|
LOG.lock()
|
||||||
let mut entry_len = -2;
|
.unwrap()
|
||||||
// Iterate through each message fragment, and get the total length
|
.iter()
|
||||||
// in lines, by adding the length of every fragment and dividing it
|
.rev()
|
||||||
// by the maximum length we desire. Then shuffle our start-y by that much.
|
.take(len)
|
||||||
log.iter().for_each(|frag| {
|
.for_each(|log| {
|
||||||
entry_len += frag.text.len() as i32;
|
let mut entry_len = -2;
|
||||||
});
|
// Iterate through each message fragment, and get the total length
|
||||||
let lines = entry_len / maximum_len;
|
// in lines, by adding the length of every fragment and dividing it
|
||||||
y -= lines;
|
// by the maximum length we desire. Then shuffle our start-y by that much.
|
||||||
let mut i = 0;
|
log.iter().for_each(|frag| {
|
||||||
log.iter().for_each(|frag| {
|
entry_len += frag.text.len() as i32;
|
||||||
// Split every fragment up into single characters.
|
});
|
||||||
let parts = frag.text.split("");
|
let lines = entry_len / maximum_len;
|
||||||
for part in parts {
|
y -= lines;
|
||||||
// This is an extremely hacky solution to a problem I don't understand yet.
|
let mut i = 0;
|
||||||
// -- without this, the lines *here* and the line count *above* wont match.
|
log.iter().for_each(|frag| {
|
||||||
if part == "" || part == "\\" {
|
// Split every fragment up into single characters.
|
||||||
continue;
|
let parts = frag.text.split("");
|
||||||
}
|
for part in parts {
|
||||||
if i > entry_len {
|
// This is an extremely hacky solution to a problem I don't understand yet.
|
||||||
break;
|
// -- without this, the lines *here* and the line count *above* wont match.
|
||||||
}
|
if part == "" || part == "\\" {
|
||||||
i += 1;
|
continue;
|
||||||
if x + part.len() as i32 > pos.x + maximum_len {
|
|
||||||
if y > pos.y - len as i32 {
|
|
||||||
console.print(x, y, "-");
|
|
||||||
}
|
}
|
||||||
y += 1;
|
if i > entry_len {
|
||||||
x = pos.x;
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
if x + (part.len() as i32) > pos.x + maximum_len {
|
||||||
|
if y > pos.y - (len as i32) {
|
||||||
|
console.print(x, y, "-");
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
x = pos.x;
|
||||||
|
}
|
||||||
|
// Stay within bounds
|
||||||
|
if y > pos.y - (len as i32) {
|
||||||
|
console.print_color(x, y, frag.colour.into(), RGB::named(rltk::BLACK).into(), part);
|
||||||
|
}
|
||||||
|
x += part.len() as i32;
|
||||||
}
|
}
|
||||||
// Stay within bounds
|
});
|
||||||
if y > pos.y - len as i32 {
|
// Take away one from the y-axis, because we want to start each entry
|
||||||
console.print_color(x, y, frag.colour.into(), RGB::named(rltk::BLACK).into(), part);
|
// on a new line, and go up an additional amount depending on how many
|
||||||
}
|
// lines our *previous* entry took.
|
||||||
x += part.len() as i32;
|
y -= 1 + lines;
|
||||||
}
|
x = pos.x;
|
||||||
});
|
});
|
||||||
// Take away one from the y-axis, because we want to start each entry
|
|
||||||
// on a new line, and go up an additional amount depending on how many
|
|
||||||
// lines our *previous* entry took.
|
|
||||||
y -= 1 + lines;
|
|
||||||
x = pos.x;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_log() {
|
pub fn setup_log() {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ mod builder;
|
||||||
pub use builder::*;
|
pub use builder::*;
|
||||||
mod logstore;
|
mod logstore;
|
||||||
use logstore::*;
|
use logstore::*;
|
||||||
pub use logstore::{clear_log, clone_log, print_log, restore_log, setup_log};
|
pub use logstore::{ clear_log, clone_log, print_log, restore_log, setup_log };
|
||||||
mod events;
|
mod events;
|
||||||
pub use events::*;
|
pub use events::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct LogFragment {
|
pub struct LogFragment {
|
||||||
pub colour: RGB,
|
pub colour: RGB,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{Skill, Skills};
|
use super::{ Skill, Skills };
|
||||||
use crate::gui::{Ancestry, Class};
|
use crate::gui::{ Ancestry, Class };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
||||||
|
|
@ -80,7 +80,7 @@ pub fn roll_4d6(rng: &mut rltk::RandomNumberGenerator) -> i32 {
|
||||||
pub fn get_attribute_rolls(
|
pub fn get_attribute_rolls(
|
||||||
rng: &mut RandomNumberGenerator,
|
rng: &mut RandomNumberGenerator,
|
||||||
class: Class,
|
class: Class,
|
||||||
ancestry: Ancestry,
|
ancestry: Ancestry
|
||||||
) -> (i32, i32, i32, i32, i32, i32) {
|
) -> (i32, i32, i32, i32, i32, i32) {
|
||||||
let (mut str, mut dex, mut con, mut int, mut wis, mut cha) = match class {
|
let (mut str, mut dex, mut con, mut int, mut wis, mut cha) = match class {
|
||||||
Class::Fighter => (10, 8, 10, 6, 6, 8),
|
Class::Fighter => (10, 8, 10, 6, 6, 8),
|
||||||
|
|
@ -96,14 +96,15 @@ pub fn get_attribute_rolls(
|
||||||
Class::Villager => [15, 15, 25, 15, 15, 15],
|
Class::Villager => [15, 15, 25, 15, 15, 15],
|
||||||
};
|
};
|
||||||
let ancestry_maximums: [i32; 6] = match ancestry {
|
let ancestry_maximums: [i32; 6] = match ancestry {
|
||||||
Ancestry::Human => [19, 19, 19, 19, 19, 19], // 114
|
Ancestry::Human => [19, 19, 19, 19, 19, 19], // 114
|
||||||
Ancestry::Elf => [15, 18, 15, 20, 20, 18], // 106
|
Ancestry::Elf => [15, 18, 15, 20, 20, 18], // 106
|
||||||
Ancestry::Dwarf => [19, 17, 20, 16, 16, 16], // 106
|
Ancestry::Dwarf => [19, 17, 20, 16, 16, 16], // 106
|
||||||
Ancestry::Gnome => [16, 18, 16, 20, 18, 18], // 106
|
Ancestry::Gnome => [16, 18, 16, 20, 18, 18], // 106
|
||||||
Ancestry::Catfolk => [16, 20, 16, 16, 18, 20], // 106
|
Ancestry::Catfolk => [16, 20, 16, 16, 18, 20], // 106
|
||||||
_ => [18, 18, 18, 18, 18, 18],
|
_ => [18, 18, 18, 18, 18, 18],
|
||||||
};
|
};
|
||||||
let improve_table = crate::random_table::RandomTable::new()
|
let improve_table = crate::random_table::RandomTable
|
||||||
|
::new()
|
||||||
.add("Strength", improve_chance[0])
|
.add("Strength", improve_chance[0])
|
||||||
.add("Dexterity", improve_chance[1])
|
.add("Dexterity", improve_chance[1])
|
||||||
.add("Constitution", improve_chance[2])
|
.add("Constitution", improve_chance[2])
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
use super::{gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State};
|
use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State };
|
||||||
use crate::config::entity::NORMAL_SPEED;
|
use crate::config::entity::NORMAL_SPEED;
|
||||||
use crate::{
|
use crate::{
|
||||||
raws, Attribute, Energy, HasAncestry, HasClass, KnownSpell, KnownSpells, Pool, Skill, Skills, Telepath, BUC,
|
raws,
|
||||||
|
Attribute,
|
||||||
|
Energy,
|
||||||
|
HasAncestry,
|
||||||
|
HasClass,
|
||||||
|
KnownSpell,
|
||||||
|
KnownSpells,
|
||||||
|
Pool,
|
||||||
|
Skill,
|
||||||
|
Skills,
|
||||||
|
Telepath,
|
||||||
|
BUC,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -79,8 +90,14 @@ lazy_static! {
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum CharCreateResult {
|
pub enum CharCreateResult {
|
||||||
NoSelection { ancestry: Ancestry, class: Class },
|
NoSelection {
|
||||||
Selected { ancestry: Ancestry, class: Class },
|
ancestry: Ancestry,
|
||||||
|
class: Class,
|
||||||
|
},
|
||||||
|
Selected {
|
||||||
|
ancestry: Ancestry,
|
||||||
|
class: Class,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the player character creation screen.
|
/// Handles the player character creation screen.
|
||||||
|
|
@ -177,20 +194,45 @@ pub fn character_creation(gs: &mut State, ctx: &mut Rltk) -> CharCreateResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => return CharCreateResult::NoSelection { ancestry, class },
|
None => {
|
||||||
Some(key) => match key {
|
return CharCreateResult::NoSelection { ancestry, class };
|
||||||
VirtualKeyCode::Escape => return CharCreateResult::Selected { ancestry: Ancestry::NULL, class },
|
}
|
||||||
VirtualKeyCode::Return => return CharCreateResult::Selected { ancestry, class },
|
Some(key) =>
|
||||||
VirtualKeyCode::H => return CharCreateResult::NoSelection { ancestry: Ancestry::Human, class },
|
match key {
|
||||||
VirtualKeyCode::E => return CharCreateResult::NoSelection { ancestry: Ancestry::Elf, class },
|
VirtualKeyCode::Escape => {
|
||||||
VirtualKeyCode::D => return CharCreateResult::NoSelection { ancestry: Ancestry::Dwarf, class },
|
return CharCreateResult::Selected { ancestry: Ancestry::NULL, class };
|
||||||
VirtualKeyCode::C => return CharCreateResult::NoSelection { ancestry: Ancestry::Catfolk, class },
|
}
|
||||||
VirtualKeyCode::F => return CharCreateResult::NoSelection { ancestry, class: Class::Fighter },
|
VirtualKeyCode::Return => {
|
||||||
VirtualKeyCode::R => return CharCreateResult::NoSelection { ancestry, class: Class::Rogue },
|
return CharCreateResult::Selected { ancestry, class };
|
||||||
VirtualKeyCode::W => return CharCreateResult::NoSelection { ancestry, class: Class::Wizard },
|
}
|
||||||
VirtualKeyCode::V => return CharCreateResult::NoSelection { ancestry, class: Class::Villager },
|
VirtualKeyCode::H => {
|
||||||
_ => return CharCreateResult::NoSelection { ancestry, class },
|
return CharCreateResult::NoSelection { ancestry: Ancestry::Human, class };
|
||||||
},
|
}
|
||||||
|
VirtualKeyCode::E => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry: Ancestry::Elf, class };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::D => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry: Ancestry::Dwarf, class };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::C => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry: Ancestry::Catfolk, class };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::F => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry, class: Class::Fighter };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::R => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry, class: Class::Rogue };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::W => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry, class: Class::Wizard };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::V => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry, class: Class::Villager };
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return CharCreateResult::NoSelection { ancestry, class };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CharCreateResult::NoSelection { ancestry: Ancestry::Human, class: Class::Fighter };
|
return CharCreateResult::NoSelection { ancestry: Ancestry::Human, class: Class::Fighter };
|
||||||
|
|
@ -214,29 +256,23 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
||||||
Ancestry::Human => {}
|
Ancestry::Human => {}
|
||||||
Ancestry::Dwarf => {
|
Ancestry::Dwarf => {
|
||||||
renderables
|
renderables
|
||||||
.insert(
|
.insert(*player, Renderable {
|
||||||
*player,
|
glyph: rltk::to_cp437('h'),
|
||||||
Renderable {
|
fg: RGB::named(rltk::RED),
|
||||||
glyph: rltk::to_cp437('h'),
|
bg: RGB::named(rltk::BLACK),
|
||||||
fg: RGB::named(rltk::RED),
|
render_order: 0,
|
||||||
bg: RGB::named(rltk::BLACK),
|
})
|
||||||
render_order: 0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("Unable to insert renderable component");
|
.expect("Unable to insert renderable component");
|
||||||
*player_skills.skills.entry(Skill::Defence).or_insert(0) += 1;
|
*player_skills.skills.entry(Skill::Defence).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
Ancestry::Elf => {
|
Ancestry::Elf => {
|
||||||
renderables
|
renderables
|
||||||
.insert(
|
.insert(*player, Renderable {
|
||||||
*player,
|
glyph: rltk::to_cp437('@'),
|
||||||
Renderable {
|
fg: RGB::named(rltk::GREEN),
|
||||||
glyph: rltk::to_cp437('@'),
|
bg: RGB::named(rltk::BLACK),
|
||||||
fg: RGB::named(rltk::GREEN),
|
render_order: 0,
|
||||||
bg: RGB::named(rltk::BLACK),
|
})
|
||||||
render_order: 0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("Unable to insert renderable component");
|
.expect("Unable to insert renderable component");
|
||||||
let mut telepaths = ecs.write_storage::<Telepath>();
|
let mut telepaths = ecs.write_storage::<Telepath>();
|
||||||
telepaths
|
telepaths
|
||||||
|
|
@ -267,43 +303,36 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
|
||||||
if class == Class::Wizard {
|
if class == Class::Wizard {
|
||||||
let mut spells = ecs.write_storage::<KnownSpells>();
|
let mut spells = ecs.write_storage::<KnownSpells>();
|
||||||
spells
|
spells
|
||||||
.insert(
|
.insert(player, KnownSpells {
|
||||||
player,
|
spells: vec![KnownSpell { display_name: "zap".to_string(), mana_cost: 1 }],
|
||||||
KnownSpells { spells: vec![KnownSpell { display_name: "zap".to_string(), mana_cost: 1 }] },
|
})
|
||||||
)
|
|
||||||
.expect("Unable to insert known spells component");
|
.expect("Unable to insert known spells component");
|
||||||
}
|
}
|
||||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||||||
let mut attributes = ecs.write_storage::<Attributes>();
|
let mut attributes = ecs.write_storage::<Attributes>();
|
||||||
let (str, dex, con, int, wis, cha) = get_attribute_rolls(&mut rng, class, ancestry);
|
let (str, dex, con, int, wis, cha) = get_attribute_rolls(&mut rng, class, ancestry);
|
||||||
attributes
|
attributes
|
||||||
.insert(
|
.insert(player, Attributes {
|
||||||
player,
|
strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) },
|
||||||
Attributes {
|
dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) },
|
||||||
strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) },
|
constitution: Attribute { base: con, modifiers: 0, bonus: attr_bonus(con) },
|
||||||
dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) },
|
intelligence: Attribute { base: int, modifiers: 0, bonus: attr_bonus(int) },
|
||||||
constitution: Attribute { base: con, modifiers: 0, bonus: attr_bonus(con) },
|
wisdom: Attribute { base: wis, modifiers: 0, bonus: attr_bonus(wis) },
|
||||||
intelligence: Attribute { base: int, modifiers: 0, bonus: attr_bonus(int) },
|
charisma: Attribute { base: cha, modifiers: 0, bonus: attr_bonus(cha) },
|
||||||
wisdom: Attribute { base: wis, modifiers: 0, bonus: attr_bonus(wis) },
|
})
|
||||||
charisma: Attribute { base: cha, modifiers: 0, bonus: attr_bonus(cha) },
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("Unable to insert attributes component");
|
.expect("Unable to insert attributes component");
|
||||||
|
|
||||||
let mut pools = ecs.write_storage::<Pools>();
|
let mut pools = ecs.write_storage::<Pools>();
|
||||||
pools
|
pools
|
||||||
.insert(
|
.insert(player, Pools {
|
||||||
player,
|
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
|
||||||
Pools {
|
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
|
||||||
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
|
xp: 0,
|
||||||
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
|
level: 1,
|
||||||
xp: 0,
|
bac: 10,
|
||||||
level: 1,
|
weight: 0.0,
|
||||||
bac: 10,
|
god: false,
|
||||||
weight: 0.0,
|
})
|
||||||
god: false,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.expect("Unable to insert pools component");
|
.expect("Unable to insert pools component");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,7 +347,7 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
|
||||||
item,
|
item,
|
||||||
buc,
|
buc,
|
||||||
raws::SpawnType::Equipped { by: player },
|
raws::SpawnType::Equipped { by: player },
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for item in starts_with.1.iter() {
|
for item in starts_with.1.iter() {
|
||||||
|
|
@ -328,7 +357,7 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
|
||||||
item,
|
item,
|
||||||
None,
|
None,
|
||||||
raws::SpawnType::Carried { by: player },
|
raws::SpawnType::Carried { by: player },
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +372,7 @@ fn get_starting_inventory(class: Class, rng: &mut RandomNumberGenerator) -> (Vec
|
||||||
equipped = vec![
|
equipped = vec![
|
||||||
"equip_shortsword".to_string(),
|
"equip_shortsword".to_string(),
|
||||||
"equip_body_ringmail".to_string(),
|
"equip_body_ringmail".to_string(),
|
||||||
"equip_mediumshield".to_string(),
|
"equip_mediumshield".to_string()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
Class::Rogue => {
|
Class::Rogue => {
|
||||||
|
|
@ -371,7 +400,7 @@ fn pick_random_table_item(
|
||||||
push_to: &mut Vec<String>,
|
push_to: &mut Vec<String>,
|
||||||
table: &'static str,
|
table: &'static str,
|
||||||
dice: &'static str,
|
dice: &'static str,
|
||||||
difficulty: Option<i32>,
|
difficulty: Option<i32>
|
||||||
) {
|
) {
|
||||||
let (n, d, m) = raws::parse_dice_string(dice);
|
let (n, d, m) = raws::parse_dice_string(dice);
|
||||||
for _i in 0..rng.roll_dice(n, d) + m {
|
for _i in 0..rng.roll_dice(n, d) + m {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult {
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::RED),
|
RGB::named(rltk::RED),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"DEBUG MENU! [aA-zZ][Esc.]",
|
"DEBUG MENU! [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
let x = 1 + x_offset;
|
let x = 1 + x_offset;
|
||||||
let mut y = 3 + y_offset;
|
let mut y = 3 + y_offset;
|
||||||
|
|
@ -50,14 +50,15 @@ pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult {
|
||||||
// Match keys
|
// Match keys
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => CheatMenuResult::NoResponse,
|
None => CheatMenuResult::NoResponse,
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::A => CheatMenuResult::Ascend,
|
match key {
|
||||||
VirtualKeyCode::D => CheatMenuResult::Descend,
|
VirtualKeyCode::A => CheatMenuResult::Ascend,
|
||||||
VirtualKeyCode::H => CheatMenuResult::Heal,
|
VirtualKeyCode::D => CheatMenuResult::Descend,
|
||||||
VirtualKeyCode::M => CheatMenuResult::MagicMap,
|
VirtualKeyCode::H => CheatMenuResult::Heal,
|
||||||
VirtualKeyCode::G => CheatMenuResult::GodMode,
|
VirtualKeyCode::M => CheatMenuResult::MagicMap,
|
||||||
VirtualKeyCode::Escape => CheatMenuResult::Cancel,
|
VirtualKeyCode::G => CheatMenuResult::GodMode,
|
||||||
_ => CheatMenuResult::NoResponse,
|
VirtualKeyCode::Escape => CheatMenuResult::Cancel,
|
||||||
},
|
_ => CheatMenuResult::NoResponse,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,24 @@
|
||||||
use super::{
|
use super::{
|
||||||
get_max_inventory_width, item_colour_ecs, obfuscate_name_ecs, print_options, renderable_colour, ItemMenuResult,
|
get_max_inventory_width,
|
||||||
|
item_colour_ecs,
|
||||||
|
obfuscate_name_ecs,
|
||||||
|
print_options,
|
||||||
|
renderable_colour,
|
||||||
|
ItemMenuResult,
|
||||||
UniqueInventoryItem,
|
UniqueInventoryItem,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, Beatitude, Entity, Equipped, InBackpack, Item, MasterDungeonMap, Name, ObfuscatedName, Renderable, State,
|
gamelog,
|
||||||
|
Beatitude,
|
||||||
|
Entity,
|
||||||
|
Equipped,
|
||||||
|
InBackpack,
|
||||||
|
Item,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Renderable,
|
||||||
|
State,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -41,8 +56,12 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// If not obfuscated, or already identified, return false.
|
// If not obfuscated, or already identified, return false.
|
||||||
if (!obfuscated.get(*item_entity).is_some() || dm.identified_items.contains(&n.name))
|
if
|
||||||
&& beatitudes.get(*item_entity).map(|beatitude| beatitude.known).unwrap_or(true)
|
(!obfuscated.get(*item_entity).is_some() || dm.identified_items.contains(&n.name)) &&
|
||||||
|
beatitudes
|
||||||
|
.get(*item_entity)
|
||||||
|
.map(|beatitude| beatitude.known)
|
||||||
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +79,8 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
|
||||||
// If only one item, return it.
|
// If only one item, return it.
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
let item = build_identify_iterator().nth(0).unwrap().0;
|
let item = build_identify_iterator().nth(0).unwrap().0;
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You identify the")
|
.append("You identify the")
|
||||||
.colour(item_colour_ecs(&gs.ecs, item))
|
.colour(item_colour_ecs(&gs.ecs, item))
|
||||||
.append_n(obfuscate_name_ecs(&gs.ecs, item).0)
|
.append_n(obfuscate_name_ecs(&gs.ecs, item).0)
|
||||||
|
|
@ -81,7 +101,9 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
|
||||||
glyph: renderable.glyph,
|
glyph: renderable.glyph,
|
||||||
name: name.name.clone(),
|
name: name.name.clone(),
|
||||||
})
|
})
|
||||||
.and_modify(|count| *count += 1)
|
.and_modify(|count| {
|
||||||
|
*count += 1;
|
||||||
|
})
|
||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
inventory_ids.entry(singular).or_insert(entity);
|
inventory_ids.entry(singular).or_insert(entity);
|
||||||
}
|
}
|
||||||
|
|
@ -95,30 +117,35 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Identify which item? [aA-zZ][Esc.]",
|
"Identify which item? [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
|
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
|
||||||
print_options(player_inventory, x + 1, y + 1, ctx);
|
print_options(player_inventory, x + 1, y + 1, ctx);
|
||||||
// Input
|
// Input
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
None => (ItemMenuResult::NoResponse, None),
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
match key {
|
||||||
_ => {
|
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||||
let selection = rltk::letter_to_option(key);
|
_ => {
|
||||||
if selection > -1 && selection < count as i32 {
|
let selection = rltk::letter_to_option(key);
|
||||||
let item = inventory_ids.iter().nth(selection as usize).unwrap().1;
|
if selection > -1 && selection < (count as i32) {
|
||||||
gamelog::Logger::new()
|
let item = inventory_ids
|
||||||
.append("You identify the")
|
.iter()
|
||||||
.colour(item_colour_ecs(&gs.ecs, *item))
|
.nth(selection as usize)
|
||||||
.append_n(obfuscate_name_ecs(&gs.ecs, *item).0)
|
.unwrap().1;
|
||||||
.colour(WHITE)
|
gamelog::Logger
|
||||||
.append("!")
|
::new()
|
||||||
.log();
|
.append("You identify the")
|
||||||
return (ItemMenuResult::Selected, Some(*item));
|
.colour(item_colour_ecs(&gs.ecs, *item))
|
||||||
|
.append_n(obfuscate_name_ecs(&gs.ecs, *item).0)
|
||||||
|
.colour(WHITE)
|
||||||
|
.append("!")
|
||||||
|
.log();
|
||||||
|
return (ItemMenuResult::Selected, Some(*item));
|
||||||
|
}
|
||||||
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
423
src/gui/mod.rs
423
src/gui/mod.rs
|
|
@ -1,8 +1,38 @@
|
||||||
use super::{
|
use super::{
|
||||||
ai::CARRY_CAPACITY_PER_STRENGTH, camera, gamelog, gamesystem, hunger_system::get_hunger_colour,
|
ai::CARRY_CAPACITY_PER_STRENGTH,
|
||||||
rex_assets::RexAssets, ArmourClassBonus, Attributes, Beatitude, Burden, Charges, Equipped, Hidden, HungerClock,
|
camera,
|
||||||
HungerState, InBackpack, KnownSpells, MagicItem, Map, MasterDungeonMap, Name, ObfuscatedName, Player, Point, Pools,
|
gamelog,
|
||||||
Position, Prop, Renderable, RunState, Skill, Skills, State, Viewshed, BUC,
|
gamesystem,
|
||||||
|
hunger_system::get_hunger_colour,
|
||||||
|
rex_assets::RexAssets,
|
||||||
|
ArmourClassBonus,
|
||||||
|
Attributes,
|
||||||
|
Beatitude,
|
||||||
|
Burden,
|
||||||
|
Charges,
|
||||||
|
Equipped,
|
||||||
|
Hidden,
|
||||||
|
HungerClock,
|
||||||
|
HungerState,
|
||||||
|
InBackpack,
|
||||||
|
KnownSpells,
|
||||||
|
MagicItem,
|
||||||
|
Map,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Player,
|
||||||
|
Point,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
Prop,
|
||||||
|
Renderable,
|
||||||
|
RunState,
|
||||||
|
Skill,
|
||||||
|
Skills,
|
||||||
|
State,
|
||||||
|
Viewshed,
|
||||||
|
BUC,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -25,11 +55,12 @@ pub fn yes_no(ctx: &mut Rltk, question: String) -> Option<bool> {
|
||||||
ctx.print_color_centered(17, RGB::named(rltk::CYAN), RGB::named(rltk::BLACK), "(y)es or (n)o");
|
ctx.print_color_centered(17, RGB::named(rltk::CYAN), RGB::named(rltk::BLACK), "(y)es or (n)o");
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => None,
|
None => None,
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Y => Some(true),
|
match key {
|
||||||
VirtualKeyCode::N => Some(false),
|
VirtualKeyCode::Y => Some(true),
|
||||||
_ => None,
|
VirtualKeyCode::N => Some(false),
|
||||||
},
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,10 +72,10 @@ pub fn draw_lerping_bar(
|
||||||
n: i32,
|
n: i32,
|
||||||
max: i32,
|
max: i32,
|
||||||
full_colour: RGB,
|
full_colour: RGB,
|
||||||
empty_colour: RGB,
|
empty_colour: RGB
|
||||||
) {
|
) {
|
||||||
let percent = n as f32 / max as f32;
|
let percent = (n as f32) / (max as f32);
|
||||||
let fill_width = (percent * width as f32) as i32;
|
let fill_width = (percent * (width as f32)) as i32;
|
||||||
let bg = empty_colour.lerp(full_colour, percent);
|
let bg = empty_colour.lerp(full_colour, percent);
|
||||||
let fg = RGB::named(rltk::BLACK);
|
let fg = RGB::named(rltk::BLACK);
|
||||||
for x in 0..width {
|
for x in 0..width {
|
||||||
|
|
@ -78,7 +109,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
stats.hit_points.current,
|
stats.hit_points.current,
|
||||||
stats.hit_points.max,
|
stats.hit_points.max,
|
||||||
RGB::from_u8(0, 255, 0),
|
RGB::from_u8(0, 255, 0),
|
||||||
RGB::from_u8(255, 0, 0),
|
RGB::from_u8(255, 0, 0)
|
||||||
);
|
);
|
||||||
draw_lerping_bar(
|
draw_lerping_bar(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -88,7 +119,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
stats.mana.current,
|
stats.mana.current,
|
||||||
stats.mana.max,
|
stats.mana.max,
|
||||||
RGB::named(rltk::BLUE),
|
RGB::named(rltk::BLUE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK)
|
||||||
);
|
);
|
||||||
// Draw AC
|
// Draw AC
|
||||||
let skill_ac_bonus = gamesystem::skill_bonus(Skill::Defence, &*skills);
|
let skill_ac_bonus = gamesystem::skill_bonus(Skill::Defence, &*skills);
|
||||||
|
|
@ -101,7 +132,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
armour_ac_bonus += ac.amount;
|
armour_ac_bonus += ac.amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let armour_class = stats.bac - (attributes.dexterity.bonus / 2) - skill_ac_bonus - armour_ac_bonus;
|
let armour_class = stats.bac - attributes.dexterity.bonus / 2 - skill_ac_bonus - armour_ac_bonus;
|
||||||
ctx.print_color(26, 53, RGB::named(rltk::PINK), RGB::named(rltk::BLACK), "AC");
|
ctx.print_color(26, 53, RGB::named(rltk::PINK), RGB::named(rltk::BLACK), "AC");
|
||||||
ctx.print_color(28, 53, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), armour_class);
|
ctx.print_color(28, 53, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), armour_class);
|
||||||
// Draw level
|
// Draw level
|
||||||
|
|
@ -110,7 +141,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
54,
|
54,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
format!("XP{}/{}", stats.level, stats.xp),
|
format!("XP{}/{}", stats.level, stats.xp)
|
||||||
);
|
);
|
||||||
// Draw attributes
|
// Draw attributes
|
||||||
let x = 38;
|
let x = 38;
|
||||||
|
|
@ -129,33 +160,33 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
// Draw hunger
|
// Draw hunger
|
||||||
match hunger.state {
|
match hunger.state {
|
||||||
HungerState::Satiated => {
|
HungerState::Satiated => {
|
||||||
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Satiated")
|
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Satiated");
|
||||||
}
|
}
|
||||||
HungerState::Normal => {}
|
HungerState::Normal => {}
|
||||||
HungerState::Hungry => {
|
HungerState::Hungry => {
|
||||||
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Hungry")
|
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Hungry");
|
||||||
}
|
}
|
||||||
HungerState::Weak => {
|
HungerState::Weak => {
|
||||||
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Weak")
|
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Weak");
|
||||||
}
|
}
|
||||||
HungerState::Fainting => {
|
HungerState::Fainting => {
|
||||||
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Fainting")
|
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Fainting");
|
||||||
}
|
}
|
||||||
HungerState::Starving => {
|
HungerState::Starving => {
|
||||||
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Starving")
|
ctx.print_color_right(70, 53, get_hunger_colour(hunger.state), RGB::named(rltk::BLACK), "Starving");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Burden
|
// Burden
|
||||||
if let Some(burden) = burden.get(*player_entity) {
|
if let Some(burden) = burden.get(*player_entity) {
|
||||||
match burden.level {
|
match burden.level {
|
||||||
crate::BurdenLevel::Burdened => {
|
crate::BurdenLevel::Burdened => {
|
||||||
ctx.print_color_right(70, 50, RGB::named(rltk::BROWN1), RGB::named(rltk::BLACK), "Burdened")
|
ctx.print_color_right(70, 50, RGB::named(rltk::BROWN1), RGB::named(rltk::BLACK), "Burdened");
|
||||||
}
|
}
|
||||||
crate::BurdenLevel::Strained => {
|
crate::BurdenLevel::Strained => {
|
||||||
ctx.print_color_right(70, 50, RGB::named(rltk::ORANGE), RGB::named(rltk::BLACK), "Strained")
|
ctx.print_color_right(70, 50, RGB::named(rltk::ORANGE), RGB::named(rltk::BLACK), "Strained");
|
||||||
}
|
}
|
||||||
crate::BurdenLevel::Overloaded => {
|
crate::BurdenLevel::Overloaded => {
|
||||||
ctx.print_color_right(70, 50, RGB::named(rltk::RED), RGB::named(rltk::BLACK), "Overloaded")
|
ctx.print_color_right(70, 50, RGB::named(rltk::RED), RGB::named(rltk::BLACK), "Overloaded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,9 +197,9 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
let renderables = ecs.read_storage::<Renderable>();
|
let renderables = ecs.read_storage::<Renderable>();
|
||||||
let mut equipment: Vec<(String, RGB, RGB, rltk::FontCharType)> = Vec::new();
|
let mut equipment: Vec<(String, RGB, RGB, rltk::FontCharType)> = Vec::new();
|
||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
for (entity, _equipped, renderable) in
|
for (entity, _equipped, renderable) in (&entities, &equipped, &renderables)
|
||||||
(&entities, &equipped, &renderables).join().filter(|item| item.1.owner == *player_entity)
|
.join()
|
||||||
{
|
.filter(|item| item.1.owner == *player_entity) {
|
||||||
equipment.push((
|
equipment.push((
|
||||||
obfuscate_name_ecs(ecs, entity).0,
|
obfuscate_name_ecs(ecs, entity).0,
|
||||||
RGB::named(item_colour_ecs(ecs, entity)),
|
RGB::named(item_colour_ecs(ecs, entity)),
|
||||||
|
|
@ -182,7 +213,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
for item in equipment {
|
for item in equipment {
|
||||||
y += 1;
|
y += 1;
|
||||||
ctx.set(72, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType);
|
ctx.set(72, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + (j as rltk::FontCharType));
|
||||||
j += 1;
|
j += 1;
|
||||||
ctx.set(74, y, item.2, RGB::named(rltk::BLACK), item.3);
|
ctx.set(74, y, item.2, RGB::named(rltk::BLACK), item.3);
|
||||||
ctx.print_color(76, y, item.1, RGB::named(rltk::BLACK), &item.0);
|
ctx.print_color(76, y, item.1, RGB::named(rltk::BLACK), &item.0);
|
||||||
|
|
@ -202,7 +233,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
"[{:.1}/{} lbs]",
|
"[{:.1}/{} lbs]",
|
||||||
stats.weight,
|
stats.weight,
|
||||||
(attributes.strength.base + attributes.strength.modifiers) * CARRY_CAPACITY_PER_STRENGTH
|
(attributes.strength.base + attributes.strength.modifiers) * CARRY_CAPACITY_PER_STRENGTH
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
y += 1;
|
y += 1;
|
||||||
let (player_inventory, _inventory_ids) = get_player_inventory(&ecs);
|
let (player_inventory, _inventory_ids) = get_player_inventory(&ecs);
|
||||||
|
|
@ -222,7 +253,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
y,
|
y,
|
||||||
RGB::named(CYAN),
|
RGB::named(CYAN),
|
||||||
RGB::named(BLACK),
|
RGB::named(BLACK),
|
||||||
&format!("{} ({})", "Force Bolt - NYI!", spell.mana_cost),
|
&format!("{} ({})", "Force Bolt - NYI!", spell.mana_cost)
|
||||||
);
|
);
|
||||||
index += 1;
|
index += 1;
|
||||||
y += 1;
|
y += 1;
|
||||||
|
|
@ -298,7 +329,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
54,
|
54,
|
||||||
RGB::named(rltk::YELLOW),
|
RGB::named(rltk::YELLOW),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
&format!("T{}", crate::gamelog::get_event_count("turns")),
|
&format!("T{}", crate::gamelog::get_event_count("turns"))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Boxes and tooltips last, so they draw over everything else.
|
// Boxes and tooltips last, so they draw over everything else.
|
||||||
|
|
@ -312,7 +343,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
pub fn get_input_direction(
|
pub fn get_input_direction(
|
||||||
ecs: &mut World,
|
ecs: &mut World,
|
||||||
ctx: &mut Rltk,
|
ctx: &mut Rltk,
|
||||||
function: fn(i: i32, j: i32, ecs: &mut World) -> RunState,
|
function: fn(i: i32, j: i32, ecs: &mut World) -> RunState
|
||||||
) -> RunState {
|
) -> RunState {
|
||||||
let (_, _, _, _, x_offset, y_offset) = camera::get_screen_bounds(ecs, ctx);
|
let (_, _, _, _, x_offset, y_offset) = camera::get_screen_bounds(ecs, ctx);
|
||||||
|
|
||||||
|
|
@ -321,24 +352,47 @@ pub fn get_input_direction(
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"In what direction? [0-9]/[YUHJKLBN]",
|
"In what direction? [0-9]/[YUHJKLBN]"
|
||||||
);
|
);
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => return RunState::ActionWithDirection { function },
|
None => {
|
||||||
Some(key) => match key {
|
return RunState::ActionWithDirection { function };
|
||||||
VirtualKeyCode::Escape => return RunState::AwaitingInput,
|
}
|
||||||
// Cardinals
|
Some(key) =>
|
||||||
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => return function(-1, 0, ecs),
|
match key {
|
||||||
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => return function(1, 0, ecs),
|
VirtualKeyCode::Escape => {
|
||||||
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => return function(0, -1, ecs),
|
return RunState::AwaitingInput;
|
||||||
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => return function(0, 1, ecs),
|
}
|
||||||
// Diagonals
|
// Cardinals
|
||||||
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => return function(1, -1, ecs),
|
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
|
||||||
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => return function(-1, -1, ecs),
|
return function(-1, 0, ecs);
|
||||||
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => return function(1, 1, ecs),
|
}
|
||||||
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => return function(-1, 1, ecs),
|
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
|
||||||
_ => return RunState::ActionWithDirection { function },
|
return function(1, 0, ecs);
|
||||||
},
|
}
|
||||||
|
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
|
||||||
|
return function(0, -1, ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
|
||||||
|
return function(0, 1, ecs);
|
||||||
|
}
|
||||||
|
// Diagonals
|
||||||
|
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => {
|
||||||
|
return function(1, -1, ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => {
|
||||||
|
return function(-1, -1, ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => {
|
||||||
|
return function(1, 1, ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => {
|
||||||
|
return function(-1, 1, ecs);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return RunState::ActionWithDirection { function };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -353,7 +407,7 @@ pub fn print_options(
|
||||||
inventory: BTreeMap<UniqueInventoryItem, i32>,
|
inventory: BTreeMap<UniqueInventoryItem, i32>,
|
||||||
mut x: i32,
|
mut x: i32,
|
||||||
mut y: i32,
|
mut y: i32,
|
||||||
ctx: &mut Rltk,
|
ctx: &mut Rltk
|
||||||
) -> (i32, i32) {
|
) -> (i32, i32) {
|
||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
let initial_x: i32 = x;
|
let initial_x: i32 = x;
|
||||||
|
|
@ -362,10 +416,10 @@ pub fn print_options(
|
||||||
x = initial_x;
|
x = initial_x;
|
||||||
// Print the character required to access this item. i.e. (a)
|
// Print the character required to access this item. i.e. (a)
|
||||||
if j < 26 {
|
if j < 26 {
|
||||||
ctx.set(x, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType);
|
ctx.set(x, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + (j as rltk::FontCharType));
|
||||||
} else {
|
} else {
|
||||||
// If we somehow have more than 26, start using capitals
|
// If we somehow have more than 26, start using capitals
|
||||||
ctx.set(x, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 65 - 26 + j as rltk::FontCharType);
|
ctx.set(x, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 65 - 26 + (j as rltk::FontCharType));
|
||||||
}
|
}
|
||||||
|
|
||||||
x += 2;
|
x += 2;
|
||||||
|
|
@ -380,15 +434,14 @@ pub fn print_options(
|
||||||
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item_count);
|
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item_count);
|
||||||
x += 2;
|
x += 2;
|
||||||
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.plural.to_string());
|
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.plural.to_string());
|
||||||
let this_width = x - initial_x + item.display_name.plural.len() as i32;
|
let this_width = x - initial_x + (item.display_name.plural.len() as i32);
|
||||||
width = if width > this_width { width } else { this_width };
|
width = if width > this_width { width } else { this_width };
|
||||||
} else {
|
} else {
|
||||||
if item.display_name.singular.to_lowercase().ends_with("s") {
|
if item.display_name.singular.to_lowercase().ends_with("s") {
|
||||||
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "some");
|
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "some");
|
||||||
x += 5;
|
x += 5;
|
||||||
} else if ['a', 'e', 'i', 'o', 'u']
|
} else if
|
||||||
.iter()
|
['a', 'e', 'i', 'o', 'u'].iter().any(|&v| item.display_name.singular.to_lowercase().starts_with(v))
|
||||||
.any(|&v| item.display_name.singular.to_lowercase().starts_with(v))
|
|
||||||
{
|
{
|
||||||
// If one and starts with a vowel, print 'an'
|
// If one and starts with a vowel, print 'an'
|
||||||
// i.e. (a) an apple
|
// i.e. (a) an apple
|
||||||
|
|
@ -401,7 +454,7 @@ pub fn print_options(
|
||||||
x += 2;
|
x += 2;
|
||||||
}
|
}
|
||||||
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.singular.to_string());
|
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item.display_name.singular.to_string());
|
||||||
let this_width = x - initial_x + item.display_name.singular.len() as i32;
|
let this_width = x - initial_x + (item.display_name.singular.len() as i32);
|
||||||
width = if width > this_width { width } else { this_width };
|
width = if width > this_width { width } else { this_width };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +495,7 @@ pub fn obfuscate_name(
|
||||||
obfuscated_names: &ReadStorage<ObfuscatedName>,
|
obfuscated_names: &ReadStorage<ObfuscatedName>,
|
||||||
beatitudes: &ReadStorage<Beatitude>,
|
beatitudes: &ReadStorage<Beatitude>,
|
||||||
dm: &MasterDungeonMap,
|
dm: &MasterDungeonMap,
|
||||||
wand: Option<&ReadStorage<Charges>>,
|
wand: Option<&ReadStorage<Charges>>
|
||||||
) -> (String, String) {
|
) -> (String, String) {
|
||||||
let (mut singular, mut plural) = ("nameless item (bug)".to_string(), "nameless items (bug)".to_string());
|
let (mut singular, mut plural) = ("nameless item (bug)".to_string(), "nameless items (bug)".to_string());
|
||||||
if let Some(name) = names.get(item) {
|
if let Some(name) = names.get(item) {
|
||||||
|
|
@ -537,9 +590,15 @@ pub fn item_colour_ecs(ecs: &World, item: Entity) -> (u8, u8, u8) {
|
||||||
if let Some(beatitude) = ecs.read_storage::<Beatitude>().get(item) {
|
if let Some(beatitude) = ecs.read_storage::<Beatitude>().get(item) {
|
||||||
if beatitude.known {
|
if beatitude.known {
|
||||||
match beatitude.buc {
|
match beatitude.buc {
|
||||||
BUC::Blessed => return GREEN,
|
BUC::Blessed => {
|
||||||
BUC::Uncursed => return WHITE,
|
return GREEN;
|
||||||
BUC::Cursed => return RED,
|
}
|
||||||
|
BUC::Uncursed => {
|
||||||
|
return WHITE;
|
||||||
|
}
|
||||||
|
BUC::Cursed => {
|
||||||
|
return RED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unidentified magic item
|
// Unidentified magic item
|
||||||
|
|
@ -554,9 +613,15 @@ pub fn item_colour(item: Entity, beatitudes: &ReadStorage<Beatitude>) -> (u8, u8
|
||||||
if let Some(beatitude) = beatitudes.get(item) {
|
if let Some(beatitude) = beatitudes.get(item) {
|
||||||
if beatitude.known {
|
if beatitude.known {
|
||||||
match beatitude.buc {
|
match beatitude.buc {
|
||||||
BUC::Blessed => return GREEN,
|
BUC::Blessed => {
|
||||||
BUC::Uncursed => return WHITE,
|
return GREEN;
|
||||||
BUC::Cursed => return RED,
|
}
|
||||||
|
BUC::Uncursed => {
|
||||||
|
return WHITE;
|
||||||
|
}
|
||||||
|
BUC::Cursed => {
|
||||||
|
return RED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unidentified magic item
|
// Unidentified magic item
|
||||||
|
|
@ -601,16 +666,17 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => YesNoResult::NoSelection,
|
None => YesNoResult::NoSelection,
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => YesNoResult::Yes,
|
match key {
|
||||||
VirtualKeyCode::Slash => {
|
VirtualKeyCode::Escape => YesNoResult::Yes,
|
||||||
if ctx.shift {
|
VirtualKeyCode::Slash => {
|
||||||
return YesNoResult::Yes;
|
if ctx.shift {
|
||||||
|
return YesNoResult::Yes;
|
||||||
|
}
|
||||||
|
return YesNoResult::NoSelection;
|
||||||
}
|
}
|
||||||
return YesNoResult::NoSelection;
|
_ => YesNoResult::NoSelection,
|
||||||
}
|
}
|
||||||
_ => YesNoResult::NoSelection,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -638,13 +704,16 @@ pub fn get_player_inventory(ecs: &World) -> (BTreeMap<UniqueInventoryItem, i32>,
|
||||||
|
|
||||||
let mut inventory_ids: BTreeMap<String, Entity> = BTreeMap::new();
|
let mut inventory_ids: BTreeMap<String, Entity> = BTreeMap::new();
|
||||||
let mut player_inventory: BTreeMap<UniqueInventoryItem, i32> = BTreeMap::new();
|
let mut player_inventory: BTreeMap<UniqueInventoryItem, i32> = BTreeMap::new();
|
||||||
for (entity, _pack, name, renderable) in
|
for (entity, _pack, name, renderable) in (&entities, &backpack, &names, &renderables)
|
||||||
(&entities, &backpack, &names, &renderables).join().filter(|item| item.1.owner == *player_entity)
|
.join()
|
||||||
{
|
.filter(|item| item.1.owner == *player_entity) {
|
||||||
// RGB can't be used as a key. This is converting the RGB (tuple of f32) into a tuple of u8s.
|
// RGB can't be used as a key. This is converting the RGB (tuple of f32) into a tuple of u8s.
|
||||||
let item_colour = item_colour_ecs(ecs, entity);
|
let item_colour = item_colour_ecs(ecs, entity);
|
||||||
let renderables =
|
let renderables = (
|
||||||
((renderable.fg.r * 255.0) as u8, (renderable.fg.g * 255.0) as u8, (renderable.fg.b * 255.0) as u8);
|
(renderable.fg.r * 255.0) as u8,
|
||||||
|
(renderable.fg.g * 255.0) as u8,
|
||||||
|
(renderable.fg.b * 255.0) as u8,
|
||||||
|
);
|
||||||
let (singular, plural) = obfuscate_name_ecs(ecs, entity);
|
let (singular, plural) = obfuscate_name_ecs(ecs, entity);
|
||||||
player_inventory
|
player_inventory
|
||||||
.entry(UniqueInventoryItem {
|
.entry(UniqueInventoryItem {
|
||||||
|
|
@ -654,7 +723,9 @@ pub fn get_player_inventory(ecs: &World) -> (BTreeMap<UniqueInventoryItem, i32>,
|
||||||
glyph: renderable.glyph,
|
glyph: renderable.glyph,
|
||||||
name: name.name.clone(),
|
name: name.name.clone(),
|
||||||
})
|
})
|
||||||
.and_modify(|count| *count += 1)
|
.and_modify(|count| {
|
||||||
|
*count += 1;
|
||||||
|
})
|
||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
inventory_ids.entry(singular).or_insert(entity);
|
inventory_ids.entry(singular).or_insert(entity);
|
||||||
}
|
}
|
||||||
|
|
@ -673,7 +744,7 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Interact with what item? [aA-zZ][Esc.]",
|
"Interact with what item? [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
|
|
||||||
let x = 1 + x_offset;
|
let x = 1 + x_offset;
|
||||||
|
|
@ -684,16 +755,25 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
None => (ItemMenuResult::NoResponse, None),
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
match key {
|
||||||
_ => {
|
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||||
let selection = letter_to_option::letter_to_option(key, ctx.shift);
|
_ => {
|
||||||
if selection > -1 && selection < count as i32 {
|
let selection = letter_to_option::letter_to_option(key, ctx.shift);
|
||||||
return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1));
|
if selection > -1 && selection < (count as i32) {
|
||||||
|
return (
|
||||||
|
ItemMenuResult::Selected,
|
||||||
|
Some(
|
||||||
|
*inventory_ids
|
||||||
|
.iter()
|
||||||
|
.nth(selection as usize)
|
||||||
|
.unwrap().1
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -708,7 +788,7 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Drop what? [aA-zZ][Esc.]",
|
"Drop what? [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
|
|
||||||
let x = 1 + x_offset;
|
let x = 1 + x_offset;
|
||||||
|
|
@ -719,16 +799,25 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
None => (ItemMenuResult::NoResponse, None),
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
match key {
|
||||||
_ => {
|
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||||
let selection = rltk::letter_to_option(key);
|
_ => {
|
||||||
if selection > -1 && selection < count as i32 {
|
let selection = rltk::letter_to_option(key);
|
||||||
return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1));
|
if selection > -1 && selection < (count as i32) {
|
||||||
|
return (
|
||||||
|
ItemMenuResult::Selected,
|
||||||
|
Some(
|
||||||
|
*inventory_ids
|
||||||
|
.iter()
|
||||||
|
.nth(selection as usize)
|
||||||
|
.unwrap().1
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -746,7 +835,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Unequip what? [aA-zZ][Esc.]",
|
"Unequip what? [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut equippable: Vec<(Entity, String)> = Vec::new();
|
let mut equippable: Vec<(Entity, String)> = Vec::new();
|
||||||
|
|
@ -772,7 +861,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
|
||||||
} else {
|
} else {
|
||||||
(RGB::named(rltk::WHITE), rltk::to_cp437('-'))
|
(RGB::named(rltk::WHITE), rltk::to_cp437('-'))
|
||||||
};
|
};
|
||||||
ctx.set(x + 1, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType);
|
ctx.set(x + 1, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + (j as rltk::FontCharType));
|
||||||
ctx.set(x + 3, y, fg, RGB::named(rltk::BLACK), glyph);
|
ctx.set(x + 3, y, fg, RGB::named(rltk::BLACK), glyph);
|
||||||
fg = RGB::named(item_colour_ecs(&gs.ecs, *e));
|
fg = RGB::named(item_colour_ecs(&gs.ecs, *e));
|
||||||
ctx.print_color(x + 5, y, fg, RGB::named(rltk::BLACK), name);
|
ctx.print_color(x + 5, y, fg, RGB::named(rltk::BLACK), name);
|
||||||
|
|
@ -782,16 +871,17 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
None => (ItemMenuResult::NoResponse, None),
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
match key {
|
||||||
_ => {
|
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||||
let selection = rltk::letter_to_option(key);
|
_ => {
|
||||||
if selection > -1 && selection < count as i32 {
|
let selection = rltk::letter_to_option(key);
|
||||||
return (ItemMenuResult::Selected, Some(equippable[selection as usize].0));
|
if selection > -1 && selection < (count as i32) {
|
||||||
|
return (ItemMenuResult::Selected, Some(equippable[selection as usize].0));
|
||||||
|
}
|
||||||
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -806,7 +896,7 @@ pub fn ranged_target(gs: &mut State, ctx: &mut Rltk, range: i32, aoe: i32) -> (I
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Targeting which tile? [mouse input]",
|
"Targeting which tile? [mouse input]"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Highlight available cells
|
// Highlight available cells
|
||||||
|
|
@ -816,10 +906,10 @@ pub fn ranged_target(gs: &mut State, ctx: &mut Rltk, range: i32, aoe: i32) -> (I
|
||||||
// We have a viewshed
|
// We have a viewshed
|
||||||
for idx in visible.visible_tiles.iter() {
|
for idx in visible.visible_tiles.iter() {
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(*player_pos, *idx);
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(*player_pos, *idx);
|
||||||
if distance <= range as f32 {
|
if distance <= (range as f32) {
|
||||||
let screen_x = idx.x - min_x;
|
let screen_x = idx.x - min_x;
|
||||||
let screen_y = idx.y - min_y;
|
let screen_y = idx.y - min_y;
|
||||||
if screen_x > 1 && screen_x < (max_x - min_x) - 1 && screen_y > 1 && screen_y < (max_y - min_y) - 1 {
|
if screen_x > 1 && screen_x < max_x - min_x - 1 && screen_y > 1 && screen_y < max_y - min_y - 1 {
|
||||||
ctx.set_bg(screen_x + x_offset, screen_y + y_offset, RGB::named(rltk::BLUE));
|
ctx.set_bg(screen_x + x_offset, screen_y + y_offset, RGB::named(rltk::BLUE));
|
||||||
available_cells.push(idx);
|
available_cells.push(idx);
|
||||||
}
|
}
|
||||||
|
|
@ -845,8 +935,11 @@ pub fn ranged_target(gs: &mut State, ctx: &mut Rltk, range: i32, aoe: i32) -> (I
|
||||||
if aoe > 0 {
|
if aoe > 0 {
|
||||||
// We adjust for camera position when getting FOV, but then we need to adjust back
|
// We adjust for camera position when getting FOV, but then we need to adjust back
|
||||||
// when iterating through the tiles themselves, by taking away min_x/min_y.
|
// when iterating through the tiles themselves, by taking away min_x/min_y.
|
||||||
let mut blast_tiles =
|
let mut blast_tiles = rltk::field_of_view(
|
||||||
rltk::field_of_view(Point::new(mouse_pos_adjusted.0, mouse_pos_adjusted.1), aoe, &*map);
|
Point::new(mouse_pos_adjusted.0, mouse_pos_adjusted.1),
|
||||||
|
aoe,
|
||||||
|
&*map
|
||||||
|
);
|
||||||
blast_tiles.retain(|p| p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1);
|
blast_tiles.retain(|p| p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1);
|
||||||
for tile in blast_tiles.iter() {
|
for tile in blast_tiles.iter() {
|
||||||
ctx.set_bg(tile.x - min_x + x_offset, tile.y - min_y + y_offset, RGB::named(rltk::DARKCYAN));
|
ctx.set_bg(tile.x - min_x + x_offset, tile.y - min_y + y_offset, RGB::named(rltk::DARKCYAN));
|
||||||
|
|
@ -875,8 +968,12 @@ pub enum MainMenuSelection {
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum MainMenuResult {
|
pub enum MainMenuResult {
|
||||||
NoSelection { selected: MainMenuSelection },
|
NoSelection {
|
||||||
Selected { selected: MainMenuSelection },
|
selected: MainMenuSelection,
|
||||||
|
},
|
||||||
|
Selected {
|
||||||
|
selected: MainMenuSelection,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
|
pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
|
||||||
|
|
@ -924,42 +1021,63 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => return MainMenuResult::NoSelection { selected: selection },
|
None => {
|
||||||
Some(key) => match key {
|
return MainMenuResult::NoSelection { selected: selection };
|
||||||
VirtualKeyCode::Escape | VirtualKeyCode::C => {
|
}
|
||||||
return MainMenuResult::NoSelection { selected: MainMenuSelection::Quit }
|
Some(key) =>
|
||||||
}
|
match key {
|
||||||
VirtualKeyCode::N => return MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame },
|
VirtualKeyCode::Escape | VirtualKeyCode::C => {
|
||||||
VirtualKeyCode::L => return MainMenuResult::NoSelection { selected: MainMenuSelection::LoadGame },
|
return MainMenuResult::NoSelection { selected: MainMenuSelection::Quit };
|
||||||
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
|
|
||||||
let mut new_selection;
|
|
||||||
match selection {
|
|
||||||
MainMenuSelection::NewGame => new_selection = MainMenuSelection::LoadGame,
|
|
||||||
MainMenuSelection::LoadGame => new_selection = MainMenuSelection::Quit,
|
|
||||||
MainMenuSelection::Quit => new_selection = MainMenuSelection::NewGame,
|
|
||||||
}
|
}
|
||||||
if new_selection == MainMenuSelection::LoadGame && !save_exists {
|
VirtualKeyCode::N => {
|
||||||
new_selection = MainMenuSelection::NewGame;
|
return MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame };
|
||||||
}
|
}
|
||||||
return MainMenuResult::NoSelection { selected: new_selection };
|
VirtualKeyCode::L => {
|
||||||
}
|
return MainMenuResult::NoSelection { selected: MainMenuSelection::LoadGame };
|
||||||
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
|
|
||||||
let mut new_selection;
|
|
||||||
match selection {
|
|
||||||
MainMenuSelection::NewGame => new_selection = MainMenuSelection::Quit,
|
|
||||||
MainMenuSelection::LoadGame => new_selection = MainMenuSelection::NewGame,
|
|
||||||
MainMenuSelection::Quit => new_selection = MainMenuSelection::LoadGame,
|
|
||||||
}
|
}
|
||||||
if new_selection == MainMenuSelection::LoadGame && !save_exists {
|
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
|
||||||
new_selection = MainMenuSelection::Quit;
|
let mut new_selection;
|
||||||
|
match selection {
|
||||||
|
MainMenuSelection::NewGame => {
|
||||||
|
new_selection = MainMenuSelection::LoadGame;
|
||||||
|
}
|
||||||
|
MainMenuSelection::LoadGame => {
|
||||||
|
new_selection = MainMenuSelection::Quit;
|
||||||
|
}
|
||||||
|
MainMenuSelection::Quit => {
|
||||||
|
new_selection = MainMenuSelection::NewGame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if new_selection == MainMenuSelection::LoadGame && !save_exists {
|
||||||
|
new_selection = MainMenuSelection::NewGame;
|
||||||
|
}
|
||||||
|
return MainMenuResult::NoSelection { selected: new_selection };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
|
||||||
|
let mut new_selection;
|
||||||
|
match selection {
|
||||||
|
MainMenuSelection::NewGame => {
|
||||||
|
new_selection = MainMenuSelection::Quit;
|
||||||
|
}
|
||||||
|
MainMenuSelection::LoadGame => {
|
||||||
|
new_selection = MainMenuSelection::NewGame;
|
||||||
|
}
|
||||||
|
MainMenuSelection::Quit => {
|
||||||
|
new_selection = MainMenuSelection::LoadGame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if new_selection == MainMenuSelection::LoadGame && !save_exists {
|
||||||
|
new_selection = MainMenuSelection::Quit;
|
||||||
|
}
|
||||||
|
return MainMenuResult::NoSelection { selected: new_selection };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Return | VirtualKeyCode::NumpadEnter => {
|
||||||
|
return MainMenuResult::Selected { selected: selection };
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return MainMenuResult::NoSelection { selected: selection };
|
||||||
}
|
}
|
||||||
return MainMenuResult::NoSelection { selected: new_selection };
|
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Return | VirtualKeyCode::NumpadEnter => {
|
|
||||||
return MainMenuResult::Selected { selected: selection }
|
|
||||||
}
|
|
||||||
_ => return MainMenuResult::NoSelection { selected: selection },
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame }
|
MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame }
|
||||||
|
|
@ -986,7 +1104,7 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
|
||||||
y,
|
y,
|
||||||
RGB::named(rltk::GREEN),
|
RGB::named(rltk::GREEN),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
format!("You survived for {} turns.", crate::gamelog::get_event_count("turns")),
|
format!("You survived for {} turns.", crate::gamelog::get_event_count("turns"))
|
||||||
);
|
);
|
||||||
y += 2;
|
y += 2;
|
||||||
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), format!("And in the process, you"));
|
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), format!("And in the process, you"));
|
||||||
|
|
@ -997,7 +1115,7 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
|
||||||
y,
|
y,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
format!("- descended {} floor(s)", crate::gamelog::get_event_count("descended")),
|
format!("- descended {} floor(s)", crate::gamelog::get_event_count("descended"))
|
||||||
);
|
);
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1011,7 +1129,7 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
|
||||||
"- kicked {} time(s), breaking {} object(s)",
|
"- kicked {} time(s), breaking {} object(s)",
|
||||||
crate::gamelog::get_event_count("kick_count"),
|
crate::gamelog::get_event_count("kick_count"),
|
||||||
crate::gamelog::get_event_count("broken_doors")
|
crate::gamelog::get_event_count("broken_doors")
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1021,7 +1139,7 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
|
||||||
y,
|
y,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
format!("- slew {} other creature(s)", crate::gamelog::get_event_count("death_count")),
|
format!("- slew {} other creature(s)", crate::gamelog::get_event_count("death_count"))
|
||||||
);
|
);
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1031,15 +1149,16 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
|
||||||
y,
|
y,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
format!("- forgot the controls {} time(s)", crate::gamelog::get_event_count("looked_for_help")),
|
format!("- forgot the controls {} time(s)", crate::gamelog::get_event_count("looked_for_help"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => YesNoResult::NoSelection,
|
None => YesNoResult::NoSelection,
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => YesNoResult::Yes,
|
match key {
|
||||||
_ => YesNoResult::NoSelection,
|
VirtualKeyCode::Escape => YesNoResult::Yes,
|
||||||
},
|
_ => YesNoResult::NoSelection,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
use super::{
|
use super::{
|
||||||
get_max_inventory_width, item_colour_ecs, obfuscate_name_ecs, print_options, renderable_colour, ItemMenuResult,
|
get_max_inventory_width,
|
||||||
|
item_colour_ecs,
|
||||||
|
obfuscate_name_ecs,
|
||||||
|
print_options,
|
||||||
|
renderable_colour,
|
||||||
|
ItemMenuResult,
|
||||||
UniqueInventoryItem,
|
UniqueInventoryItem,
|
||||||
};
|
};
|
||||||
use crate::{gamelog, Beatitude, Entity, Equipped, InBackpack, Item, Name, Renderable, State, BUC};
|
use crate::{ gamelog, Beatitude, Entity, Equipped, InBackpack, Item, Name, Renderable, State, BUC };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
@ -58,7 +63,8 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
|
||||||
// If only one item, return it.
|
// If only one item, return it.
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
let item = build_cursed_iterator().nth(0).unwrap().0;
|
let item = build_cursed_iterator().nth(0).unwrap().0;
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You decurse the")
|
.append("You decurse the")
|
||||||
.colour(item_colour_ecs(&gs.ecs, item))
|
.colour(item_colour_ecs(&gs.ecs, item))
|
||||||
.append_n(obfuscate_name_ecs(&gs.ecs, item).0)
|
.append_n(obfuscate_name_ecs(&gs.ecs, item).0)
|
||||||
|
|
@ -79,7 +85,9 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
|
||||||
glyph: renderable.glyph,
|
glyph: renderable.glyph,
|
||||||
name: name.name.clone(),
|
name: name.name.clone(),
|
||||||
})
|
})
|
||||||
.and_modify(|count| *count += 1)
|
.and_modify(|count| {
|
||||||
|
*count += 1;
|
||||||
|
})
|
||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
inventory_ids.entry(singular).or_insert(entity);
|
inventory_ids.entry(singular).or_insert(entity);
|
||||||
}
|
}
|
||||||
|
|
@ -93,30 +101,35 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
|
||||||
1 + y_offset,
|
1 + y_offset,
|
||||||
RGB::named(rltk::WHITE),
|
RGB::named(rltk::WHITE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
"Decurse which item? [aA-zZ][Esc.]",
|
"Decurse which item? [aA-zZ][Esc.]"
|
||||||
);
|
);
|
||||||
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
|
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
|
||||||
print_options(player_inventory, x + 1, y + 1, ctx);
|
print_options(player_inventory, x + 1, y + 1, ctx);
|
||||||
// Input
|
// Input
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => (ItemMenuResult::NoResponse, None),
|
None => (ItemMenuResult::NoResponse, None),
|
||||||
Some(key) => match key {
|
Some(key) =>
|
||||||
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
match key {
|
||||||
_ => {
|
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
|
||||||
let selection = rltk::letter_to_option(key);
|
_ => {
|
||||||
if selection > -1 && selection < count as i32 {
|
let selection = rltk::letter_to_option(key);
|
||||||
let item = inventory_ids.iter().nth(selection as usize).unwrap().1;
|
if selection > -1 && selection < (count as i32) {
|
||||||
gamelog::Logger::new()
|
let item = inventory_ids
|
||||||
.append("You decurse the")
|
.iter()
|
||||||
.colour(item_colour_ecs(&gs.ecs, *item))
|
.nth(selection as usize)
|
||||||
.append_n(obfuscate_name_ecs(&gs.ecs, *item).0)
|
.unwrap().1;
|
||||||
.colour(WHITE)
|
gamelog::Logger
|
||||||
.append("!")
|
::new()
|
||||||
.log();
|
.append("You decurse the")
|
||||||
return (ItemMenuResult::Selected, Some(*item));
|
.colour(item_colour_ecs(&gs.ecs, *item))
|
||||||
|
.append_n(obfuscate_name_ecs(&gs.ecs, *item).0)
|
||||||
|
.colour(WHITE)
|
||||||
|
.append("!")
|
||||||
|
.log();
|
||||||
|
return (ItemMenuResult::Selected, Some(*item));
|
||||||
|
}
|
||||||
|
(ItemMenuResult::NoResponse, None)
|
||||||
}
|
}
|
||||||
(ItemMenuResult::NoResponse, None)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Renderable, Rltk, World, RGB};
|
use super::{ camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Renderable, Rltk, World, RGB };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -26,15 +26,15 @@ impl Tooltip {
|
||||||
max = s.0.len();
|
max = s.0.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max as i32 + 2i32;
|
return (max as i32) + 2i32;
|
||||||
}
|
}
|
||||||
fn height(&self) -> i32 {
|
fn height(&self) -> i32 {
|
||||||
return self.lines.len() as i32 + 2i32;
|
return (self.lines.len() as i32) + 2i32;
|
||||||
}
|
}
|
||||||
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
||||||
ctx.draw_box(x, y, self.width() - 1, self.height() - 1, RGB::named(WHITE), RGB::named(BLACK));
|
ctx.draw_box(x, y, self.width() - 1, self.height() - 1, RGB::named(WHITE), RGB::named(BLACK));
|
||||||
for (i, s) in self.lines.iter().enumerate() {
|
for (i, s) in self.lines.iter().enumerate() {
|
||||||
ctx.print_color(x + 1, y + i as i32 + 1, s.1, RGB::named(BLACK), &s.0);
|
ctx.print_color(x + 1, y + (i as i32) + 1, s.1, RGB::named(BLACK), &s.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
use super::{
|
use super::{
|
||||||
effects::{add_effect, EffectType, Targets},
|
effects::{ add_effect, EffectType, Targets },
|
||||||
gamelog, Clock, HungerClock, HungerState, TakingTurn, LOG_TICKS,
|
gamelog,
|
||||||
|
Clock,
|
||||||
|
HungerClock,
|
||||||
|
HungerState,
|
||||||
|
TakingTurn,
|
||||||
|
LOG_TICKS,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -74,10 +79,9 @@ impl<'a> System<'a> for HungerSystem {
|
||||||
add_effect(None, EffectType::Damage { amount: 1 }, Targets::Entity { target: entity });
|
add_effect(None, EffectType::Damage { amount: 1 }, Targets::Entity { target: entity });
|
||||||
}
|
}
|
||||||
if LOG_TICKS && entity == *player_entity {
|
if LOG_TICKS && entity == *player_entity {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"HUNGER SYSTEM: Ticked for player entity. [clock: {}]",
|
format!("HUNGER SYSTEM: Ticked for player entity. [clock: {}]", hunger_clock.duration)
|
||||||
hunger_clock.duration
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if hunger_clock.state == initial_state {
|
if hunger_clock.state == initial_state {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -87,39 +91,49 @@ impl<'a> System<'a> for HungerSystem {
|
||||||
}
|
}
|
||||||
// Things which only happen to the player.
|
// Things which only happen to the player.
|
||||||
match hunger_clock.state {
|
match hunger_clock.state {
|
||||||
HungerState::Satiated => gamelog::Logger::new()
|
HungerState::Satiated =>
|
||||||
.append("You feel")
|
gamelog::Logger
|
||||||
.colour(get_hunger_colour(hunger_clock.state))
|
::new()
|
||||||
.append_n("satiated")
|
.append("You feel")
|
||||||
.colour(WHITE)
|
.colour(get_hunger_colour(hunger_clock.state))
|
||||||
.period()
|
.append_n("satiated")
|
||||||
.log(),
|
.colour(WHITE)
|
||||||
|
.period()
|
||||||
|
.log(),
|
||||||
HungerState::Normal => {}
|
HungerState::Normal => {}
|
||||||
HungerState::Hungry => gamelog::Logger::new()
|
HungerState::Hungry =>
|
||||||
.append("You feel")
|
gamelog::Logger
|
||||||
.colour(get_hunger_colour(hunger_clock.state))
|
::new()
|
||||||
.append_n("hungry")
|
.append("You feel")
|
||||||
.colour(WHITE)
|
.colour(get_hunger_colour(hunger_clock.state))
|
||||||
.period()
|
.append_n("hungry")
|
||||||
.log(),
|
.colour(WHITE)
|
||||||
HungerState::Weak => gamelog::Logger::new()
|
.period()
|
||||||
.append("You feel")
|
.log(),
|
||||||
.colour(get_hunger_colour(hunger_clock.state))
|
HungerState::Weak =>
|
||||||
.append_n("weak with hunger")
|
gamelog::Logger
|
||||||
.colour(WHITE)
|
::new()
|
||||||
.period()
|
.append("You feel")
|
||||||
.log(),
|
.colour(get_hunger_colour(hunger_clock.state))
|
||||||
HungerState::Fainting => gamelog::Logger::new()
|
.append_n("weak with hunger")
|
||||||
.append("You feel")
|
.colour(WHITE)
|
||||||
.colour(get_hunger_colour(hunger_clock.state))
|
.period()
|
||||||
.append_n("hungry enough to faint")
|
.log(),
|
||||||
.colour(WHITE)
|
HungerState::Fainting =>
|
||||||
.period()
|
gamelog::Logger
|
||||||
.log(),
|
::new()
|
||||||
_ => gamelog::Logger::new()
|
.append("You feel")
|
||||||
.colour(get_hunger_colour(hunger_clock.state))
|
.colour(get_hunger_colour(hunger_clock.state))
|
||||||
.append_n("You can't go on without food!")
|
.append_n("hungry enough to faint")
|
||||||
.log(),
|
.colour(WHITE)
|
||||||
|
.period()
|
||||||
|
.log(),
|
||||||
|
_ =>
|
||||||
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
|
.colour(get_hunger_colour(hunger_clock.state))
|
||||||
|
.append_n("You can't go on without food!")
|
||||||
|
.log(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, gui::obfuscate_name, Beatitude, Charges, EquipmentChanged, InBackpack, MagicItem, MasterDungeonMap, Name,
|
gamelog,
|
||||||
ObfuscatedName, Position, WantsToPickupItem,
|
gui::obfuscate_name,
|
||||||
|
Beatitude,
|
||||||
|
Charges,
|
||||||
|
EquipmentChanged,
|
||||||
|
InBackpack,
|
||||||
|
MagicItem,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Position,
|
||||||
|
WantsToPickupItem,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -45,21 +55,23 @@ impl<'a> System<'a> for ItemCollectionSystem {
|
||||||
.expect("Unable to insert EquipmentChanged.");
|
.expect("Unable to insert EquipmentChanged.");
|
||||||
|
|
||||||
if pickup.collected_by == *player_entity {
|
if pickup.collected_by == *player_entity {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You pick up the")
|
.append("You pick up the")
|
||||||
.item_name_n(format!(
|
.item_name_n(
|
||||||
"{}",
|
format!(
|
||||||
obfuscate_name(
|
"{}",
|
||||||
pickup.item,
|
obfuscate_name(
|
||||||
&names,
|
pickup.item,
|
||||||
&magic_items,
|
&names,
|
||||||
&obfuscated_names,
|
&magic_items,
|
||||||
&beatitudes,
|
&obfuscated_names,
|
||||||
&dm,
|
&beatitudes,
|
||||||
Some(&wands)
|
&dm,
|
||||||
|
Some(&wands)
|
||||||
|
).0
|
||||||
)
|
)
|
||||||
.0
|
)
|
||||||
))
|
|
||||||
.period()
|
.period()
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog, gui::obfuscate_name, Beatitude, Charges, EquipmentChanged, InBackpack, MagicItem, MasterDungeonMap, Name,
|
gamelog,
|
||||||
ObfuscatedName, Position, WantsToDropItem,
|
gui::obfuscate_name,
|
||||||
|
Beatitude,
|
||||||
|
Charges,
|
||||||
|
EquipmentChanged,
|
||||||
|
InBackpack,
|
||||||
|
MagicItem,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
Position,
|
||||||
|
WantsToDropItem,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -53,21 +63,23 @@ impl<'a> System<'a> for ItemDropSystem {
|
||||||
backpack.remove(to_drop.item);
|
backpack.remove(to_drop.item);
|
||||||
|
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You drop the")
|
.append("You drop the")
|
||||||
.item_name_n(format!(
|
.item_name_n(
|
||||||
"{}",
|
format!(
|
||||||
obfuscate_name(
|
"{}",
|
||||||
to_drop.item,
|
obfuscate_name(
|
||||||
&names,
|
to_drop.item,
|
||||||
&magic_items,
|
&names,
|
||||||
&obfuscated_names,
|
&magic_items,
|
||||||
&beatitudes,
|
&obfuscated_names,
|
||||||
&dm,
|
&beatitudes,
|
||||||
Some(&wands)
|
&dm,
|
||||||
|
Some(&wands)
|
||||||
|
).0
|
||||||
)
|
)
|
||||||
.0
|
)
|
||||||
))
|
|
||||||
.period()
|
.period()
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,19 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog,
|
gamelog,
|
||||||
gui::{item_colour, obfuscate_name},
|
gui::{ item_colour, obfuscate_name },
|
||||||
Beatitude, EquipmentChanged, Equippable, Equipped, IdentifiedBeatitude, IdentifiedItem, InBackpack, MagicItem,
|
Beatitude,
|
||||||
MasterDungeonMap, Name, ObfuscatedName, WantsToUseItem, BUC,
|
EquipmentChanged,
|
||||||
|
Equippable,
|
||||||
|
Equipped,
|
||||||
|
IdentifiedBeatitude,
|
||||||
|
IdentifiedItem,
|
||||||
|
InBackpack,
|
||||||
|
MagicItem,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
WantsToUseItem,
|
||||||
|
BUC,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -70,9 +81,8 @@ impl<'a> System<'a> for ItemEquipSystem {
|
||||||
&obfuscated_names,
|
&obfuscated_names,
|
||||||
&beatitudes,
|
&beatitudes,
|
||||||
&dm,
|
&dm,
|
||||||
None,
|
None
|
||||||
)
|
).0
|
||||||
.0,
|
|
||||||
)
|
)
|
||||||
.colour(rltk::WHITE)
|
.colour(rltk::WHITE)
|
||||||
.append("!");
|
.append("!");
|
||||||
|
|
@ -96,8 +106,7 @@ impl<'a> System<'a> for ItemEquipSystem {
|
||||||
.append("You remove your")
|
.append("You remove your")
|
||||||
.colour(item_colour(*item, &beatitudes))
|
.colour(item_colour(*item, &beatitudes))
|
||||||
.append_n(
|
.append_n(
|
||||||
obfuscate_name(*item, &names, &magic_items, &obfuscated_names, &beatitudes, &dm, None)
|
obfuscate_name(*item, &names, &magic_items, &obfuscated_names, &beatitudes, &dm, None).0
|
||||||
.0,
|
|
||||||
)
|
)
|
||||||
.colour(rltk::WHITE)
|
.colour(rltk::WHITE)
|
||||||
.period();
|
.period();
|
||||||
|
|
@ -121,18 +130,16 @@ impl<'a> System<'a> for ItemEquipSystem {
|
||||||
&obfuscated_names,
|
&obfuscated_names,
|
||||||
&beatitudes,
|
&beatitudes,
|
||||||
&dm,
|
&dm,
|
||||||
None,
|
None
|
||||||
)
|
).0
|
||||||
.0,
|
|
||||||
)
|
)
|
||||||
.colour(rltk::WHITE)
|
.colour(rltk::WHITE)
|
||||||
.period();
|
.period();
|
||||||
logger.log();
|
logger.log();
|
||||||
identified_items
|
identified_items
|
||||||
.insert(
|
.insert(target, IdentifiedItem {
|
||||||
target,
|
name: names.get(wants_to_use_item.item).unwrap().name.clone(),
|
||||||
IdentifiedItem { name: names.get(wants_to_use_item.item).unwrap().name.clone() },
|
})
|
||||||
)
|
|
||||||
.expect("Unable to insert IdentifiedItem");
|
.expect("Unable to insert IdentifiedItem");
|
||||||
identified_beatitude
|
identified_beatitude
|
||||||
.insert(wants_to_use_item.item, IdentifiedBeatitude {})
|
.insert(wants_to_use_item.item, IdentifiedBeatitude {})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Beatitude, IdentifiedBeatitude, IdentifiedItem, Item, MasterDungeonMap, Name, ObfuscatedName, Player};
|
use crate::{ Beatitude, IdentifiedBeatitude, IdentifiedItem, Item, MasterDungeonMap, Name, ObfuscatedName, Player };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct ItemIdentificationSystem {}
|
pub struct ItemIdentificationSystem {}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ mod identification_system;
|
||||||
mod remove_system;
|
mod remove_system;
|
||||||
mod use_system;
|
mod use_system;
|
||||||
|
|
||||||
pub use {
|
pub use self::{
|
||||||
collection_system::ItemCollectionSystem, drop_system::ItemDropSystem, equip_system::ItemEquipSystem,
|
collection_system::ItemCollectionSystem,
|
||||||
identification_system::ItemIdentificationSystem, remove_system::ItemRemoveSystem, use_system::ItemUseSystem,
|
drop_system::ItemDropSystem,
|
||||||
|
equip_system::ItemEquipSystem,
|
||||||
|
identification_system::ItemIdentificationSystem,
|
||||||
|
remove_system::ItemRemoveSystem,
|
||||||
|
use_system::ItemUseSystem,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
gamelog,
|
gamelog,
|
||||||
gui::{item_colour, obfuscate_name},
|
gui::{ item_colour, obfuscate_name },
|
||||||
Beatitude, Equipped, InBackpack, MagicItem, MasterDungeonMap, Name, ObfuscatedName, WantsToRemoveItem, BUC,
|
Beatitude,
|
||||||
|
Equipped,
|
||||||
|
InBackpack,
|
||||||
|
MagicItem,
|
||||||
|
MasterDungeonMap,
|
||||||
|
Name,
|
||||||
|
ObfuscatedName,
|
||||||
|
WantsToRemoveItem,
|
||||||
|
BUC,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -43,7 +51,8 @@ impl<'a> System<'a> for ItemRemoveSystem {
|
||||||
// If cursed, can't remove!
|
// If cursed, can't remove!
|
||||||
if beatitude.buc == BUC::Cursed {
|
if beatitude.buc == BUC::Cursed {
|
||||||
can_remove = false;
|
can_remove = false;
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You can't remove the")
|
.append("You can't remove the")
|
||||||
.colour(item_colour(to_remove.item, &beatitudes))
|
.colour(item_colour(to_remove.item, &beatitudes))
|
||||||
.append_n(
|
.append_n(
|
||||||
|
|
@ -54,9 +63,8 @@ impl<'a> System<'a> for ItemRemoveSystem {
|
||||||
&obfuscated_names,
|
&obfuscated_names,
|
||||||
&beatitudes,
|
&beatitudes,
|
||||||
&dm,
|
&dm,
|
||||||
None,
|
None
|
||||||
)
|
).0
|
||||||
.0,
|
|
||||||
)
|
)
|
||||||
.colour(WHITE)
|
.colour(WHITE)
|
||||||
.append("!")
|
.append("!")
|
||||||
|
|
@ -70,7 +78,8 @@ impl<'a> System<'a> for ItemRemoveSystem {
|
||||||
equipped.remove(to_remove.item);
|
equipped.remove(to_remove.item);
|
||||||
if let Some(_) = names.get(to_remove.item) {
|
if let Some(_) = names.get(to_remove.item) {
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You unequip the")
|
.append("You unequip the")
|
||||||
.colour(item_colour(to_remove.item, &beatitudes))
|
.colour(item_colour(to_remove.item, &beatitudes))
|
||||||
.append_n(
|
.append_n(
|
||||||
|
|
@ -81,9 +90,8 @@ impl<'a> System<'a> for ItemRemoveSystem {
|
||||||
&obfuscated_names,
|
&obfuscated_names,
|
||||||
&beatitudes,
|
&beatitudes,
|
||||||
&dm,
|
&dm,
|
||||||
None,
|
None
|
||||||
)
|
).0
|
||||||
.0,
|
|
||||||
)
|
)
|
||||||
.colour(WHITE)
|
.colour(WHITE)
|
||||||
.period()
|
.period()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
effects::{add_effect, aoe_tiles, EffectType, Targets},
|
effects::{ add_effect, aoe_tiles, EffectType, Targets },
|
||||||
EquipmentChanged, IdentifiedItem, Map, Name, WantsToUseItem, AOE,
|
EquipmentChanged,
|
||||||
|
IdentifiedItem,
|
||||||
|
Map,
|
||||||
|
Name,
|
||||||
|
WantsToUseItem,
|
||||||
|
AOE,
|
||||||
};
|
};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -32,20 +37,16 @@ impl<'a> System<'a> for ItemUseSystem {
|
||||||
.expect("Unable to insert");
|
.expect("Unable to insert");
|
||||||
}
|
}
|
||||||
// Call the effects system
|
// Call the effects system
|
||||||
add_effect(
|
add_effect(Some(entity), EffectType::ItemUse { item: useitem.item }, match useitem.target {
|
||||||
Some(entity),
|
None => Targets::Entity { target: *player_entity },
|
||||||
EffectType::ItemUse { item: useitem.item },
|
Some(target) => {
|
||||||
match useitem.target {
|
if let Some(aoe) = aoe.get(useitem.item) {
|
||||||
None => Targets::Entity { target: *player_entity },
|
Targets::TileList { targets: aoe_tiles(&*map, target, aoe.radius) }
|
||||||
Some(target) => {
|
} else {
|
||||||
if let Some(aoe) = aoe.get(useitem.item) {
|
Targets::Tile { target: map.xy_idx(target.x, target.y) }
|
||||||
Targets::TileList { targets: aoe_tiles(&*map, target, aoe.radius) }
|
|
||||||
} else {
|
|
||||||
Targets::Tile { target: map.xy_idx(target.x, target.y) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
wants_use.clear();
|
wants_use.clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
131
src/main.rs
131
src/main.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use rltk::{GameState, Point, RandomNumberGenerator, Rltk};
|
use rltk::{ GameState, Point, RandomNumberGenerator, Rltk };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
|
use specs::saveload::{ SimpleMarker, SimpleMarkerAllocator };
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
|
|
@ -27,7 +27,7 @@ mod trigger_system;
|
||||||
use melee_combat_system::MeleeCombatSystem;
|
use melee_combat_system::MeleeCombatSystem;
|
||||||
mod inventory;
|
mod inventory;
|
||||||
mod particle_system;
|
mod particle_system;
|
||||||
use particle_system::{ParticleBuilder, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME};
|
use particle_system::{ ParticleBuilder, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME };
|
||||||
mod ai;
|
mod ai;
|
||||||
mod config;
|
mod config;
|
||||||
mod effects;
|
mod effects;
|
||||||
|
|
@ -48,23 +48,37 @@ pub const LOG_TICKS: bool = false;
|
||||||
pub enum RunState {
|
pub enum RunState {
|
||||||
AwaitingInput, // Player's turn
|
AwaitingInput, // Player's turn
|
||||||
PreRun,
|
PreRun,
|
||||||
Ticking, // Tick systems
|
Ticking, // Tick systems
|
||||||
ShowCheatMenu, // Teleport, godmode, etc. - for debugging
|
ShowCheatMenu, // Teleport, godmode, etc. - for debugging
|
||||||
ShowInventory,
|
ShowInventory,
|
||||||
ShowDropItem,
|
ShowDropItem,
|
||||||
ShowRemoveItem,
|
ShowRemoveItem,
|
||||||
ShowTargeting { range: i32, item: Entity, aoe: i32 },
|
ShowTargeting {
|
||||||
|
range: i32,
|
||||||
|
item: Entity,
|
||||||
|
aoe: i32,
|
||||||
|
},
|
||||||
ShowRemoveCurse,
|
ShowRemoveCurse,
|
||||||
ShowIdentify,
|
ShowIdentify,
|
||||||
ActionWithDirection { function: fn(i: i32, j: i32, ecs: &mut World) -> RunState },
|
ActionWithDirection {
|
||||||
MainMenu { menu_selection: gui::MainMenuSelection },
|
function: fn(i: i32, j: i32, ecs: &mut World) -> RunState,
|
||||||
CharacterCreation { ancestry: gui::Ancestry, class: gui::Class },
|
},
|
||||||
|
MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection,
|
||||||
|
},
|
||||||
|
CharacterCreation {
|
||||||
|
ancestry: gui::Ancestry,
|
||||||
|
class: gui::Class,
|
||||||
|
},
|
||||||
SaveGame,
|
SaveGame,
|
||||||
GameOver,
|
GameOver,
|
||||||
NextLevel,
|
NextLevel,
|
||||||
PreviousLevel,
|
PreviousLevel,
|
||||||
HelpScreen,
|
HelpScreen,
|
||||||
MagicMapReveal { row: i32, cursed: bool }, // Animates magic mapping effect
|
MagicMapReveal {
|
||||||
|
row: i32,
|
||||||
|
cursed: bool,
|
||||||
|
}, // Animates magic mapping effect
|
||||||
MapGeneration,
|
MapGeneration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,20 +274,30 @@ impl GameState for State {
|
||||||
self.ecs.maintain();
|
self.ecs.maintain();
|
||||||
try_spawn_interval(&mut self.ecs);
|
try_spawn_interval(&mut self.ecs);
|
||||||
match *self.ecs.fetch::<RunState>() {
|
match *self.ecs.fetch::<RunState>() {
|
||||||
RunState::AwaitingInput => new_runstate = RunState::AwaitingInput,
|
RunState::AwaitingInput => {
|
||||||
RunState::MagicMapReveal { row, cursed } => {
|
new_runstate = RunState::AwaitingInput;
|
||||||
new_runstate = RunState::MagicMapReveal { row: row, cursed: cursed }
|
}
|
||||||
|
RunState::MagicMapReveal { row, cursed } => {
|
||||||
|
new_runstate = RunState::MagicMapReveal { row: row, cursed: cursed };
|
||||||
|
}
|
||||||
|
RunState::ShowRemoveCurse => {
|
||||||
|
new_runstate = RunState::ShowRemoveCurse;
|
||||||
|
}
|
||||||
|
RunState::ShowIdentify => {
|
||||||
|
new_runstate = RunState::ShowIdentify;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
new_runstate = RunState::Ticking;
|
||||||
}
|
}
|
||||||
RunState::ShowRemoveCurse => new_runstate = RunState::ShowRemoveCurse,
|
|
||||||
RunState::ShowIdentify => new_runstate = RunState::ShowIdentify,
|
|
||||||
_ => new_runstate = RunState::Ticking,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RunState::ShowCheatMenu => {
|
RunState::ShowCheatMenu => {
|
||||||
let result = gui::show_cheat_menu(self, ctx);
|
let result = gui::show_cheat_menu(self, ctx);
|
||||||
match result {
|
match result {
|
||||||
gui::CheatMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::CheatMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::CheatMenuResult::NoResponse => {}
|
gui::CheatMenuResult::NoResponse => {}
|
||||||
gui::CheatMenuResult::Ascend => {
|
gui::CheatMenuResult::Ascend => {
|
||||||
self.goto_level(-1);
|
self.goto_level(-1);
|
||||||
|
|
@ -312,7 +336,9 @@ impl GameState for State {
|
||||||
RunState::ShowInventory => {
|
RunState::ShowInventory => {
|
||||||
let result = gui::show_inventory(self, ctx);
|
let result = gui::show_inventory(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
|
|
@ -326,10 +352,13 @@ impl GameState for State {
|
||||||
range: ranged_item.range,
|
range: ranged_item.range,
|
||||||
item: item_entity,
|
item: item_entity,
|
||||||
aoe: aoe_item.radius,
|
aoe: aoe_item.radius,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
new_runstate =
|
new_runstate = RunState::ShowTargeting {
|
||||||
RunState::ShowTargeting { range: ranged_item.range, item: item_entity, aoe: 0 }
|
range: ranged_item.range,
|
||||||
|
item: item_entity,
|
||||||
|
aoe: 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
|
|
@ -344,7 +373,9 @@ impl GameState for State {
|
||||||
RunState::ShowDropItem => {
|
RunState::ShowDropItem => {
|
||||||
let result = gui::drop_item_menu(self, ctx);
|
let result = gui::drop_item_menu(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
|
|
@ -359,7 +390,9 @@ impl GameState for State {
|
||||||
RunState::ShowRemoveItem => {
|
RunState::ShowRemoveItem => {
|
||||||
let result = gui::remove_item_menu(self, ctx);
|
let result = gui::remove_item_menu(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
|
|
@ -374,7 +407,9 @@ impl GameState for State {
|
||||||
RunState::ShowTargeting { range, item, aoe } => {
|
RunState::ShowTargeting { range, item, aoe } => {
|
||||||
let result = gui::ranged_target(self, ctx, range, aoe);
|
let result = gui::ranged_target(self, ctx, range, aoe);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
|
|
@ -388,7 +423,9 @@ impl GameState for State {
|
||||||
RunState::ShowRemoveCurse => {
|
RunState::ShowRemoveCurse => {
|
||||||
let result = gui::remove_curse(self, ctx);
|
let result = gui::remove_curse(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
|
|
@ -403,7 +440,9 @@ impl GameState for State {
|
||||||
RunState::ShowIdentify => {
|
RunState::ShowIdentify => {
|
||||||
let result = gui::identify(self, ctx);
|
let result = gui::identify(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
|
gui::ItemMenuResult::Cancel => {
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
}
|
||||||
gui::ItemMenuResult::NoResponse => {}
|
gui::ItemMenuResult::NoResponse => {}
|
||||||
gui::ItemMenuResult::Selected => {
|
gui::ItemMenuResult::Selected => {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
|
|
@ -425,31 +464,32 @@ impl GameState for State {
|
||||||
let result = gui::main_menu(self, ctx);
|
let result = gui::main_menu(self, ctx);
|
||||||
match result {
|
match result {
|
||||||
gui::MainMenuResult::NoSelection { selected } => {
|
gui::MainMenuResult::NoSelection { selected } => {
|
||||||
new_runstate = RunState::MainMenu { menu_selection: selected }
|
new_runstate = RunState::MainMenu { menu_selection: selected };
|
||||||
}
|
}
|
||||||
gui::MainMenuResult::Selected { selected } => match selected {
|
gui::MainMenuResult::Selected { selected } =>
|
||||||
gui::MainMenuSelection::NewGame => {
|
match selected {
|
||||||
new_runstate = RunState::CharacterCreation {
|
gui::MainMenuSelection::NewGame => {
|
||||||
ancestry: gui::Ancestry::Human,
|
new_runstate = RunState::CharacterCreation {
|
||||||
class: gui::Class::Fighter,
|
ancestry: gui::Ancestry::Human,
|
||||||
|
class: gui::Class::Fighter,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
gui::MainMenuSelection::LoadGame => {
|
||||||
|
saveload_system::load_game(&mut self.ecs);
|
||||||
|
new_runstate = RunState::AwaitingInput;
|
||||||
|
saveload_system::delete_save();
|
||||||
|
}
|
||||||
|
gui::MainMenuSelection::Quit => {
|
||||||
|
::std::process::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gui::MainMenuSelection::LoadGame => {
|
|
||||||
saveload_system::load_game(&mut self.ecs);
|
|
||||||
new_runstate = RunState::AwaitingInput;
|
|
||||||
saveload_system::delete_save();
|
|
||||||
}
|
|
||||||
gui::MainMenuSelection::Quit => {
|
|
||||||
::std::process::exit(0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RunState::CharacterCreation { .. } => {
|
RunState::CharacterCreation { .. } => {
|
||||||
let result = gui::character_creation(self, ctx);
|
let result = gui::character_creation(self, ctx);
|
||||||
match result {
|
match result {
|
||||||
gui::CharCreateResult::NoSelection { ancestry, class } => {
|
gui::CharCreateResult::NoSelection { ancestry, class } => {
|
||||||
new_runstate = RunState::CharacterCreation { ancestry, class }
|
new_runstate = RunState::CharacterCreation { ancestry, class };
|
||||||
}
|
}
|
||||||
gui::CharCreateResult::Selected { ancestry, class } => {
|
gui::CharCreateResult::Selected { ancestry, class } => {
|
||||||
if ancestry == gui::Ancestry::NULL {
|
if ancestry == gui::Ancestry::NULL {
|
||||||
|
|
@ -473,8 +513,9 @@ impl GameState for State {
|
||||||
gui::YesNoResult::Yes => {
|
gui::YesNoResult::Yes => {
|
||||||
self.game_over_cleanup();
|
self.game_over_cleanup();
|
||||||
new_runstate = RunState::MapGeneration;
|
new_runstate = RunState::MapGeneration;
|
||||||
self.mapgen_next_state =
|
self.mapgen_next_state = Some(RunState::MainMenu {
|
||||||
Some(RunState::MainMenu { menu_selection: gui::MainMenuSelection::NewGame });
|
menu_selection: gui::MainMenuSelection::NewGame,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -508,7 +549,7 @@ impl GameState for State {
|
||||||
if x % 2 == 0 {
|
if x % 2 == 0 {
|
||||||
idx = map.xy_idx(x as i32, row);
|
idx = map.xy_idx(x as i32, row);
|
||||||
} else {
|
} else {
|
||||||
idx = map.xy_idx(x as i32, (map.height as i32 - 1) - (row));
|
idx = map.xy_idx(x as i32, (map.height as i32) - 1 - row);
|
||||||
}
|
}
|
||||||
if !cursed {
|
if !cursed {
|
||||||
map.revealed_tiles[idx] = true;
|
map.revealed_tiles[idx] = true;
|
||||||
|
|
@ -527,7 +568,7 @@ impl GameState for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if row as usize == map.height as usize - 1 {
|
if (row as usize) == (map.height as usize) - 1 {
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
} else {
|
} else {
|
||||||
new_runstate = RunState::MagicMapReveal { row: row + 1, cursed: cursed };
|
new_runstate = RunState::MagicMapReveal { row: row + 1, cursed: cursed };
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use super::{Map, TileType};
|
use super::{ Map, TileType };
|
||||||
use crate::{gamelog, map_builders, OtherLevelPosition, Position, Telepath, Viewshed};
|
use crate::{ gamelog, map_builders, OtherLevelPosition, Position, Telepath, Viewshed };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{ HashMap, HashSet };
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct MasterDungeonMap {
|
pub struct MasterDungeonMap {
|
||||||
|
|
@ -108,18 +108,42 @@ fn make_scroll_name(rng: &mut RandomNumberGenerator) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
const POTION_COLOURS: &[&str] = &[
|
const POTION_COLOURS: &[&str] = &[
|
||||||
"red", "orange", "yellow", "green", "blue", "indigo", "violet", "black", "white", "silver", "gold", "rainbow",
|
"red",
|
||||||
"blood", "purple", "cyan", "brown", "grey", "octarine",
|
"orange",
|
||||||
|
"yellow",
|
||||||
|
"green",
|
||||||
|
"blue",
|
||||||
|
"indigo",
|
||||||
|
"violet",
|
||||||
|
"black",
|
||||||
|
"white",
|
||||||
|
"silver",
|
||||||
|
"gold",
|
||||||
|
"rainbow",
|
||||||
|
"blood",
|
||||||
|
"purple",
|
||||||
|
"cyan",
|
||||||
|
"brown",
|
||||||
|
"grey",
|
||||||
|
"octarine",
|
||||||
|
];
|
||||||
|
const POTION_ADJECTIVES: &[&str] = &[
|
||||||
|
"swirling",
|
||||||
|
"viscous",
|
||||||
|
"effervescent",
|
||||||
|
"slimy",
|
||||||
|
"oily",
|
||||||
|
"metallic",
|
||||||
|
"prismatic",
|
||||||
|
"goopy",
|
||||||
];
|
];
|
||||||
const POTION_ADJECTIVES: &[&str] =
|
|
||||||
&["swirling", "viscous", "effervescent", "slimy", "oily", "metallic", "prismatic", "goopy"];
|
|
||||||
|
|
||||||
fn make_potion_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
|
fn make_potion_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
|
||||||
loop {
|
loop {
|
||||||
let mut name: String =
|
let mut name: String =
|
||||||
POTION_ADJECTIVES[rng.roll_dice(1, POTION_ADJECTIVES.len() as i32) as usize - 1].to_string();
|
POTION_ADJECTIVES[(rng.roll_dice(1, POTION_ADJECTIVES.len() as i32) as usize) - 1].to_string();
|
||||||
name += " ";
|
name += " ";
|
||||||
name += POTION_COLOURS[rng.roll_dice(1, POTION_COLOURS.len() as i32) as usize - 1];
|
name += POTION_COLOURS[(rng.roll_dice(1, POTION_COLOURS.len() as i32) as usize) - 1];
|
||||||
name += " potion";
|
name += " potion";
|
||||||
|
|
||||||
if !used_names.contains(&name) {
|
if !used_names.contains(&name) {
|
||||||
|
|
@ -153,7 +177,7 @@ const WAND_TYPES: &[&str] = &[
|
||||||
|
|
||||||
fn make_wand_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
|
fn make_wand_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
|
||||||
loop {
|
loop {
|
||||||
let mut name: String = WAND_TYPES[rng.roll_dice(1, WAND_TYPES.len() as i32) as usize - 1].to_string();
|
let mut name: String = WAND_TYPES[(rng.roll_dice(1, WAND_TYPES.len() as i32) as usize) - 1].to_string();
|
||||||
name += " wand";
|
name += " wand";
|
||||||
|
|
||||||
if !used_names.contains(&name) {
|
if !used_names.contains(&name) {
|
||||||
|
|
@ -189,12 +213,12 @@ fn transition_to_existing_map(ecs: &mut World, new_id: i32, offset: i32) {
|
||||||
for (idx, tt) in map.tiles.iter().enumerate() {
|
for (idx, tt) in map.tiles.iter().enumerate() {
|
||||||
if *tt == stair_type {
|
if *tt == stair_type {
|
||||||
let mut player_position = ecs.write_resource::<Point>();
|
let mut player_position = ecs.write_resource::<Point>();
|
||||||
*player_position = Point::new(idx as i32 % w, idx as i32 / w);
|
*player_position = Point::new((idx as i32) % w, (idx as i32) / w);
|
||||||
let mut position_components = ecs.write_storage::<Position>();
|
let mut position_components = ecs.write_storage::<Position>();
|
||||||
let player_pos_component = position_components.get_mut(*player_entity);
|
let player_pos_component = position_components.get_mut(*player_entity);
|
||||||
if let Some(player_pos_component) = player_pos_component {
|
if let Some(player_pos_component) = player_pos_component {
|
||||||
player_pos_component.x = idx as i32 % w;
|
player_pos_component.x = (idx as i32) % w;
|
||||||
player_pos_component.y = idx as i32 / w;
|
player_pos_component.y = (idx as i32) / w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{gamelog, raws, spawner, Clock, Map, RandomNumberGenerator, TakingTurn, LOG_SPAWNING};
|
use crate::{ gamelog, raws, spawner, Clock, Map, RandomNumberGenerator, TakingTurn, LOG_SPAWNING };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
const TRY_SPAWN_CHANCE: i32 = 70;
|
const TRY_SPAWN_CHANCE: i32 = 70;
|
||||||
|
|
@ -48,7 +48,7 @@ fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) {
|
||||||
let roll = raws::get_mob_spawn_amount(&mut rng, &spawn_type, player_level);
|
let roll = raws::get_mob_spawn_amount(&mut rng, &spawn_type, player_level);
|
||||||
for _i in 0..roll {
|
for _i in 0..roll {
|
||||||
let idx = get_random_idx_from_tiles(&mut rng, &mut available_tiles);
|
let idx = get_random_idx_from_tiles(&mut rng, &mut available_tiles);
|
||||||
spawn_locations.push((idx as i32 % map.width, idx as i32 / map.width));
|
spawn_locations.push(((idx as i32) % map.width, (idx as i32) / map.width));
|
||||||
}
|
}
|
||||||
// Dropping resources for borrow-checker.
|
// Dropping resources for borrow-checker.
|
||||||
std::mem::drop(map);
|
std::mem::drop(map);
|
||||||
|
|
@ -64,7 +64,7 @@ fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) {
|
||||||
&key,
|
&key,
|
||||||
None,
|
None,
|
||||||
raws::SpawnType::AtPosition { x: idx.0, y: idx.1 },
|
raws::SpawnType::AtPosition { x: idx.0, y: idx.1 },
|
||||||
difficulty,
|
difficulty
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use rltk::{Algorithm2D, BaseMap, Point};
|
use rltk::{ Algorithm2D, BaseMap, Point };
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
pub mod colours;
|
pub mod colours;
|
||||||
mod glyphs;
|
mod glyphs;
|
||||||
mod tiletype;
|
mod tiletype;
|
||||||
pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
pub use tiletype::{ tile_cost, tile_opaque, tile_walkable, TileType };
|
||||||
mod interval_spawning_system;
|
mod interval_spawning_system;
|
||||||
pub use interval_spawning_system::try_spawn_interval;
|
pub use interval_spawning_system::try_spawn_interval;
|
||||||
pub mod dungeon;
|
pub mod dungeon;
|
||||||
pub use dungeon::{level_transition, MasterDungeonMap};
|
pub use dungeon::{ level_transition, MasterDungeonMap };
|
||||||
pub mod themes;
|
pub mod themes;
|
||||||
pub use colours::NON_VISIBLE_MULTIPLIER;
|
pub use colours::NON_VISIBLE_MULTIPLIER;
|
||||||
|
|
||||||
|
|
@ -65,9 +65,9 @@ impl Map {
|
||||||
let mut rng = rltk::RandomNumberGenerator::new();
|
let mut rng = rltk::RandomNumberGenerator::new();
|
||||||
|
|
||||||
for idx in 0..map.colour_offset.len() {
|
for idx in 0..map.colour_offset.len() {
|
||||||
let red_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
let red_roll: f32 = ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32) / 100f32 + 1.0;
|
||||||
let green_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
let green_roll: f32 = ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32) / 100f32 + 1.0;
|
||||||
let blue_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
let blue_roll: f32 = ((rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32) / 100f32 + 1.0;
|
||||||
map.colour_offset[idx] = (red_roll, green_roll, blue_roll);
|
map.colour_offset[idx] = (red_roll, green_roll, blue_roll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{colours::*, glyphs::*, Map, Point, TileType};
|
use super::{ colours::*, glyphs::*, Map, Point, TileType };
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{ Add, Mul };
|
||||||
|
|
||||||
const DARKEN_TILES_BY_DISTANCE: bool = true;
|
const DARKEN_TILES_BY_DISTANCE: bool = true;
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub fn get_tile_renderables_for_id(idx: usize, map: &Map, other_pos: Option<Poin
|
||||||
|
|
||||||
// If one of the colours was left blank, make them the same.
|
// If one of the colours was left blank, make them the same.
|
||||||
if fg == RGB::new() {
|
if fg == RGB::new() {
|
||||||
fg = bg
|
fg = bg;
|
||||||
} else if bg == RGB::new() {
|
} else if bg == RGB::new() {
|
||||||
bg = fg;
|
bg = fg;
|
||||||
}
|
}
|
||||||
|
|
@ -22,8 +22,10 @@ pub fn get_tile_renderables_for_id(idx: usize, map: &Map, other_pos: Option<Poin
|
||||||
bg = apply_bloodstain_if_necessary(bg, map, idx);
|
bg = apply_bloodstain_if_necessary(bg, map, idx);
|
||||||
(fg, bg) = darken_if_not_visible(fg, bg, map, idx);
|
(fg, bg) = darken_if_not_visible(fg, bg, map, idx);
|
||||||
if other_pos.is_some() && DARKEN_TILES_BY_DISTANCE {
|
if other_pos.is_some() && DARKEN_TILES_BY_DISTANCE {
|
||||||
let distance =
|
let distance = darken_by_distance(
|
||||||
darken_by_distance(Point::new(idx as i32 % map.width, idx as i32 / map.width), other_pos.unwrap());
|
Point::new((idx as i32) % map.width, (idx as i32) / map.width),
|
||||||
|
other_pos.unwrap()
|
||||||
|
);
|
||||||
(fg, bg) = (fg.mul(distance), bg.mul(distance));
|
(fg, bg) = (fg.mul(distance), bg.mul(distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +85,7 @@ fn is_revealed_and_wall(map: &Map, x: i32, y: i32) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
||||||
if x < 1 || x > map.width - 2 || y < 1 || y > map.height - 2 as i32 {
|
if x < 1 || x > map.width - 2 || y < 1 || y > map.height - (2 as i32) {
|
||||||
return 35;
|
return 35;
|
||||||
}
|
}
|
||||||
let mut mask: u8 = 0;
|
let mut mask: u8 = 0;
|
||||||
|
|
@ -126,16 +128,16 @@ fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
||||||
}
|
}
|
||||||
|
|
||||||
match mask {
|
match mask {
|
||||||
0 => 254, // ■ (254) square pillar; but maybe ○ (9) looks better
|
0 => 254, // ■ (254) square pillar; but maybe ○ (9) looks better
|
||||||
1 => 186, // Wall only to the north
|
1 => 186, // Wall only to the north
|
||||||
2 => 186, // Wall only to the south
|
2 => 186, // Wall only to the south
|
||||||
3 => 186, // Wall to the north and south
|
3 => 186, // Wall to the north and south
|
||||||
4 => 205, // Wall only to the west
|
4 => 205, // Wall only to the west
|
||||||
5 => 188, // Wall to the north and west
|
5 => 188, // Wall to the north and west
|
||||||
6 => 187, // Wall to the south and west
|
6 => 187, // Wall to the south and west
|
||||||
7 => 185, // Wall to the north, south and west
|
7 => 185, // Wall to the north, south and west
|
||||||
8 => 205, // Wall only to the east
|
8 => 205, // Wall only to the east
|
||||||
9 => 200, // Wall to the north and east
|
9 => 200, // Wall to the north and east
|
||||||
10 => 201, // Wall to the south and east
|
10 => 201, // Wall to the south and east
|
||||||
11 => 204, // Wall to the north, south and east
|
11 => 204, // Wall to the north, south and east
|
||||||
12 => 205, // Wall to the east and west
|
12 => 205, // Wall to the east and west
|
||||||
|
|
@ -194,7 +196,7 @@ fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
||||||
205 => 202,
|
205 => 202,
|
||||||
175 => 204,
|
175 => 204,
|
||||||
203 => 204,
|
203 => 204,
|
||||||
61 => 205, // NEW cases
|
61 => 205, // NEW cases
|
||||||
125 => 205, // NEW cases
|
125 => 205, // NEW cases
|
||||||
189 => 205, // NEW cases
|
189 => 205, // NEW cases
|
||||||
206 => 205,
|
206 => 205,
|
||||||
|
|
@ -204,7 +206,7 @@ fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
||||||
253 => 205,
|
253 => 205,
|
||||||
254 => 205,
|
254 => 205,
|
||||||
167 => 186, // NSW, NW, SW
|
167 => 186, // NSW, NW, SW
|
||||||
91 => 186, // NSE, NE, SE
|
91 => 186, // NSE, NE, SE
|
||||||
183 => 186, // NSW, NW, SW, NE
|
183 => 186, // NSW, NW, SW, NE
|
||||||
123 => 186, // NSE, NE, SE, NW
|
123 => 186, // NSE, NE, SE, NW
|
||||||
231 => 186, // NSW, NW, SW, SE
|
231 => 186, // NSW, NW, SW, SE
|
||||||
|
|
@ -215,7 +217,7 @@ fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
||||||
191 => 201, // Everything except NW
|
191 => 201, // Everything except NW
|
||||||
223 => 188, // Everything except SE
|
223 => 188, // Everything except SE
|
||||||
239 => 200, // Everything except SW
|
239 => 200, // Everything except SW
|
||||||
_ => 35, // We missed one?
|
_ => 35, // We missed one?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,8 +253,9 @@ pub fn multiply_by_float(rgb: rltk::RGB, offsets: (f32, f32, f32)) -> RGB {
|
||||||
|
|
||||||
fn darken_by_distance(pos: Point, other_pos: Point) -> f32 {
|
fn darken_by_distance(pos: Point, other_pos: Point) -> f32 {
|
||||||
let distance = DistanceAlg::Pythagoras.distance2d(pos, other_pos) as f32; // Get distance in tiles.
|
let distance = DistanceAlg::Pythagoras.distance2d(pos, other_pos) as f32; // Get distance in tiles.
|
||||||
let interp_factor = (distance - START_DARKEN_AT_N_TILES)
|
let interp_factor =
|
||||||
/ (MAX_DARKEN_AT_N_TILES * crate::config::entity::DEFAULT_VIEWSHED_STANDARD as f32 - START_DARKEN_AT_N_TILES);
|
(distance - START_DARKEN_AT_N_TILES) /
|
||||||
|
(MAX_DARKEN_AT_N_TILES * (crate::config::entity::DEFAULT_VIEWSHED_STANDARD as f32) - START_DARKEN_AT_N_TILES);
|
||||||
let interp_factor = interp_factor.max(0.0).min(1.0); // Clamp [0-1]
|
let interp_factor = interp_factor.max(0.0).min(1.0); // Clamp [0-1]
|
||||||
return 1.0 - interp_factor * (1.0 - MAX_DARKENING);
|
return 1.0 - interp_factor * (1.0 - MAX_DARKENING);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub enum TileType {
|
pub enum TileType {
|
||||||
|
|
@ -26,7 +26,7 @@ pub enum TileType {
|
||||||
|
|
||||||
pub fn tile_walkable(tt: TileType) -> bool {
|
pub fn tile_walkable(tt: TileType) -> bool {
|
||||||
match tt {
|
match tt {
|
||||||
TileType::Floor
|
| TileType::Floor
|
||||||
| TileType::WoodFloor
|
| TileType::WoodFloor
|
||||||
| TileType::Gravel
|
| TileType::Gravel
|
||||||
| TileType::Road
|
| TileType::Road
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Position};
|
use super::{ BuilderMap, MetaMapBuilder, Position };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -37,14 +37,26 @@ impl AreaStartingPosition {
|
||||||
let seed_y;
|
let seed_y;
|
||||||
|
|
||||||
match self.x {
|
match self.x {
|
||||||
XStart::LEFT => seed_x = 1,
|
XStart::LEFT => {
|
||||||
XStart::CENTRE => seed_x = build_data.map.width / 2,
|
seed_x = 1;
|
||||||
XStart::RIGHT => seed_x = build_data.map.width - 2,
|
}
|
||||||
|
XStart::CENTRE => {
|
||||||
|
seed_x = build_data.map.width / 2;
|
||||||
|
}
|
||||||
|
XStart::RIGHT => {
|
||||||
|
seed_x = build_data.map.width - 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match self.y {
|
match self.y {
|
||||||
YStart::TOP => seed_y = 1,
|
YStart::TOP => {
|
||||||
YStart::CENTRE => seed_y = build_data.map.height / 2,
|
seed_y = 1;
|
||||||
YStart::BOTTOM => seed_y = build_data.map.height - 2,
|
}
|
||||||
|
YStart::CENTRE => {
|
||||||
|
seed_y = build_data.map.height / 2;
|
||||||
|
}
|
||||||
|
YStart::BOTTOM => {
|
||||||
|
seed_y = build_data.map.height - 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||||
|
|
@ -53,8 +65,8 @@ impl AreaStartingPosition {
|
||||||
available_floors.push((
|
available_floors.push((
|
||||||
idx,
|
idx,
|
||||||
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
||||||
rltk::Point::new(idx as i32 % build_data.map.width, idx as i32 / build_data.map.width),
|
rltk::Point::new((idx as i32) % build_data.map.width, (idx as i32) / build_data.map.width),
|
||||||
rltk::Point::new(seed_x, seed_y),
|
rltk::Point::new(seed_x, seed_y)
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +77,8 @@ impl AreaStartingPosition {
|
||||||
|
|
||||||
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
|
|
||||||
let start_x = available_floors[0].0 as i32 % build_data.map.width;
|
let start_x = (available_floors[0].0 as i32) % build_data.map.width;
|
||||||
let start_y = available_floors[0].0 as i32 / build_data.map.width;
|
let start_y = (available_floors[0].0 as i32) / build_data.map.width;
|
||||||
|
|
||||||
build_data.starting_position = Some(Position { x: start_x, y: start_y });
|
build_data.starting_position = Some(Position { x: start_x, y: start_y });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, Rect, TileType};
|
use super::{ BuilderMap, InitialMapBuilder, Rect, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct BspDungeonBuilder {
|
pub struct BspDungeonBuilder {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{draw_corridor, BuilderMap, InitialMapBuilder, Rect, TileType};
|
use super::{ draw_corridor, BuilderMap, InitialMapBuilder, Rect, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
const MIN_ROOM_SIZE: i32 = 8;
|
const MIN_ROOM_SIZE: i32 = 8;
|
||||||
|
|
@ -36,7 +36,7 @@ impl BspInteriorBuilder {
|
||||||
for y in room.y1..room.y2 {
|
for y in room.y1..room.y2 {
|
||||||
for x in room.x1..room.x2 {
|
for x in room.x1..room.x2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height) - 1) as usize {
|
if idx > 0 && idx < ((build_data.map.width * build_data.map.height - 1) as usize) {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, InitialMapBuilder, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct CellularAutomataBuilder {}
|
pub struct CellularAutomataBuilder {}
|
||||||
|
|
@ -31,9 +31,9 @@ impl CellularAutomataBuilder {
|
||||||
let roll = rng.roll_dice(1, 100);
|
let roll = rng.roll_dice(1, 100);
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if roll > 55 {
|
if roll > 55 {
|
||||||
build_data.map.tiles[idx] = TileType::Floor
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
} else {
|
} else {
|
||||||
build_data.map.tiles[idx] = TileType::Wall
|
build_data.map.tiles[idx] = TileType::Wall;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -58,22 +58,22 @@ impl CellularAutomataBuilder {
|
||||||
if build_data.map.tiles[idx + 1] == TileType::Wall {
|
if build_data.map.tiles[idx + 1] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Wall {
|
if build_data.map.tiles[idx - (build_data.map.width as usize)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Wall {
|
if build_data.map.tiles[idx + (build_data.map.width as usize)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx - (build_data.map.width as usize - 1)] == TileType::Wall {
|
if build_data.map.tiles[idx - ((build_data.map.width as usize) - 1)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx - (build_data.map.width as usize + 1)] == TileType::Wall {
|
if build_data.map.tiles[idx - ((build_data.map.width as usize) + 1)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx + (build_data.map.width as usize - 1)] == TileType::Wall {
|
if build_data.map.tiles[idx + ((build_data.map.width as usize) - 1)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx + (build_data.map.width as usize + 1)] == TileType::Wall {
|
if build_data.map.tiles[idx + ((build_data.map.width as usize) + 1)] == TileType::Wall {
|
||||||
neighbors += 1;
|
neighbors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{Map, Rect, TileType};
|
use super::{ Map, Rect, TileType };
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{ max, min };
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn apply_room_to_map(map: &mut Map, room: &Rect) {
|
pub fn apply_room_to_map(map: &mut Map, room: &Rect) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct CullUnreachable {}
|
pub struct CullUnreachable {}
|
||||||
|
|
@ -25,7 +25,7 @@ impl CullUnreachable {
|
||||||
build_data.map.height as usize,
|
build_data.map.height as usize,
|
||||||
&map_starts,
|
&map_starts,
|
||||||
&build_data.map,
|
&build_data.map,
|
||||||
1000.0,
|
1000.0
|
||||||
);
|
);
|
||||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
if *tile == TileType::Floor {
|
if *tile == TileType::Floor {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct DistantExit {}
|
pub struct DistantExit {}
|
||||||
|
|
@ -25,7 +25,7 @@ impl DistantExit {
|
||||||
build_data.map.height as usize,
|
build_data.map.height as usize,
|
||||||
&map_starts,
|
&map_starts,
|
||||||
&build_data.map,
|
&build_data.map,
|
||||||
1000.0,
|
1000.0
|
||||||
);
|
);
|
||||||
let mut exit_tile = (0, 0.0f32);
|
let mut exit_tile = (0, 0.0f32);
|
||||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType};
|
use super::{ paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
|
@ -100,13 +100,16 @@ impl DLABuilder {
|
||||||
build_data.map.tiles[start_idx] = TileType::Floor;
|
build_data.map.tiles[start_idx] = TileType::Floor;
|
||||||
build_data.map.tiles[start_idx - 1] = TileType::Floor;
|
build_data.map.tiles[start_idx - 1] = TileType::Floor;
|
||||||
build_data.map.tiles[start_idx + 1] = TileType::Floor;
|
build_data.map.tiles[start_idx + 1] = TileType::Floor;
|
||||||
build_data.map.tiles[start_idx - build_data.map.width as usize] = TileType::Floor;
|
build_data.map.tiles[start_idx - (build_data.map.width as usize)] = TileType::Floor;
|
||||||
build_data.map.tiles[start_idx + build_data.map.width as usize] = TileType::Floor;
|
build_data.map.tiles[start_idx + (build_data.map.width as usize)] = TileType::Floor;
|
||||||
|
|
||||||
// Random walker
|
// Random walker
|
||||||
let total_tiles = build_data.map.width * build_data.map.height;
|
let total_tiles = build_data.map.width * build_data.map.height;
|
||||||
let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize;
|
let desired_floor_tiles = (self.floor_percent * (total_tiles as f32)) as usize;
|
||||||
let mut floor_tile_count = build_data.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
let mut floor_tile_count = build_data.map.tiles
|
||||||
|
.iter()
|
||||||
|
.filter(|a| **a == TileType::Floor)
|
||||||
|
.count();
|
||||||
while floor_tile_count < desired_floor_tiles {
|
while floor_tile_count < desired_floor_tiles {
|
||||||
match self.algorithm {
|
match self.algorithm {
|
||||||
DLAAlgorithm::WalkInwards => {
|
DLAAlgorithm::WalkInwards => {
|
||||||
|
|
@ -189,7 +192,7 @@ impl DLABuilder {
|
||||||
let mut path = rltk::line2d(
|
let mut path = rltk::line2d(
|
||||||
rltk::LineAlg::Bresenham,
|
rltk::LineAlg::Bresenham,
|
||||||
rltk::Point::new(digger_x, digger_y),
|
rltk::Point::new(digger_x, digger_y),
|
||||||
rltk::Point::new(starting_position.x, starting_position.y),
|
rltk::Point::new(starting_position.x, starting_position.y)
|
||||||
);
|
);
|
||||||
|
|
||||||
while build_data.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() {
|
while build_data.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() {
|
||||||
|
|
@ -206,7 +209,10 @@ impl DLABuilder {
|
||||||
|
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
|
||||||
floor_tile_count = build_data.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
floor_tile_count = build_data.map.tiles
|
||||||
|
.iter()
|
||||||
|
.filter(|a| **a == TileType::Floor)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct DoorPlacement {}
|
pub struct DoorPlacement {}
|
||||||
|
|
@ -45,27 +45,35 @@ impl DoorPlacement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = idx % build_data.map.width as usize;
|
let x = idx % (build_data.map.width as usize);
|
||||||
let y = idx / build_data.map.width as usize;
|
let y = idx / (build_data.map.width as usize);
|
||||||
|
|
||||||
// Check for east-west door possibility
|
// Check for east-west door possibility
|
||||||
if build_data.map.tiles[idx] == TileType::Floor
|
if
|
||||||
&& (x > 1 && build_data.map.tiles[idx - 1] == TileType::Floor)
|
build_data.map.tiles[idx] == TileType::Floor &&
|
||||||
&& (x < build_data.map.width as usize - 2 && build_data.map.tiles[idx + 1] == TileType::Floor)
|
x > 1 &&
|
||||||
&& (y > 1 && build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Wall)
|
build_data.map.tiles[idx - 1] == TileType::Floor &&
|
||||||
&& (y < build_data.map.height as usize - 2
|
x < (build_data.map.width as usize) - 2 &&
|
||||||
&& build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Wall)
|
build_data.map.tiles[idx + 1] == TileType::Floor &&
|
||||||
|
y > 1 &&
|
||||||
|
build_data.map.tiles[idx - (build_data.map.width as usize)] == TileType::Wall &&
|
||||||
|
y < (build_data.map.height as usize) - 2 &&
|
||||||
|
build_data.map.tiles[idx + (build_data.map.width as usize)] == TileType::Wall
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for north-south door possibility
|
// Check for north-south door possibility
|
||||||
if build_data.map.tiles[idx] == TileType::Floor
|
if
|
||||||
&& (x > 1 && build_data.map.tiles[idx - 1] == TileType::Wall)
|
build_data.map.tiles[idx] == TileType::Floor &&
|
||||||
&& (x < build_data.map.width as usize - 2 && build_data.map.tiles[idx + 1] == TileType::Wall)
|
x > 1 &&
|
||||||
&& (y > 1 && build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Floor)
|
build_data.map.tiles[idx - 1] == TileType::Wall &&
|
||||||
&& (y < build_data.map.height as usize - 2
|
x < (build_data.map.width as usize) - 2 &&
|
||||||
&& build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Floor)
|
build_data.map.tiles[idx + 1] == TileType::Wall &&
|
||||||
|
y > 1 &&
|
||||||
|
build_data.map.tiles[idx - (build_data.map.width as usize)] == TileType::Floor &&
|
||||||
|
y < (build_data.map.height as usize) - 2 &&
|
||||||
|
build_data.map.tiles[idx + (build_data.map.width as usize)] == TileType::Floor
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType};
|
use super::{ paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
|
@ -112,8 +112,11 @@ impl DrunkardsWalkBuilder {
|
||||||
build_data.map.tiles[start_idx] = TileType::Floor;
|
build_data.map.tiles[start_idx] = TileType::Floor;
|
||||||
|
|
||||||
let total_tiles = build_data.map.width * build_data.map.height;
|
let total_tiles = build_data.map.width * build_data.map.height;
|
||||||
let desired_floor_tiles = (self.settings.floor_percent * total_tiles as f32) as usize;
|
let desired_floor_tiles = (self.settings.floor_percent * (total_tiles as f32)) as usize;
|
||||||
let mut floor_tile_count = build_data.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
let mut floor_tile_count = build_data.map.tiles
|
||||||
|
.iter()
|
||||||
|
.filter(|a| **a == TileType::Floor)
|
||||||
|
.count();
|
||||||
let mut digger_count = 0;
|
let mut digger_count = 0;
|
||||||
while floor_tile_count < desired_floor_tiles {
|
while floor_tile_count < desired_floor_tiles {
|
||||||
let mut did_something = false;
|
let mut did_something = false;
|
||||||
|
|
@ -180,7 +183,10 @@ impl DrunkardsWalkBuilder {
|
||||||
*t = TileType::Floor;
|
*t = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
floor_tile_count = build_data.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
floor_tile_count = build_data.map.tiles
|
||||||
|
.iter()
|
||||||
|
.filter(|a| **a == TileType::Floor)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct FillEdges {
|
pub struct FillEdges {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
use super::{
|
use super::{
|
||||||
AreaStartingPosition, BuilderChain, BuilderMap, CellularAutomataBuilder, CullUnreachable, MetaMapBuilder, TileType,
|
AreaStartingPosition,
|
||||||
VoronoiSpawning, XStart, YStart,
|
BuilderChain,
|
||||||
|
BuilderMap,
|
||||||
|
CellularAutomataBuilder,
|
||||||
|
CullUnreachable,
|
||||||
|
MetaMapBuilder,
|
||||||
|
TileType,
|
||||||
|
VoronoiSpawning,
|
||||||
|
XStart,
|
||||||
|
YStart,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
|
|
||||||
|
|
@ -10,7 +18,7 @@ pub fn forest_builder(
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
difficulty: i32,
|
difficulty: i32,
|
||||||
initial_player_level: i32,
|
initial_player_level: i32
|
||||||
) -> BuilderChain {
|
) -> BuilderChain {
|
||||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the woods", initial_player_level);
|
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the woods", initial_player_level);
|
||||||
chain.start_with(CellularAutomataBuilder::new());
|
chain.start_with(CellularAutomataBuilder::new());
|
||||||
|
|
@ -44,8 +52,8 @@ impl RoadExit {
|
||||||
available_floors.push((
|
available_floors.push((
|
||||||
idx,
|
idx,
|
||||||
DistanceAlg::PythagorasSquared.distance2d(
|
DistanceAlg::PythagorasSquared.distance2d(
|
||||||
Point::new(idx as i32 % build_data.map.width, idx as i32 / build_data.map.width),
|
Point::new((idx as i32) % build_data.map.width, (idx as i32) / build_data.map.width),
|
||||||
Point::new(seed_x, seed_y),
|
Point::new(seed_x, seed_y)
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -54,8 +62,8 @@ impl RoadExit {
|
||||||
panic!("No valid floors to start on.");
|
panic!("No valid floors to start on.");
|
||||||
}
|
}
|
||||||
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
let end_x = available_floors[0].0 as i32 % build_data.map.width;
|
let end_x = (available_floors[0].0 as i32) % build_data.map.width;
|
||||||
let end_y = available_floors[0].0 as i32 / build_data.map.width;
|
let end_y = (available_floors[0].0 as i32) / build_data.map.width;
|
||||||
return (end_x, end_y);
|
return (end_x, end_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,8 +86,8 @@ impl RoadExit {
|
||||||
|
|
||||||
let path = a_star_search(start_idx, end_idx, &mut build_data.map);
|
let path = a_star_search(start_idx, end_idx, &mut build_data.map);
|
||||||
for idx in path.steps.iter() {
|
for idx in path.steps.iter() {
|
||||||
let x = *idx as i32 % build_data.map.width;
|
let x = (*idx as i32) % build_data.map.width;
|
||||||
let y = *idx as i32 / build_data.map.width;
|
let y = (*idx as i32) / build_data.map.width;
|
||||||
self.paint_road(build_data, x, y);
|
self.paint_road(build_data, x, y);
|
||||||
self.paint_road(build_data, x - 1, y);
|
self.paint_road(build_data, x - 1, y);
|
||||||
self.paint_road(build_data, x + 1, y);
|
self.paint_road(build_data, x + 1, y);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, Map, TileType};
|
use super::{ BuilderMap, InitialMapBuilder, Map, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct MazeBuilder {}
|
pub struct MazeBuilder {}
|
||||||
|
|
@ -19,7 +19,7 @@ impl MazeBuilder {
|
||||||
#[allow(clippy::map_entry)]
|
#[allow(clippy::map_entry)]
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
// Maze gen
|
// Maze gen
|
||||||
let mut maze = Grid::new((build_data.map.width / 2) - 2, (build_data.map.height / 2) - 2, rng);
|
let mut maze = Grid::new(build_data.map.width / 2 - 2, build_data.map.height / 2 - 2, rng);
|
||||||
maze.generate_maze(build_data);
|
maze.generate_maze(build_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +90,7 @@ impl<'a> Grid<'a> {
|
||||||
if row < 0 || column < 0 || column > self.width - 1 || row > self.height - 1 {
|
if row < 0 || column < 0 || column > self.width - 1 || row > self.height - 1 {
|
||||||
-1
|
-1
|
||||||
} else {
|
} else {
|
||||||
column + (row * self.width)
|
column + row * self.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,16 +178,16 @@ impl<'a> Grid<'a> {
|
||||||
|
|
||||||
map.tiles[idx] = TileType::Floor;
|
map.tiles[idx] = TileType::Floor;
|
||||||
if !cell.walls[TOP] {
|
if !cell.walls[TOP] {
|
||||||
map.tiles[idx - map.width as usize] = TileType::Floor
|
map.tiles[idx - (map.width as usize)] = TileType::Floor;
|
||||||
}
|
}
|
||||||
if !cell.walls[RIGHT] {
|
if !cell.walls[RIGHT] {
|
||||||
map.tiles[idx + 1] = TileType::Floor
|
map.tiles[idx + 1] = TileType::Floor;
|
||||||
}
|
}
|
||||||
if !cell.walls[BOTTOM] {
|
if !cell.walls[BOTTOM] {
|
||||||
map.tiles[idx + map.width as usize] = TileType::Floor
|
map.tiles[idx + (map.width as usize)] = TileType::Floor;
|
||||||
}
|
}
|
||||||
if !cell.walls[LEFT] {
|
if !cell.walls[LEFT] {
|
||||||
map.tiles[idx - 1] = TileType::Floor
|
map.tiles[idx - 1] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{spawner, Map, Position, Rect, TileType, SHOW_MAPGEN};
|
use super::{ spawner, Map, Position, Rect, TileType, SHOW_MAPGEN };
|
||||||
mod bsp_dungeon;
|
mod bsp_dungeon;
|
||||||
use bsp_dungeon::BspDungeonBuilder;
|
use bsp_dungeon::BspDungeonBuilder;
|
||||||
mod bsp_interior;
|
mod bsp_interior;
|
||||||
|
|
@ -26,7 +26,7 @@ use room_based_stairs::*;
|
||||||
mod room_based_starting_position;
|
mod room_based_starting_position;
|
||||||
use room_based_starting_position::*;
|
use room_based_starting_position::*;
|
||||||
mod area_starting_points;
|
mod area_starting_points;
|
||||||
use area_starting_points::{AreaStartingPosition, XStart, YStart};
|
use area_starting_points::{ AreaStartingPosition, XStart, YStart };
|
||||||
mod cull_unreachable;
|
mod cull_unreachable;
|
||||||
use cull_unreachable::CullUnreachable;
|
use cull_unreachable::CullUnreachable;
|
||||||
mod distant_exit;
|
mod distant_exit;
|
||||||
|
|
@ -45,7 +45,7 @@ use rooms_corridors_dogleg::DoglegCorridors;
|
||||||
mod rooms_corridors_bsp;
|
mod rooms_corridors_bsp;
|
||||||
use rooms_corridors_bsp::BspCorridors;
|
use rooms_corridors_bsp::BspCorridors;
|
||||||
mod room_sorter;
|
mod room_sorter;
|
||||||
use room_sorter::{RoomSort, RoomSorter};
|
use room_sorter::{ RoomSort, RoomSorter };
|
||||||
mod room_draw;
|
mod room_draw;
|
||||||
use room_draw::RoomDrawer;
|
use room_draw::RoomDrawer;
|
||||||
mod rooms_corridors_nearest;
|
mod rooms_corridors_nearest;
|
||||||
|
|
@ -101,7 +101,7 @@ impl BuilderChain {
|
||||||
height: i32,
|
height: i32,
|
||||||
difficulty: i32,
|
difficulty: i32,
|
||||||
name: S,
|
name: S,
|
||||||
initial_player_level: i32,
|
initial_player_level: i32
|
||||||
) -> BuilderChain {
|
) -> BuilderChain {
|
||||||
BuilderChain {
|
BuilderChain {
|
||||||
starter: None,
|
starter: None,
|
||||||
|
|
@ -122,7 +122,9 @@ impl BuilderChain {
|
||||||
|
|
||||||
pub fn start_with(&mut self, starter: Box<dyn InitialMapBuilder>) {
|
pub fn start_with(&mut self, starter: Box<dyn InitialMapBuilder>) {
|
||||||
match self.starter {
|
match self.starter {
|
||||||
None => self.starter = Some(starter),
|
None => {
|
||||||
|
self.starter = Some(starter);
|
||||||
|
}
|
||||||
Some(_) => panic!("You can only have one starting builder."),
|
Some(_) => panic!("You can only have one starting builder."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -168,17 +170,29 @@ fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YSta
|
||||||
let x;
|
let x;
|
||||||
let xroll = rng.roll_dice(1, 3);
|
let xroll = rng.roll_dice(1, 3);
|
||||||
match xroll {
|
match xroll {
|
||||||
1 => x = XStart::LEFT,
|
1 => {
|
||||||
2 => x = XStart::CENTRE,
|
x = XStart::LEFT;
|
||||||
_ => x = XStart::RIGHT,
|
}
|
||||||
|
2 => {
|
||||||
|
x = XStart::CENTRE;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
x = XStart::RIGHT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let y;
|
let y;
|
||||||
let yroll = rng.roll_dice(1, 3);
|
let yroll = rng.roll_dice(1, 3);
|
||||||
match yroll {
|
match yroll {
|
||||||
1 => y = YStart::BOTTOM,
|
1 => {
|
||||||
2 => y = YStart::CENTRE,
|
y = YStart::BOTTOM;
|
||||||
_ => y = YStart::TOP,
|
}
|
||||||
|
2 => {
|
||||||
|
y = YStart::CENTRE;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
y = YStart::TOP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(x, y)
|
(x, y)
|
||||||
|
|
@ -305,7 +319,7 @@ pub fn random_builder(
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
difficulty: i32,
|
difficulty: i32,
|
||||||
initial_player_level: i32,
|
initial_player_level: i32
|
||||||
) -> BuilderChain {
|
) -> BuilderChain {
|
||||||
rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
|
rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
|
||||||
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "the dungeon", initial_player_level);
|
let mut builder = BuilderChain::new(new_id, width, height, difficulty, "the dungeon", initial_player_level);
|
||||||
|
|
@ -313,7 +327,9 @@ pub fn random_builder(
|
||||||
let mut want_doors = true;
|
let mut want_doors = true;
|
||||||
match type_roll {
|
match type_roll {
|
||||||
1 => random_room_builder(rng, &mut builder),
|
1 => random_room_builder(rng, &mut builder),
|
||||||
_ => want_doors = random_shape_builder(rng, &mut builder),
|
_ => {
|
||||||
|
want_doors = random_shape_builder(rng, &mut builder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -354,7 +370,7 @@ pub fn level_builder(
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
initial_player_level: i32,
|
initial_player_level: i32
|
||||||
) -> BuilderChain {
|
) -> BuilderChain {
|
||||||
// TODO: With difficulty and ID/depth decoupled, this can be used for branches later.
|
// TODO: With difficulty and ID/depth decoupled, this can be used for branches later.
|
||||||
let difficulty = new_id;
|
let difficulty = new_id;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{spawner, BuilderMap, MetaMapBuilder};
|
use super::{ spawner, BuilderMap, MetaMapBuilder };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomBasedSpawner {}
|
pub struct RoomBasedSpawner {}
|
||||||
|
|
@ -23,7 +23,7 @@ impl RoomBasedSpawner {
|
||||||
rng,
|
rng,
|
||||||
room,
|
room,
|
||||||
&mut build_data.spawn_list,
|
&mut build_data.spawn_list,
|
||||||
build_data.initial_player_level,
|
build_data.initial_player_level
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomBasedStairs {}
|
pub struct RoomBasedStairs {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Position};
|
use super::{ BuilderMap, MetaMapBuilder, Position };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomBasedStartingPosition {}
|
pub struct RoomBasedStartingPosition {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Rect, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomCornerRounder {}
|
pub struct RoomCornerRounder {}
|
||||||
|
|
@ -23,13 +23,13 @@ impl RoomCornerRounder {
|
||||||
if x > 0 && build_data.map.tiles[idx - 1] == TileType::Wall {
|
if x > 0 && build_data.map.tiles[idx - 1] == TileType::Wall {
|
||||||
neighbour_walls += 1;
|
neighbour_walls += 1;
|
||||||
}
|
}
|
||||||
if y > 0 && build_data.map.tiles[idx - w as usize] == TileType::Wall {
|
if y > 0 && build_data.map.tiles[idx - (w as usize)] == TileType::Wall {
|
||||||
neighbour_walls += 1;
|
neighbour_walls += 1;
|
||||||
}
|
}
|
||||||
if x < w - 2 && build_data.map.tiles[idx + 1] == TileType::Wall {
|
if x < w - 2 && build_data.map.tiles[idx + 1] == TileType::Wall {
|
||||||
neighbour_walls += 1;
|
neighbour_walls += 1;
|
||||||
}
|
}
|
||||||
if y < h - 2 && build_data.map.tiles[idx + w as usize] == TileType::Wall {
|
if y < h - 2 && build_data.map.tiles[idx + (w as usize)] == TileType::Wall {
|
||||||
neighbour_walls += 1;
|
neighbour_walls += 1;
|
||||||
}
|
}
|
||||||
if neighbour_walls == 2 {
|
if neighbour_walls == 2 {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Rect, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomDrawer {}
|
pub struct RoomDrawer {}
|
||||||
|
|
@ -19,7 +19,7 @@ impl RoomDrawer {
|
||||||
for y in room.y1 + 1..=room.y2 {
|
for y in room.y1 + 1..=room.y2 {
|
||||||
for x in room.x1 + 1..=room.x2 {
|
for x in room.x1 + 1..=room.x2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height) - 1) as usize {
|
if idx > 0 && idx < ((build_data.map.width * build_data.map.height - 1) as usize) {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,15 +27,14 @@ impl RoomDrawer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn circle(&mut self, build_data: &mut BuilderMap, room: &Rect) {
|
fn circle(&mut self, build_data: &mut BuilderMap, room: &Rect) {
|
||||||
let radius = i32::min(room.x2 - room.x1, room.y2 - room.y1) as f32 / 2.0;
|
let radius = (i32::min(room.x2 - room.x1, room.y2 - room.y1) as f32) / 2.0;
|
||||||
let center = room.centre();
|
let center = room.centre();
|
||||||
let center_pt = rltk::Point::new(center.0, center.1);
|
let center_pt = rltk::Point::new(center.0, center.1);
|
||||||
for y in room.y1..=room.y2 {
|
for y in room.y1..=room.y2 {
|
||||||
for x in room.x1..=room.x2 {
|
for x in room.x1..=room.x2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(center_pt, rltk::Point::new(x, y));
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(center_pt, rltk::Point::new(x, y));
|
||||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height) - 1) as usize && distance <= radius
|
if idx > 0 && idx < ((build_data.map.width * build_data.map.height - 1) as usize) && distance <= radius {
|
||||||
{
|
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{paint, BuilderMap, MetaMapBuilder, Rect, Symmetry, TileType};
|
use super::{ paint, BuilderMap, MetaMapBuilder, Rect, Symmetry, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct RoomExploder {}
|
pub struct RoomExploder {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Rect};
|
use super::{ BuilderMap, MetaMapBuilder, Rect };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -29,19 +29,38 @@ impl RoomSorter {
|
||||||
|
|
||||||
fn sorter(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn sorter(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
match self.sort_by {
|
match self.sort_by {
|
||||||
RoomSort::LEFTMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| a.x1.cmp(&b.x1)),
|
RoomSort::LEFTMOST =>
|
||||||
RoomSort::RIGHTMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| b.x2.cmp(&a.x2)),
|
build_data.rooms
|
||||||
RoomSort::TOPMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| a.y1.cmp(&b.y1)),
|
.as_mut()
|
||||||
RoomSort::BOTTOMMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| b.y2.cmp(&a.y2)),
|
.unwrap()
|
||||||
|
.sort_by(|a, b| a.x1.cmp(&b.x1)),
|
||||||
|
RoomSort::RIGHTMOST =>
|
||||||
|
build_data.rooms
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.sort_by(|a, b| b.x2.cmp(&a.x2)),
|
||||||
|
RoomSort::TOPMOST =>
|
||||||
|
build_data.rooms
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.sort_by(|a, b| a.y1.cmp(&b.y1)),
|
||||||
|
RoomSort::BOTTOMMOST =>
|
||||||
|
build_data.rooms
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.sort_by(|a, b| b.y2.cmp(&a.y2)),
|
||||||
RoomSort::CENTRAL => {
|
RoomSort::CENTRAL => {
|
||||||
let map_centre = rltk::Point::new(build_data.map.width / 2, build_data.map.height / 2);
|
let map_centre = rltk::Point::new(build_data.map.width / 2, build_data.map.height / 2);
|
||||||
build_data.rooms.as_mut().unwrap().sort_by(|a: &Rect, b: &Rect| {
|
build_data.rooms
|
||||||
let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1);
|
.as_mut()
|
||||||
let b_centre_pt = rltk::Point::new(b.centre().0, b.centre().1);
|
.unwrap()
|
||||||
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(a_centre_pt, map_centre);
|
.sort_by(|a: &Rect, b: &Rect| {
|
||||||
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(b_centre_pt, map_centre);
|
let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1);
|
||||||
return distance_a.partial_cmp(&distance_b).unwrap();
|
let b_centre_pt = rltk::Point::new(b.centre().0, b.centre().1);
|
||||||
})
|
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(a_centre_pt, map_centre);
|
||||||
|
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(b_centre_pt, map_centre);
|
||||||
|
return distance_a.partial_cmp(&distance_b).unwrap();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, MetaMapBuilder, Rect, TileType};
|
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ impl BresenhamCorridors {
|
||||||
let line = rltk::line2d(
|
let line = rltk::line2d(
|
||||||
rltk::LineAlg::Bresenham,
|
rltk::LineAlg::Bresenham,
|
||||||
room_centre_pt,
|
room_centre_pt,
|
||||||
rltk::Point::new(dest_centre.0, dest_centre.1),
|
rltk::Point::new(dest_centre.0, dest_centre.1)
|
||||||
);
|
);
|
||||||
let mut corridor = Vec::new();
|
let mut corridor = Vec::new();
|
||||||
for cell in line.iter() {
|
for cell in line.iter() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{draw_corridor, BuilderMap, MetaMapBuilder, Rect};
|
use super::{ draw_corridor, BuilderMap, MetaMapBuilder, Rect };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct BspCorridors {}
|
pub struct BspCorridors {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{apply_horizontal_tunnel, apply_vertical_tunnel, BuilderMap, MetaMapBuilder, Rect};
|
use super::{ apply_horizontal_tunnel, apply_vertical_tunnel, BuilderMap, MetaMapBuilder, Rect };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct DoglegCorridors {}
|
pub struct DoglegCorridors {}
|
||||||
|
|
@ -28,7 +28,7 @@ impl DoglegCorridors {
|
||||||
for (i, room) in rooms.iter().enumerate() {
|
for (i, room) in rooms.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
let (new_x, new_y) = room.centre();
|
let (new_x, new_y) = room.centre();
|
||||||
let (prev_x, prev_y) = rooms[i as usize - 1].centre();
|
let (prev_x, prev_y) = rooms[(i as usize) - 1].centre();
|
||||||
if rng.range(0, 2) == 1 {
|
if rng.range(0, 2) == 1 {
|
||||||
let mut c1 = apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, prev_y);
|
let mut c1 = apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, prev_y);
|
||||||
let mut c2 = apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, new_x);
|
let mut c2 = apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, new_x);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{draw_corridor, BuilderMap, MetaMapBuilder, Rect};
|
use super::{ draw_corridor, BuilderMap, MetaMapBuilder, Rect };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
@ -43,8 +43,13 @@ impl NearestCorridors {
|
||||||
if !room_distance.is_empty() {
|
if !room_distance.is_empty() {
|
||||||
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||||
let dest_centre = rooms[room_distance[0].0].centre();
|
let dest_centre = rooms[room_distance[0].0].centre();
|
||||||
let corridor =
|
let corridor = draw_corridor(
|
||||||
draw_corridor(&mut build_data.map, room_centre.0, room_centre.1, dest_centre.0, dest_centre.1);
|
&mut build_data.map,
|
||||||
|
room_centre.0,
|
||||||
|
room_centre.1,
|
||||||
|
dest_centre.0,
|
||||||
|
dest_centre.1
|
||||||
|
);
|
||||||
connected.insert(i);
|
connected.insert(i);
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
corridors.push(corridor);
|
corridors.push(corridor);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{spawner, BuilderMap, MetaMapBuilder};
|
use super::{ spawner, BuilderMap, MetaMapBuilder };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct CorridorSpawner {}
|
pub struct CorridorSpawner {}
|
||||||
|
|
@ -23,7 +23,7 @@ impl CorridorSpawner {
|
||||||
rng,
|
rng,
|
||||||
&corridor,
|
&corridor,
|
||||||
&mut build_data.spawn_list,
|
&mut build_data.spawn_list,
|
||||||
build_data.initial_player_level,
|
build_data.initial_player_level
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, Rect};
|
use super::{ BuilderMap, InitialMapBuilder, Rect };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct SimpleMapBuilder {
|
pub struct SimpleMapBuilder {
|
||||||
|
|
@ -22,9 +22,9 @@ impl SimpleMapBuilder {
|
||||||
let (max_rooms, min_size, max_size);
|
let (max_rooms, min_size, max_size);
|
||||||
|
|
||||||
if let Some(room_params) = room_params {
|
if let Some(room_params) = room_params {
|
||||||
(max_rooms, min_size, max_size) = (room_params.0, room_params.1, room_params.2)
|
(max_rooms, min_size, max_size) = (room_params.0, room_params.1, room_params.2);
|
||||||
} else {
|
} else {
|
||||||
(max_rooms, min_size, max_size) = (DEFAULT_MAX_ROOMS, DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE)
|
(max_rooms, min_size, max_size) = (DEFAULT_MAX_ROOMS, DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(SimpleMapBuilder { room_params: (max_rooms, min_size, max_size) })
|
Box::new(SimpleMapBuilder { room_params: (max_rooms, min_size, max_size) })
|
||||||
|
|
@ -42,7 +42,7 @@ impl SimpleMapBuilder {
|
||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
for other_room in rooms.iter() {
|
for other_room in rooms.iter() {
|
||||||
if new_room.intersect(other_room) {
|
if new_room.intersect(other_room) {
|
||||||
ok = false
|
ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType};
|
use super::{ BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType };
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub fn town_builder(
|
pub fn town_builder(
|
||||||
|
|
@ -7,7 +7,7 @@ pub fn town_builder(
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
difficulty: i32,
|
difficulty: i32,
|
||||||
initial_player_level: i32,
|
initial_player_level: i32
|
||||||
) -> BuilderChain {
|
) -> BuilderChain {
|
||||||
rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
|
rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
|
||||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the town", initial_player_level);
|
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "the town", initial_player_level);
|
||||||
|
|
@ -78,7 +78,7 @@ impl TownBuilder {
|
||||||
building_size[2].2 = BuildingTag::Mine;
|
building_size[2].2 = BuildingTag::Mine;
|
||||||
building_size[3].2 = BuildingTag::PlayerHouse;
|
building_size[3].2 = BuildingTag::PlayerHouse;
|
||||||
for b in building_size.iter_mut().skip(4) {
|
for b in building_size.iter_mut().skip(4) {
|
||||||
b.2 = BuildingTag::NPCHouse
|
b.2 = BuildingTag::NPCHouse;
|
||||||
}
|
}
|
||||||
let last_idx = building_size.len() - 1;
|
let last_idx = building_size.len() - 1;
|
||||||
building_size[last_idx].2 = BuildingTag::Abandoned;
|
building_size[last_idx].2 = BuildingTag::Abandoned;
|
||||||
|
|
@ -91,7 +91,7 @@ impl TownBuilder {
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
buildings: &[(i32, i32, i32, i32)],
|
buildings: &[(i32, i32, i32, i32)],
|
||||||
building_index: &[(usize, i32, BuildingTag)],
|
building_index: &[(usize, i32, BuildingTag)]
|
||||||
) {
|
) {
|
||||||
for (i, building) in buildings.iter().enumerate() {
|
for (i, building) in buildings.iter().enumerate() {
|
||||||
let build_tag = &building_index[i].2;
|
let build_tag = &building_index[i].2;
|
||||||
|
|
@ -123,7 +123,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
available_building_tiles: &mut HashSet<usize>,
|
available_building_tiles: &mut HashSet<usize>
|
||||||
) {
|
) {
|
||||||
for idx in available_building_tiles.iter() {
|
for idx in available_building_tiles.iter() {
|
||||||
if rng.roll_dice(1, 40) == 1 {
|
if rng.roll_dice(1, 40) == 1 {
|
||||||
|
|
@ -161,15 +161,16 @@ impl TownBuilder {
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
to_place: &mut Vec<&str>,
|
to_place: &mut Vec<&str>,
|
||||||
avoid_tile: usize,
|
avoid_tile: usize
|
||||||
) {
|
) {
|
||||||
for y in building.1..building.1 + building.3 {
|
for y in building.1..building.1 + building.3 {
|
||||||
for x in building.0..building.0 + building.2 {
|
for x in building.0..building.0 + building.2 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if build_data.map.tiles[idx] == TileType::WoodFloor
|
if
|
||||||
&& idx != avoid_tile
|
build_data.map.tiles[idx] == TileType::WoodFloor &&
|
||||||
&& rng.roll_dice(1, 3) == 1
|
idx != avoid_tile &&
|
||||||
&& !to_place.is_empty()
|
rng.roll_dice(1, 3) == 1 &&
|
||||||
|
!to_place.is_empty()
|
||||||
{
|
{
|
||||||
let entity_tag = to_place[0];
|
let entity_tag = to_place[0];
|
||||||
to_place.remove(0);
|
to_place.remove(0);
|
||||||
|
|
@ -183,12 +184,14 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
// Place player
|
// Place player
|
||||||
build_data.starting_position =
|
build_data.starting_position = Some(Position {
|
||||||
Some(Position { x: building.0 + (building.2 / 2), y: building.1 + (building.3 / 2) });
|
x: building.0 + building.2 / 2,
|
||||||
let player_idx = build_data.map.xy_idx(building.0 + (building.2 / 2), building.1 + (building.3 / 2));
|
y: building.1 + building.3 / 2,
|
||||||
|
});
|
||||||
|
let player_idx = build_data.map.xy_idx(building.0 + building.2 / 2, building.1 + building.3 / 2);
|
||||||
|
|
||||||
// Place other items
|
// Place other items
|
||||||
let mut to_place: Vec<&str> = vec![
|
let mut to_place: Vec<&str> = vec![
|
||||||
|
|
@ -200,7 +203,7 @@ impl TownBuilder {
|
||||||
"prop_table",
|
"prop_table",
|
||||||
"prop_table",
|
"prop_table",
|
||||||
"prop_chair",
|
"prop_chair",
|
||||||
"prop_chair",
|
"prop_chair"
|
||||||
];
|
];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, player_idx);
|
self.random_building_spawn(building, build_data, rng, &mut to_place, player_idx);
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +212,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
let mut to_place: Vec<&str> = vec![
|
let mut to_place: Vec<&str> = vec![
|
||||||
"npc_priest",
|
"npc_priest",
|
||||||
|
|
@ -220,7 +223,7 @@ impl TownBuilder {
|
||||||
"prop_table",
|
"prop_table",
|
||||||
"prop_table",
|
"prop_table",
|
||||||
"prop_candle",
|
"prop_candle",
|
||||||
"prop_candle",
|
"prop_candle"
|
||||||
];
|
];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, 0)
|
self.random_building_spawn(building, build_data, rng, &mut to_place, 0)
|
||||||
}
|
}
|
||||||
|
|
@ -229,10 +232,10 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
// Place exit
|
// Place exit
|
||||||
let exit_idx = build_data.map.xy_idx(building.0 + (building.2 / 2), building.1 + (building.3 / 2));
|
let exit_idx = build_data.map.xy_idx(building.0 + building.2 / 2, building.1 + building.3 / 2);
|
||||||
build_data.map.tiles[exit_idx] = TileType::DownStair;
|
build_data.map.tiles[exit_idx] = TileType::DownStair;
|
||||||
let mut to_place: Vec<&str> = vec!["npc_miner", "npc_miner", "npc_guard", "prop_chair"];
|
let mut to_place: Vec<&str> = vec!["npc_miner", "npc_miner", "npc_guard", "prop_chair"];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, exit_idx)
|
self.random_building_spawn(building, build_data, rng, &mut to_place, exit_idx)
|
||||||
|
|
@ -242,7 +245,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
let mut to_place: Vec<&str> = vec!["prop_bed", "prop_table", "dog_little", "prop_chair", "prop_chair"];
|
let mut to_place: Vec<&str> = vec!["prop_bed", "prop_table", "dog_little", "prop_chair", "prop_chair"];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
||||||
|
|
@ -252,7 +255,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
let mut to_place: Vec<&str> = vec!["npc_townsperson", "prop_bed", "prop_table", "prop_chair"];
|
let mut to_place: Vec<&str> = vec!["npc_townsperson", "prop_bed", "prop_table", "prop_chair"];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
||||||
|
|
@ -262,7 +265,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
building: &(i32, i32, i32, i32),
|
building: &(i32, i32, i32, i32),
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator
|
||||||
) {
|
) {
|
||||||
let mut to_place: Vec<&str> = vec!["rat", "rat", "rat", "prop_table", "prop_chair"];
|
let mut to_place: Vec<&str> = vec!["rat", "rat", "rat", "prop_table", "prop_chair"];
|
||||||
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
|
||||||
|
|
@ -285,7 +288,7 @@ impl TownBuilder {
|
||||||
let sand_width = shallow_width + 4;
|
let sand_width = shallow_width + 4;
|
||||||
|
|
||||||
for y in 0..build_data.height {
|
for y in 0..build_data.height {
|
||||||
let n_water = (f32::sin(n) * variance as f32) as i32 + minimum_width + rng.roll_dice(1, 2);
|
let n_water = ((f32::sin(n) * (variance as f32)) as i32) + minimum_width + rng.roll_dice(1, 2);
|
||||||
water_width.push(n_water);
|
water_width.push(n_water);
|
||||||
n += 0.1;
|
n += 0.1;
|
||||||
for x in 0..n_water {
|
for x in 0..n_water {
|
||||||
|
|
@ -323,10 +326,10 @@ impl TownBuilder {
|
||||||
|
|
||||||
let start_roll = rng.roll_dice(1, 4);
|
let start_roll = rng.roll_dice(1, 4);
|
||||||
let largest_water_width;
|
let largest_water_width;
|
||||||
if water_width[y as usize] > water_width[y as usize + 1] {
|
if water_width[y as usize] > water_width[(y as usize) + 1] {
|
||||||
largest_water_width = water_width[y as usize];
|
largest_water_width = water_width[y as usize];
|
||||||
} else {
|
} else {
|
||||||
largest_water_width = water_width[y as usize + 1];
|
largest_water_width = water_width[(y as usize) + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make pier length
|
// Make pier length
|
||||||
|
|
@ -360,7 +363,7 @@ impl TownBuilder {
|
||||||
fn town_walls(
|
fn town_walls(
|
||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap
|
||||||
) -> (HashSet<usize>, i32) {
|
) -> (HashSet<usize>, i32) {
|
||||||
let mut available_building_tiles: HashSet<usize> = HashSet::new();
|
let mut available_building_tiles: HashSet<usize> = HashSet::new();
|
||||||
|
|
||||||
|
|
@ -370,7 +373,7 @@ impl TownBuilder {
|
||||||
const HALF_PATH_THICKNESS: i32 = 3;
|
const HALF_PATH_THICKNESS: i32 = 3;
|
||||||
|
|
||||||
let wall_gap_y =
|
let wall_gap_y =
|
||||||
(build_data.height / 2) + rng.roll_dice(1, PATH_OFFSET_FROM_CENTRE * 2) - 1 - PATH_OFFSET_FROM_CENTRE;
|
build_data.height / 2 + rng.roll_dice(1, PATH_OFFSET_FROM_CENTRE * 2) - 1 - PATH_OFFSET_FROM_CENTRE;
|
||||||
|
|
||||||
for y in BORDER..build_data.height - BORDER {
|
for y in BORDER..build_data.height - BORDER {
|
||||||
if !(y > wall_gap_y - HALF_PATH_THICKNESS && y < wall_gap_y + HALF_PATH_THICKNESS) {
|
if !(y > wall_gap_y - HALF_PATH_THICKNESS && y < wall_gap_y + HALF_PATH_THICKNESS) {
|
||||||
|
|
@ -384,14 +387,19 @@ impl TownBuilder {
|
||||||
let gravel_idx = build_data.map.xy_idx(x, y);
|
let gravel_idx = build_data.map.xy_idx(x, y);
|
||||||
let roll = rng.roll_dice(1, 6);
|
let roll = rng.roll_dice(1, 6);
|
||||||
match roll {
|
match roll {
|
||||||
1 => build_data.map.tiles[gravel_idx] = TileType::Foliage,
|
1 => {
|
||||||
2 => build_data.map.tiles[gravel_idx] = TileType::HeavyFoliage,
|
build_data.map.tiles[gravel_idx] = TileType::Foliage;
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
build_data.map.tiles[gravel_idx] = TileType::HeavyFoliage;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if y > BORDER + 1
|
if
|
||||||
&& y < build_data.height - BORDER - 1
|
y > BORDER + 1 &&
|
||||||
&& x > OFFSET_FROM_LEFT + 2
|
y < build_data.height - BORDER - 1 &&
|
||||||
&& x < build_data.width - BORDER - 1
|
x > OFFSET_FROM_LEFT + 2 &&
|
||||||
|
x < build_data.width - BORDER - 1
|
||||||
{
|
{
|
||||||
available_building_tiles.insert(gravel_idx);
|
available_building_tiles.insert(gravel_idx);
|
||||||
}
|
}
|
||||||
|
|
@ -420,7 +428,7 @@ impl TownBuilder {
|
||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
available_building_tiles: &mut HashSet<usize>,
|
available_building_tiles: &mut HashSet<usize>
|
||||||
) -> Vec<(i32, i32, i32, i32)> {
|
) -> Vec<(i32, i32, i32, i32)> {
|
||||||
let mut buildings: Vec<(i32, i32, i32, i32)> = Vec::new();
|
let mut buildings: Vec<(i32, i32, i32, i32)> = Vec::new();
|
||||||
let mut n_buildings = 0;
|
let mut n_buildings = 0;
|
||||||
|
|
@ -458,9 +466,9 @@ impl TownBuilder {
|
||||||
build_data.map.tiles[idx] = TileType::WoodFloor;
|
build_data.map.tiles[idx] = TileType::WoodFloor;
|
||||||
available_building_tiles.remove(&idx);
|
available_building_tiles.remove(&idx);
|
||||||
available_building_tiles.remove(&(idx + 1));
|
available_building_tiles.remove(&(idx + 1));
|
||||||
available_building_tiles.remove(&(idx + build_data.width as usize));
|
available_building_tiles.remove(&(idx + (build_data.width as usize)));
|
||||||
available_building_tiles.remove(&(idx - 1));
|
available_building_tiles.remove(&(idx - 1));
|
||||||
available_building_tiles.remove(&(idx - build_data.width as usize));
|
available_building_tiles.remove(&(idx - (build_data.width as usize)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
|
@ -480,10 +488,10 @@ impl TownBuilder {
|
||||||
if build_data.map.tiles[idx + 1] != TileType::WoodFloor {
|
if build_data.map.tiles[idx + 1] != TileType::WoodFloor {
|
||||||
neighbours += 1;
|
neighbours += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx - build_data.width as usize] != TileType::WoodFloor {
|
if build_data.map.tiles[idx - (build_data.width as usize)] != TileType::WoodFloor {
|
||||||
neighbours += 1;
|
neighbours += 1;
|
||||||
}
|
}
|
||||||
if build_data.map.tiles[idx + build_data.width as usize] != TileType::WoodFloor {
|
if build_data.map.tiles[idx + (build_data.width as usize)] != TileType::WoodFloor {
|
||||||
neighbours += 1;
|
neighbours += 1;
|
||||||
}
|
}
|
||||||
if neighbours > 0 {
|
if neighbours > 0 {
|
||||||
|
|
@ -503,12 +511,12 @@ impl TownBuilder {
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
build_data: &mut BuilderMap,
|
build_data: &mut BuilderMap,
|
||||||
buildings: &mut Vec<(i32, i32, i32, i32)>,
|
buildings: &mut Vec<(i32, i32, i32, i32)>,
|
||||||
wall_gap_y: i32,
|
wall_gap_y: i32
|
||||||
) -> Vec<usize> {
|
) -> Vec<usize> {
|
||||||
let mut doors = Vec::new();
|
let mut doors = Vec::new();
|
||||||
for building in buildings.iter() {
|
for building in buildings.iter() {
|
||||||
let door_x = building.0 + 1 + rng.roll_dice(1, building.2 - 3);
|
let door_x = building.0 + 1 + rng.roll_dice(1, building.2 - 3);
|
||||||
let cy = building.1 + (building.3 / 2);
|
let cy = building.1 + building.3 / 2;
|
||||||
let idx = if cy > wall_gap_y {
|
let idx = if cy > wall_gap_y {
|
||||||
// Door on north wall
|
// Door on north wall
|
||||||
build_data.map.xy_idx(door_x, building.1)
|
build_data.map.xy_idx(door_x, building.1)
|
||||||
|
|
@ -529,7 +537,7 @@ impl TownBuilder {
|
||||||
tiles: &[usize],
|
tiles: &[usize],
|
||||||
tiletype: TileType,
|
tiletype: TileType,
|
||||||
new_road_tiletype: TileType,
|
new_road_tiletype: TileType,
|
||||||
include_new_tiles: bool,
|
include_new_tiles: bool
|
||||||
) {
|
) {
|
||||||
let mut roads = self.find_tiletype(build_data, tiletype);
|
let mut roads = self.find_tiletype(build_data, tiletype);
|
||||||
|
|
||||||
|
|
@ -537,15 +545,15 @@ impl TownBuilder {
|
||||||
for tile_idx in tiles.iter() {
|
for tile_idx in tiles.iter() {
|
||||||
let mut nearest_tiletype: Vec<(usize, f32)> = Vec::new();
|
let mut nearest_tiletype: Vec<(usize, f32)> = Vec::new();
|
||||||
let tile_pt = rltk::Point::new(
|
let tile_pt = rltk::Point::new(
|
||||||
*tile_idx as i32 % build_data.map.width as i32,
|
(*tile_idx as i32) % (build_data.map.width as i32),
|
||||||
*tile_idx as i32 / build_data.map.width as i32,
|
(*tile_idx as i32) / (build_data.map.width as i32)
|
||||||
);
|
);
|
||||||
for r in roads.iter() {
|
for r in roads.iter() {
|
||||||
nearest_tiletype.push((
|
nearest_tiletype.push((
|
||||||
*r,
|
*r,
|
||||||
rltk::DistanceAlg::Manhattan.distance2d(
|
rltk::DistanceAlg::Manhattan.distance2d(
|
||||||
tile_pt,
|
tile_pt,
|
||||||
rltk::Point::new(*r as i32 % build_data.map.width, *r as i32 / build_data.map.width),
|
rltk::Point::new((*r as i32) % build_data.map.width, (*r as i32) / build_data.map.width)
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, TileType};
|
use super::{ BuilderMap, InitialMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
|
@ -55,8 +55,8 @@ impl VoronoiBuilder {
|
||||||
let mut voronoi_distance = vec![(0, 0.0f32); self.n_seeds];
|
let mut voronoi_distance = vec![(0, 0.0f32); self.n_seeds];
|
||||||
let mut voronoi_membership: Vec<i32> = vec![0; build_data.map.width as usize * build_data.map.height as usize];
|
let mut voronoi_membership: Vec<i32> = vec![0; build_data.map.width as usize * build_data.map.height as usize];
|
||||||
for (i, vid) in voronoi_membership.iter_mut().enumerate() {
|
for (i, vid) in voronoi_membership.iter_mut().enumerate() {
|
||||||
let x = i as i32 % build_data.map.width;
|
let x = (i as i32) % build_data.map.width;
|
||||||
let y = i as i32 / build_data.map.width;
|
let y = (i as i32) / build_data.map.width;
|
||||||
|
|
||||||
for (seed, pos) in voronoi_seeds.iter().enumerate() {
|
for (seed, pos) in voronoi_seeds.iter().enumerate() {
|
||||||
let distance;
|
let distance;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{spawner, BuilderMap, MetaMapBuilder, TileType};
|
use super::{ spawner, BuilderMap, MetaMapBuilder, TileType };
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ impl VoronoiSpawning {
|
||||||
rng,
|
rng,
|
||||||
area.1,
|
area.1,
|
||||||
&mut build_data.spawn_list,
|
&mut build_data.spawn_list,
|
||||||
build_data.initial_player_level,
|
build_data.initial_player_level
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,27 @@
|
||||||
use super::{
|
use super::{
|
||||||
effects::{add_effect, EffectType, Targets},
|
effects::{ add_effect, EffectType, Targets },
|
||||||
gamelog, gamesystem,
|
gamelog,
|
||||||
|
gamesystem,
|
||||||
gui::renderable_colour,
|
gui::renderable_colour,
|
||||||
ArmourClassBonus, Attributes, Blind, EquipmentSlot, Equipped, HungerClock, HungerState, MeleeWeapon, MultiAttack,
|
ArmourClassBonus,
|
||||||
Name, NaturalAttacks, ParticleBuilder, Pools, Position, Renderable, Skill, Skills, ToHitBonus, WantsToMelee,
|
Attributes,
|
||||||
|
Blind,
|
||||||
|
EquipmentSlot,
|
||||||
|
Equipped,
|
||||||
|
HungerClock,
|
||||||
|
HungerState,
|
||||||
|
MeleeWeapon,
|
||||||
|
MultiAttack,
|
||||||
|
Name,
|
||||||
|
NaturalAttacks,
|
||||||
|
ParticleBuilder,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
Renderable,
|
||||||
|
Skill,
|
||||||
|
Skills,
|
||||||
|
ToHitBonus,
|
||||||
|
WantsToMelee,
|
||||||
WeaponAttribute,
|
WeaponAttribute,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
|
|
@ -74,9 +92,14 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
let mut logger = gamelog::Logger::new();
|
let mut logger = gamelog::Logger::new();
|
||||||
let mut something_to_log = false;
|
let mut something_to_log = false;
|
||||||
|
|
||||||
for (entity, wants_melee, name, attacker_attributes, attacker_skills, attacker_pools) in
|
for (entity, wants_melee, name, attacker_attributes, attacker_skills, attacker_pools) in (
|
||||||
(&entities, &wants_melee, &names, &attributes, &skills, &pools).join()
|
&entities,
|
||||||
{
|
&wants_melee,
|
||||||
|
&names,
|
||||||
|
&attributes,
|
||||||
|
&skills,
|
||||||
|
&pools,
|
||||||
|
).join() {
|
||||||
// Create blank vector of attacks being attempted.
|
// Create blank vector of attacks being attempted.
|
||||||
let mut attacks: Vec<(MeleeWeapon, String)> = Vec::new();
|
let mut attacks: Vec<(MeleeWeapon, String)> = Vec::new();
|
||||||
let mut multi_attack = false;
|
let mut multi_attack = false;
|
||||||
|
|
@ -136,7 +159,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
let mut status_hit_bonus = 0;
|
let mut status_hit_bonus = 0;
|
||||||
if let Some(_) = blind_entities.get(entity) {
|
if let Some(_) = blind_entities.get(entity) {
|
||||||
status_hit_bonus -= 4;
|
status_hit_bonus -= 4;
|
||||||
};
|
}
|
||||||
let hc = hunger_clock.get(entity);
|
let hc = hunger_clock.get(entity);
|
||||||
if let Some(hc) = hc {
|
if let Some(hc) = hc {
|
||||||
match hc.state {
|
match hc.state {
|
||||||
|
|
@ -153,12 +176,13 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Total to-hit bonus
|
// Total to-hit bonus
|
||||||
let attacker_bonuses = 1 // +1 for being in melee combat
|
let attacker_bonuses =
|
||||||
+ attacker_pools.level // + level
|
1 + // +1 for being in melee combat
|
||||||
+ attribute_hit_bonus // +- str/dex bonus depending on weapon used
|
attacker_pools.level + // + level
|
||||||
+ skill_hit_bonus // +- relevant skill modifier
|
attribute_hit_bonus + // +- str/dex bonus depending on weapon used
|
||||||
+ equipment_hit_bonus // +- any other to-hit modifiers from equipment
|
skill_hit_bonus + // +- relevant skill modifier
|
||||||
+ status_hit_bonus; // +- any to-hit modifiers from status effects
|
equipment_hit_bonus + // +- any other to-hit modifiers from equipment
|
||||||
|
status_hit_bonus; // +- any to-hit modifiers from status effects
|
||||||
|
|
||||||
// Get armour class
|
// Get armour class
|
||||||
let bac = target_pools.bac;
|
let bac = target_pools.bac;
|
||||||
|
|
@ -187,17 +211,19 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
|
|
||||||
let target_name = names.get(wants_melee.target).unwrap();
|
let target_name = names.get(wants_melee.target).unwrap();
|
||||||
if COMBAT_LOGGING {
|
if COMBAT_LOGGING {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)",
|
format!(
|
||||||
&name.name,
|
"ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)",
|
||||||
attack_verb,
|
&name.name,
|
||||||
&target_name.name,
|
attack_verb,
|
||||||
d20,
|
&target_name.name,
|
||||||
target_number,
|
d20,
|
||||||
monster_v_player_bonus,
|
target_number,
|
||||||
armour_class_roll,
|
monster_v_player_bonus,
|
||||||
attacker_bonuses
|
armour_class_roll,
|
||||||
));
|
attacker_bonuses
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if d20 < target_number {
|
if d20 < target_number {
|
||||||
|
|
@ -206,8 +232,12 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
let skill_damage_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills);
|
let skill_damage_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills);
|
||||||
let mut attribute_damage_bonus = weapon_info.damage_bonus;
|
let mut attribute_damage_bonus = weapon_info.damage_bonus;
|
||||||
match weapon_info.attribute {
|
match weapon_info.attribute {
|
||||||
WeaponAttribute::Dexterity => attribute_damage_bonus += attacker_attributes.dexterity.bonus,
|
WeaponAttribute::Dexterity => {
|
||||||
WeaponAttribute::Strength => attribute_damage_bonus += attacker_attributes.strength.bonus,
|
attribute_damage_bonus += attacker_attributes.dexterity.bonus;
|
||||||
|
}
|
||||||
|
WeaponAttribute::Strength => {
|
||||||
|
attribute_damage_bonus += attacker_attributes.strength.bonus;
|
||||||
|
}
|
||||||
WeaponAttribute::Finesse => {
|
WeaponAttribute::Finesse => {
|
||||||
if attacker_attributes.dexterity.bonus > attacker_attributes.strength.bonus {
|
if attacker_attributes.dexterity.bonus > attacker_attributes.strength.bonus {
|
||||||
attribute_damage_bonus += attacker_attributes.dexterity.bonus;
|
attribute_damage_bonus += attacker_attributes.dexterity.bonus;
|
||||||
|
|
@ -219,37 +249,43 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
let mut damage = i32::max(0, base_damage + skill_damage_bonus + attribute_damage_bonus);
|
let mut damage = i32::max(0, base_damage + skill_damage_bonus + attribute_damage_bonus);
|
||||||
|
|
||||||
if COMBAT_LOGGING {
|
if COMBAT_LOGGING {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"ATTACKLOG: {} HIT for {} ({}[{}d{}]+{}[skill]+{}[attr])",
|
format!(
|
||||||
&name.name,
|
"ATTACKLOG: {} HIT for {} ({}[{}d{}]+{}[skill]+{}[attr])",
|
||||||
damage,
|
&name.name,
|
||||||
base_damage,
|
damage,
|
||||||
weapon_info.damage_n_dice,
|
base_damage,
|
||||||
weapon_info.damage_die_type,
|
weapon_info.damage_n_dice,
|
||||||
skill_damage_bonus,
|
weapon_info.damage_die_type,
|
||||||
attribute_damage_bonus
|
skill_damage_bonus,
|
||||||
));
|
attribute_damage_bonus
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if actual_armour_class < 0 {
|
if actual_armour_class < 0 {
|
||||||
let ac_damage_reduction = rng.roll_dice(1, -actual_armour_class);
|
let ac_damage_reduction = rng.roll_dice(1, -actual_armour_class);
|
||||||
damage = i32::min(1, damage - ac_damage_reduction);
|
damage = i32::min(1, damage - ac_damage_reduction);
|
||||||
if COMBAT_LOGGING {
|
if COMBAT_LOGGING {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"ATTACKLOG: {} reduced their damage taken by {} (1dAC), and took {} hp damage.",
|
format!(
|
||||||
&target_name.name, ac_damage_reduction, damage
|
"ATTACKLOG: {} reduced their damage taken by {} (1dAC), and took {} hp damage.",
|
||||||
));
|
&target_name.name,
|
||||||
|
ac_damage_reduction,
|
||||||
|
damage
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = positions.get(wants_melee.target);
|
let pos = positions.get(wants_melee.target);
|
||||||
if let Some(pos) = pos {
|
if let Some(pos) = pos {
|
||||||
particle_builder.damage_taken(pos.x, pos.y)
|
particle_builder.damage_taken(pos.x, pos.y);
|
||||||
}
|
}
|
||||||
add_effect(
|
add_effect(
|
||||||
Some(entity),
|
Some(entity),
|
||||||
EffectType::Damage { amount: damage },
|
EffectType::Damage { amount: damage },
|
||||||
Targets::Entity { target: wants_melee.target },
|
Targets::Entity { target: wants_melee.target }
|
||||||
);
|
);
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
something_to_log = true;
|
something_to_log = true;
|
||||||
|
|
@ -269,7 +305,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
.append(attack_verb)
|
.append(attack_verb)
|
||||||
.append("you!");
|
.append("you!");
|
||||||
} else {
|
} else {
|
||||||
gamelog::Logger::new() // <name> misses the <target>.
|
gamelog::Logger
|
||||||
|
::new() // <name> misses the <target>.
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity))
|
.colour(renderable_colour(&renderables, entity))
|
||||||
.append(&name.name)
|
.append(&name.name)
|
||||||
|
|
@ -289,7 +326,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
|
|
||||||
let pos = positions.get(wants_melee.target);
|
let pos = positions.get(wants_melee.target);
|
||||||
if let Some(pos) = pos {
|
if let Some(pos) = pos {
|
||||||
particle_builder.attack_miss(pos.x, pos.y)
|
particle_builder.attack_miss(pos.x, pos.y);
|
||||||
}
|
}
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
something_to_log = true;
|
something_to_log = true;
|
||||||
|
|
@ -304,7 +341,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
.colour(WHITE)
|
.colour(WHITE)
|
||||||
.append("misses!");
|
.append("misses!");
|
||||||
} else {
|
} else {
|
||||||
gamelog::Logger::new() // <name> misses the <target>.
|
gamelog::Logger
|
||||||
|
::new() // <name> misses the <target>.
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity))
|
.colour(renderable_colour(&renderables, entity))
|
||||||
.append(&name.name)
|
.append(&name.name)
|
||||||
|
|
@ -330,7 +368,7 @@ fn get_natural_attacks(
|
||||||
rng: &mut rltk::RandomNumberGenerator,
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
nat: NaturalAttacks,
|
nat: NaturalAttacks,
|
||||||
multi_attack: bool,
|
multi_attack: bool,
|
||||||
attacks: &mut Vec<(MeleeWeapon, String)>,
|
attacks: &mut Vec<(MeleeWeapon, String)>
|
||||||
) {
|
) {
|
||||||
if !nat.attacks.is_empty() {
|
if !nat.attacks.is_empty() {
|
||||||
if multi_attack {
|
if multi_attack {
|
||||||
|
|
@ -347,8 +385,11 @@ fn get_natural_attacks(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let attack_index =
|
let attack_index = if nat.attacks.len() == 1 {
|
||||||
if nat.attacks.len() == 1 { 0 } else { rng.roll_dice(1, nat.attacks.len() as i32) as usize - 1 };
|
0
|
||||||
|
} else {
|
||||||
|
(rng.roll_dice(1, nat.attacks.len() as i32) as usize) - 1
|
||||||
|
};
|
||||||
attacks.push((
|
attacks.push((
|
||||||
MeleeWeapon {
|
MeleeWeapon {
|
||||||
attribute: WeaponAttribute::Strength,
|
attribute: WeaponAttribute::Strength,
|
||||||
|
|
@ -367,7 +408,7 @@ fn get_weapon_attack(
|
||||||
wielded: &Equipped,
|
wielded: &Equipped,
|
||||||
melee: &MeleeWeapon,
|
melee: &MeleeWeapon,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
attacks: &mut Vec<(MeleeWeapon, String)>,
|
attacks: &mut Vec<(MeleeWeapon, String)>
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if wielded.owner == entity && wielded.slot == EquipmentSlot::Melee {
|
if wielded.owner == entity && wielded.slot == EquipmentSlot::Melee {
|
||||||
attacks.push((melee.clone(), "hits".to_string()));
|
attacks.push((melee.clone(), "hits".to_string()));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{ParticleLifetime, Position, Renderable, Rltk};
|
use super::{ ParticleLifetime, Position, Renderable, Rltk };
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
|
@ -69,7 +69,10 @@ fn create_delayed_particles(ecs: &mut World, ctx: &Rltk) {
|
||||||
let mut renderables = ecs.write_storage::<Renderable>();
|
let mut renderables = ecs.write_storage::<Renderable>();
|
||||||
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
||||||
for handled in handled_particles {
|
for handled in handled_particles {
|
||||||
let index = particle_builder.delayed_requests.iter().position(|x| x.particle == handled).unwrap();
|
let index = particle_builder.delayed_requests
|
||||||
|
.iter()
|
||||||
|
.position(|x| x.particle == handled)
|
||||||
|
.unwrap();
|
||||||
particle_builder.delayed_requests.remove(index);
|
particle_builder.delayed_requests.remove(index);
|
||||||
let p = entities.create();
|
let p = entities.create();
|
||||||
positions.insert(p, Position { x: handled.x, y: handled.y }).expect("Could not insert position");
|
positions.insert(p, Position { x: handled.x, y: handled.y }).expect("Could not insert position");
|
||||||
|
|
@ -113,8 +116,10 @@ impl ParticleBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delay(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32, delay: f32) {
|
pub fn delay(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32, delay: f32) {
|
||||||
self.delayed_requests
|
self.delayed_requests.push(DelayedParticleRequest {
|
||||||
.push(DelayedParticleRequest { delay: delay, particle: ParticleRequest { x, y, fg, bg, glyph, lifetime } });
|
delay: delay,
|
||||||
|
particle: ParticleRequest { x, y, fg, bg, glyph, lifetime },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn damage_taken(&mut self, x: i32, y: i32) {
|
pub fn damage_taken(&mut self, x: i32, y: i32) {
|
||||||
|
|
@ -124,7 +129,7 @@ impl ParticleBuilder {
|
||||||
rltk::RGB::named(rltk::ORANGE),
|
rltk::RGB::named(rltk::ORANGE),
|
||||||
rltk::RGB::named(rltk::BLACK),
|
rltk::RGB::named(rltk::BLACK),
|
||||||
rltk::to_cp437('‼'),
|
rltk::to_cp437('‼'),
|
||||||
DEFAULT_PARTICLE_LIFETIME,
|
DEFAULT_PARTICLE_LIFETIME
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +140,7 @@ impl ParticleBuilder {
|
||||||
rltk::RGB::named(rltk::CYAN),
|
rltk::RGB::named(rltk::CYAN),
|
||||||
rltk::RGB::named(rltk::BLACK),
|
rltk::RGB::named(rltk::BLACK),
|
||||||
rltk::to_cp437('‼'),
|
rltk::to_cp437('‼'),
|
||||||
DEFAULT_PARTICLE_LIFETIME,
|
DEFAULT_PARTICLE_LIFETIME
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +151,7 @@ impl ParticleBuilder {
|
||||||
rltk::RGB::named(rltk::CHOCOLATE),
|
rltk::RGB::named(rltk::CHOCOLATE),
|
||||||
rltk::RGB::named(rltk::BLACK),
|
rltk::RGB::named(rltk::BLACK),
|
||||||
rltk::to_cp437('‼'),
|
rltk::to_cp437('‼'),
|
||||||
SHORT_PARTICLE_LIFETIME,
|
SHORT_PARTICLE_LIFETIME
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +165,7 @@ impl ParticleBuilder {
|
||||||
bg: RGB,
|
bg: RGB,
|
||||||
glyph: rltk::FontCharType,
|
glyph: rltk::FontCharType,
|
||||||
lifetime: f32,
|
lifetime: f32,
|
||||||
secondary_fg: RGB,
|
secondary_fg: RGB
|
||||||
) {
|
) {
|
||||||
let eighth_l = lifetime / 8.0;
|
let eighth_l = lifetime / 8.0;
|
||||||
let quarter_l = eighth_l * 2.0;
|
let quarter_l = eighth_l * 2.0;
|
||||||
|
|
@ -231,10 +236,12 @@ impl<'a> System<'a> for ParticleSpawnSystem {
|
||||||
let p = entities.create();
|
let p = entities.create();
|
||||||
positions.insert(p, Position { x: new_particle.x, y: new_particle.y }).expect("Could not insert position");
|
positions.insert(p, Position { x: new_particle.x, y: new_particle.y }).expect("Could not insert position");
|
||||||
renderables
|
renderables
|
||||||
.insert(
|
.insert(p, Renderable {
|
||||||
p,
|
fg: new_particle.fg,
|
||||||
Renderable { fg: new_particle.fg, bg: new_particle.bg, glyph: new_particle.glyph, render_order: 0 },
|
bg: new_particle.bg,
|
||||||
)
|
glyph: new_particle.glyph,
|
||||||
|
render_order: 0,
|
||||||
|
})
|
||||||
.expect("Could not insert renderables");
|
.expect("Could not insert renderables");
|
||||||
particles
|
particles
|
||||||
.insert(p, ParticleLifetime { lifetime_ms: new_particle.lifetime })
|
.insert(p, ParticleLifetime { lifetime_ms: new_particle.lifetime })
|
||||||
|
|
|
||||||
250
src/player.rs
250
src/player.rs
|
|
@ -1,17 +1,39 @@
|
||||||
use super::{
|
use super::{
|
||||||
effects::{add_effect, EffectType, Targets},
|
effects::{ add_effect, EffectType, Targets },
|
||||||
gamelog,
|
gamelog,
|
||||||
gui::obfuscate_name_ecs,
|
gui::obfuscate_name_ecs,
|
||||||
gui::renderable_colour,
|
gui::renderable_colour,
|
||||||
raws::Reaction,
|
raws::Reaction,
|
||||||
Attributes, BlocksTile, BlocksVisibility, Door, EntityMoved, Faction, HasAncestry, Hidden, HungerClock,
|
Attributes,
|
||||||
HungerState, Item, Map, Name, ParticleBuilder, Player, Pools, Position, Renderable, RunState, State, Telepath,
|
BlocksTile,
|
||||||
TileType, Viewshed, WantsToMelee, WantsToPickupItem,
|
BlocksVisibility,
|
||||||
|
Door,
|
||||||
|
EntityMoved,
|
||||||
|
Faction,
|
||||||
|
HasAncestry,
|
||||||
|
Hidden,
|
||||||
|
HungerClock,
|
||||||
|
HungerState,
|
||||||
|
Item,
|
||||||
|
Map,
|
||||||
|
Name,
|
||||||
|
ParticleBuilder,
|
||||||
|
Player,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
Renderable,
|
||||||
|
RunState,
|
||||||
|
State,
|
||||||
|
Telepath,
|
||||||
|
TileType,
|
||||||
|
Viewshed,
|
||||||
|
WantsToMelee,
|
||||||
|
WantsToPickupItem,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use rltk::{Point, RandomNumberGenerator, Rltk, VirtualKeyCode};
|
use rltk::{ Point, RandomNumberGenerator, Rltk, VirtualKeyCode };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{ max, min };
|
||||||
|
|
||||||
pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let mut positions = ecs.write_storage::<Position>();
|
let mut positions = ecs.write_storage::<Position>();
|
||||||
|
|
@ -35,10 +57,13 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 0
|
if
|
||||||
|| pos.x + delta_x > map.width - 1
|
!(
|
||||||
|| pos.y + delta_y < 0
|
pos.x + delta_x < 0 ||
|
||||||
|| pos.y + delta_y > map.height - 1)
|
pos.x + delta_x > map.width - 1 ||
|
||||||
|
pos.y + delta_y < 0 ||
|
||||||
|
pos.y + delta_y > map.height - 1
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
||||||
|
|
@ -120,10 +145,13 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 0
|
if
|
||||||
|| pos.x + delta_x > map.width - 1
|
!(
|
||||||
|| pos.y + delta_y < 0
|
pos.x + delta_x < 0 ||
|
||||||
|| pos.y + delta_y > map.height - 1)
|
pos.x + delta_x > map.width - 1 ||
|
||||||
|
pos.y + delta_y < 0 ||
|
||||||
|
pos.y + delta_y > map.height - 1
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
||||||
|
|
@ -190,10 +218,13 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 0
|
if
|
||||||
|| pos.x + delta_x > map.width - 1
|
!(
|
||||||
|| pos.y + delta_y < 0
|
pos.x + delta_x < 0 ||
|
||||||
|| pos.y + delta_y > map.height - 1)
|
pos.x + delta_x > map.width - 1 ||
|
||||||
|
pos.y + delta_y < 0 ||
|
||||||
|
pos.y + delta_y > map.height - 1
|
||||||
|
)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
||||||
|
|
@ -224,7 +255,8 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
particle_builder.kick(pos.x + delta_x, pos.y + delta_y);
|
particle_builder.kick(pos.x + delta_x, pos.y + delta_y);
|
||||||
// ~33% chance of breaking it down + str
|
// ~33% chance of breaking it down + str
|
||||||
if rng.roll_dice(1, 10) + attributes.strength.bonus > 6 {
|
if rng.roll_dice(1, 10) + attributes.strength.bonus > 6 {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("As you kick the")
|
.append("As you kick the")
|
||||||
.item_name_n(target_name)
|
.item_name_n(target_name)
|
||||||
.append(", it crashes open!")
|
.append(", it crashes open!")
|
||||||
|
|
@ -233,16 +265,17 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
destroyed_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
destroyed_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
|
||||||
gamelog::record_event("broken_doors", 1);
|
gamelog::record_event("broken_doors", 1);
|
||||||
return false;
|
return false;
|
||||||
// 66% chance of just kicking it.
|
// 66% chance of just kicking it.
|
||||||
} else {
|
} else {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You kick the")
|
.append("You kick the")
|
||||||
.item_name_n(target_name)
|
.item_name_n(target_name)
|
||||||
.period()
|
.period()
|
||||||
.log();
|
.log();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// If the door is open and there's nothing else on the tile,
|
// If the door is open and there's nothing else on the tile,
|
||||||
} else if crate::spatial::length(destination_idx) == 1 {
|
} else if crate::spatial::length(destination_idx) == 1 {
|
||||||
// Just kick the air.
|
// Just kick the air.
|
||||||
gamelog::Logger::new().append("You kick the open air.").log();
|
gamelog::Logger::new().append("You kick the open air.").log();
|
||||||
|
|
@ -297,10 +330,11 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||||
let mut result: Option<RunState>;
|
let mut result: Option<RunState>;
|
||||||
|
|
||||||
for (entity, _player, pos, viewshed) in (&entities, &mut players, &mut positions, &mut viewsheds).join() {
|
for (entity, _player, pos, viewshed) in (&entities, &mut players, &mut positions, &mut viewsheds).join() {
|
||||||
if pos.x + delta_x < 0
|
if
|
||||||
|| pos.x + delta_x > map.width - 1
|
pos.x + delta_x < 0 ||
|
||||||
|| pos.y + delta_y < 0
|
pos.x + delta_x > map.width - 1 ||
|
||||||
|| pos.y + delta_y > map.height - 1
|
pos.y + delta_y < 0 ||
|
||||||
|
pos.y + delta_y > map.height - 1
|
||||||
{
|
{
|
||||||
return RunState::AwaitingInput;
|
return RunState::AwaitingInput;
|
||||||
}
|
}
|
||||||
|
|
@ -317,7 +351,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||||
entity,
|
entity,
|
||||||
&factions,
|
&factions,
|
||||||
&ancestries,
|
&ancestries,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
&crate::raws::RAWS.lock().unwrap()
|
||||||
);
|
);
|
||||||
if result != Reaction::Attack {
|
if result != Reaction::Attack {
|
||||||
hostile = false;
|
hostile = false;
|
||||||
|
|
@ -408,7 +442,8 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
||||||
for m in swap_entities.iter() {
|
for m in swap_entities.iter() {
|
||||||
if let Some(name) = names.get(m.0) {
|
if let Some(name) = names.get(m.0) {
|
||||||
let renderables = ecs.read_storage::<Renderable>();
|
let renderables = ecs.read_storage::<Renderable>();
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You swap places with the")
|
.append("You swap places with the")
|
||||||
.colour(renderable_colour(&renderables, m.0))
|
.colour(renderable_colour(&renderables, m.0))
|
||||||
.append_n(&name.name)
|
.append_n(&name.name)
|
||||||
|
|
@ -459,71 +494,98 @@ fn get_item(ecs: &mut World) -> RunState {
|
||||||
|
|
||||||
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => return RunState::AwaitingInput,
|
None => {
|
||||||
Some(key) => match key {
|
return RunState::AwaitingInput;
|
||||||
// Cardinals
|
}
|
||||||
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
|
Some(key) =>
|
||||||
return try_move_player(-1, 0, &mut gs.ecs)
|
match key {
|
||||||
}
|
// Cardinals
|
||||||
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
|
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
|
||||||
return try_move_player(1, 0, &mut gs.ecs);
|
return try_move_player(-1, 0, &mut gs.ecs);
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
|
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
|
||||||
return try_move_player(0, -1, &mut gs.ecs);
|
return try_move_player(1, 0, &mut gs.ecs);
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
|
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
|
||||||
return try_move_player(0, 1, &mut gs.ecs);
|
return try_move_player(0, -1, &mut gs.ecs);
|
||||||
}
|
}
|
||||||
// Diagonals
|
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
|
||||||
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => return try_move_player(1, -1, &mut gs.ecs),
|
return try_move_player(0, 1, &mut gs.ecs);
|
||||||
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => return try_move_player(-1, -1, &mut gs.ecs),
|
}
|
||||||
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => return try_move_player(1, 1, &mut gs.ecs),
|
// Diagonals
|
||||||
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => return try_move_player(-1, 1, &mut gs.ecs),
|
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => {
|
||||||
// id
|
return try_move_player(1, -1, &mut gs.ecs);
|
||||||
VirtualKeyCode::Period => {
|
}
|
||||||
if ctx.shift {
|
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => {
|
||||||
if !try_next_level(&mut gs.ecs) {
|
return try_move_player(-1, -1, &mut gs.ecs);
|
||||||
return RunState::AwaitingInput;
|
}
|
||||||
|
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => {
|
||||||
|
return try_move_player(1, 1, &mut gs.ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => {
|
||||||
|
return try_move_player(-1, 1, &mut gs.ecs);
|
||||||
|
}
|
||||||
|
// id
|
||||||
|
VirtualKeyCode::Period => {
|
||||||
|
if ctx.shift {
|
||||||
|
if !try_next_level(&mut gs.ecs) {
|
||||||
|
return RunState::AwaitingInput;
|
||||||
|
}
|
||||||
|
return RunState::NextLevel; // > to descend
|
||||||
|
} else {
|
||||||
|
return skip_turn(&mut gs.ecs); // (Wait a turn)
|
||||||
}
|
}
|
||||||
return RunState::NextLevel; // > to descend
|
|
||||||
} else {
|
|
||||||
return skip_turn(&mut gs.ecs); // (Wait a turn)
|
|
||||||
}
|
}
|
||||||
}
|
VirtualKeyCode::Comma => {
|
||||||
VirtualKeyCode::Comma => {
|
if ctx.shift {
|
||||||
if ctx.shift {
|
if !try_previous_level(&mut gs.ecs) {
|
||||||
if !try_previous_level(&mut gs.ecs) {
|
return RunState::AwaitingInput;
|
||||||
return RunState::AwaitingInput;
|
}
|
||||||
|
return RunState::PreviousLevel; // < to ascend
|
||||||
}
|
}
|
||||||
return RunState::PreviousLevel; // < to ascend
|
|
||||||
}
|
}
|
||||||
}
|
VirtualKeyCode::Slash => {
|
||||||
VirtualKeyCode::Slash => {
|
if ctx.shift {
|
||||||
if ctx.shift {
|
return RunState::HelpScreen;
|
||||||
return RunState::HelpScreen;
|
}
|
||||||
|
}
|
||||||
|
VirtualKeyCode::NumpadDecimal => {
|
||||||
|
return skip_turn(&mut gs.ecs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
VirtualKeyCode::NumpadDecimal => {
|
|
||||||
return skip_turn(&mut gs.ecs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
VirtualKeyCode::C => return RunState::ActionWithDirection { function: try_door },
|
VirtualKeyCode::C => {
|
||||||
VirtualKeyCode::O => return RunState::ActionWithDirection { function: open },
|
return RunState::ActionWithDirection { function: try_door };
|
||||||
VirtualKeyCode::F => return RunState::ActionWithDirection { function: kick },
|
}
|
||||||
VirtualKeyCode::G => {
|
VirtualKeyCode::O => {
|
||||||
return get_item(&mut gs.ecs);
|
return RunState::ActionWithDirection { function: open };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::F => {
|
||||||
|
return RunState::ActionWithDirection { function: kick };
|
||||||
|
}
|
||||||
|
VirtualKeyCode::G => {
|
||||||
|
return get_item(&mut gs.ecs);
|
||||||
|
}
|
||||||
|
VirtualKeyCode::I => {
|
||||||
|
return RunState::ShowInventory;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::D => {
|
||||||
|
return RunState::ShowDropItem;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::R => {
|
||||||
|
return RunState::ShowRemoveItem;
|
||||||
|
}
|
||||||
|
// Other
|
||||||
|
VirtualKeyCode::Minus => {
|
||||||
|
return RunState::ShowCheatMenu;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Escape => {
|
||||||
|
return RunState::SaveGame;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return RunState::AwaitingInput;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
VirtualKeyCode::I => return RunState::ShowInventory,
|
|
||||||
VirtualKeyCode::D => return RunState::ShowDropItem,
|
|
||||||
VirtualKeyCode::R => return RunState::ShowRemoveItem,
|
|
||||||
// Other
|
|
||||||
VirtualKeyCode::Minus => return RunState::ShowCheatMenu,
|
|
||||||
VirtualKeyCode::Escape => return RunState::SaveGame,
|
|
||||||
_ => {
|
|
||||||
return RunState::AwaitingInput;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return RunState::AwaitingInput;
|
return RunState::AwaitingInput;
|
||||||
}
|
}
|
||||||
|
|
@ -573,7 +635,7 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
||||||
entity_id,
|
entity_id,
|
||||||
&factions,
|
&factions,
|
||||||
&ancestries,
|
&ancestries,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
&crate::raws::RAWS.lock().unwrap()
|
||||||
);
|
);
|
||||||
if result == Reaction::Attack {
|
if result == Reaction::Attack {
|
||||||
can_heal = false;
|
can_heal = false;
|
||||||
|
|
@ -587,9 +649,15 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
||||||
let player_hunger_clock = hunger_clocks.get(*player_entity);
|
let player_hunger_clock = hunger_clocks.get(*player_entity);
|
||||||
if let Some(clock) = player_hunger_clock {
|
if let Some(clock) = player_hunger_clock {
|
||||||
match clock.state {
|
match clock.state {
|
||||||
HungerState::Hungry => can_heal = false,
|
HungerState::Hungry => {
|
||||||
HungerState::Weak => can_heal = false,
|
can_heal = false;
|
||||||
HungerState::Fainting => can_heal = false,
|
}
|
||||||
|
HungerState::Weak => {
|
||||||
|
can_heal = false;
|
||||||
|
}
|
||||||
|
HungerState::Fainting => {
|
||||||
|
can_heal = false;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -599,7 +667,7 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
||||||
let pools = health_components.get_mut(*player_entity).unwrap();
|
let pools = health_components.get_mut(*player_entity).unwrap();
|
||||||
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
|
||||||
let roll = rng.roll_dice(1, 6);
|
let roll = rng.roll_dice(1, 6);
|
||||||
if (roll == 6) && pools.hit_points.current < pools.hit_points.max {
|
if roll == 6 && pools.hit_points.current < pools.hit_points.max {
|
||||||
pools.hit_points.current += 1;
|
pools.hit_points.current += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ mod loot_table_structs;
|
||||||
use loot_table_structs::*;
|
use loot_table_structs::*;
|
||||||
mod reaction_structs;
|
mod reaction_structs;
|
||||||
pub use reaction_structs::Reaction;
|
pub use reaction_structs::Reaction;
|
||||||
use reaction_structs::{AncestryData, FactionData};
|
use reaction_structs::{ AncestryData, FactionData };
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
@ -76,6 +76,6 @@ macro_rules! impl_ParseJson {
|
||||||
return serde_json::from_str(&raw_string).expect("Failed to convert &str to json");
|
return serde_json::from_str(&raw_string).expect("Failed to convert &str to json");
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
impl_ParseJson!(for Vec<Item>, Vec<Mob>, Vec<Prop>, Vec<SpawnTable>, Vec<LootTable>, Vec<FactionData>, Vec<AncestryData>);
|
impl_ParseJson!(for Vec<Item>, Vec<Mob>, Vec<Prop>, Vec<SpawnTable>, Vec<LootTable>, Vec<FactionData>, Vec<AncestryData>);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Raws, Reaction};
|
use super::{ Raws, Reaction };
|
||||||
use crate::components::*;
|
use crate::components::*;
|
||||||
use crate::config::entity;
|
use crate::config::entity;
|
||||||
use crate::gamesystem::*;
|
use crate::gamesystem::*;
|
||||||
|
|
@ -8,8 +8,8 @@ use crate::LOG_SPAWNING;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use specs::saveload::{MarkedBuilder, SimpleMarker};
|
use specs::saveload::{ MarkedBuilder, SimpleMarker };
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{ HashMap, HashSet };
|
||||||
|
|
||||||
/// Applies effects to the entity - e.g. "healing: 1d4+1", where
|
/// Applies effects to the entity - e.g. "healing: 1d4+1", where
|
||||||
/// effects are components on the entity with varying parameters.
|
/// effects are components on the entity with varying parameters.
|
||||||
|
|
@ -103,9 +103,16 @@ macro_rules! apply_flags {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SpawnType {
|
pub enum SpawnType {
|
||||||
AtPosition { x: i32, y: i32 },
|
AtPosition {
|
||||||
Equipped { by: Entity },
|
x: i32,
|
||||||
Carried { by: Entity },
|
y: i32,
|
||||||
|
},
|
||||||
|
Equipped {
|
||||||
|
by: Entity,
|
||||||
|
},
|
||||||
|
Carried {
|
||||||
|
by: Entity,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RawMaster {
|
pub struct RawMaster {
|
||||||
|
|
@ -164,27 +171,24 @@ impl RawMaster {
|
||||||
self.table_index.insert(table.id.clone(), i);
|
self.table_index.insert(table.id.clone(), i);
|
||||||
used_names.insert(table.id.clone());
|
used_names.insert(table.id.clone());
|
||||||
for entry in table.table.iter() {
|
for entry in table.table.iter() {
|
||||||
check_for_unspecified_entity(&used_names, &entry.id)
|
check_for_unspecified_entity(&used_names, &entry.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i, loot_table) in self.raws.loot_tables.iter().enumerate() {
|
for (i, loot_table) in self.raws.loot_tables.iter().enumerate() {
|
||||||
check_for_duplicate_entries(&used_names, &loot_table.id);
|
check_for_duplicate_entries(&used_names, &loot_table.id);
|
||||||
self.loot_index.insert(loot_table.id.clone(), i);
|
self.loot_index.insert(loot_table.id.clone(), i);
|
||||||
for entry in loot_table.table.iter() {
|
for entry in loot_table.table.iter() {
|
||||||
check_for_unspecified_entity(&used_names, &entry.id)
|
check_for_unspecified_entity(&used_names, &entry.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for faction in self.raws.factions.iter() {
|
for faction in self.raws.factions.iter() {
|
||||||
let mut reactions: HashMap<String, Reaction> = HashMap::new();
|
let mut reactions: HashMap<String, Reaction> = HashMap::new();
|
||||||
for other in faction.responses.iter() {
|
for other in faction.responses.iter() {
|
||||||
reactions.insert(
|
reactions.insert(other.0.clone(), match other.1.as_str() {
|
||||||
other.0.clone(),
|
"flee" => Reaction::Flee,
|
||||||
match other.1.as_str() {
|
"attack" => Reaction::Attack,
|
||||||
"flee" => Reaction::Flee,
|
_ => Reaction::Ignore,
|
||||||
"attack" => Reaction::Attack,
|
});
|
||||||
_ => Reaction::Ignore,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
self.faction_index.insert(faction.id.clone(), reactions);
|
self.faction_index.insert(faction.id.clone(), reactions);
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +217,7 @@ pub fn spawn_named_entity(
|
||||||
key: &str,
|
key: &str,
|
||||||
buc: Option<BUC>,
|
buc: Option<BUC>,
|
||||||
pos: SpawnType,
|
pos: SpawnType,
|
||||||
map_difficulty: i32,
|
map_difficulty: i32
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
if raws.item_index.contains_key(key) {
|
if raws.item_index.contains_key(key) {
|
||||||
return spawn_named_item(raws, ecs, key, buc, pos);
|
return spawn_named_item(raws, ecs, key, buc, pos);
|
||||||
|
|
@ -230,7 +234,7 @@ pub fn spawn_named_item(
|
||||||
ecs: &mut World,
|
ecs: &mut World,
|
||||||
key: &str,
|
key: &str,
|
||||||
buc: Option<BUC>,
|
buc: Option<BUC>,
|
||||||
pos: SpawnType,
|
pos: SpawnType
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
if raws.item_index.contains_key(key) {
|
if raws.item_index.contains_key(key) {
|
||||||
let item_template = &raws.raws.items[raws.item_index[key]];
|
let item_template = &raws.raws.items[raws.item_index[key]];
|
||||||
|
|
@ -245,18 +249,10 @@ pub fn spawn_named_item(
|
||||||
let player_entity = ecs.fetch::<Entity>();
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
let known_beatitude = match pos {
|
let known_beatitude = match pos {
|
||||||
SpawnType::Equipped { by } => {
|
SpawnType::Equipped { by } => {
|
||||||
if by == *player_entity {
|
if by == *player_entity { true } else { false }
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SpawnType::Carried { by } => {
|
SpawnType::Carried { by } => {
|
||||||
if by == *player_entity {
|
if by == *player_entity { true } else { false }
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
@ -310,25 +306,25 @@ pub fn spawn_named_item(
|
||||||
let singular = scroll_names[&item_template.name.name].clone();
|
let singular = scroll_names[&item_template.name.name].clone();
|
||||||
let mut plural = singular.clone();
|
let mut plural = singular.clone();
|
||||||
plural += "s";
|
plural += "s";
|
||||||
eb = eb.with(ObfuscatedName { name: singular, plural: plural })
|
eb = eb.with(ObfuscatedName { name: singular, plural: plural });
|
||||||
}
|
}
|
||||||
"potion" => {
|
"potion" => {
|
||||||
let singular = potion_names[&item_template.name.name].clone();
|
let singular = potion_names[&item_template.name.name].clone();
|
||||||
let mut plural = singular.clone();
|
let mut plural = singular.clone();
|
||||||
plural += "s";
|
plural += "s";
|
||||||
eb = eb.with(ObfuscatedName { name: singular, plural: plural })
|
eb = eb.with(ObfuscatedName { name: singular, plural: plural });
|
||||||
}
|
}
|
||||||
"wand" => {
|
"wand" => {
|
||||||
let singular = wand_names[&item_template.name.name].clone();
|
let singular = wand_names[&item_template.name.name].clone();
|
||||||
let mut plural = singular.clone();
|
let mut plural = singular.clone();
|
||||||
plural += "s";
|
plural += "s";
|
||||||
eb = eb.with(ObfuscatedName { name: singular, plural: plural })
|
eb = eb.with(ObfuscatedName { name: singular, plural: plural });
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let singular = magic_item.naming.clone();
|
let singular = magic_item.naming.clone();
|
||||||
let mut plural = singular.clone();
|
let mut plural = singular.clone();
|
||||||
plural += "s";
|
plural += "s";
|
||||||
eb = eb.with(ObfuscatedName { name: singular, plural: plural })
|
eb = eb.with(ObfuscatedName { name: singular, plural: plural });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -362,7 +358,7 @@ pub fn spawn_named_mob(
|
||||||
ecs: &mut World,
|
ecs: &mut World,
|
||||||
key: &str,
|
key: &str,
|
||||||
pos: SpawnType,
|
pos: SpawnType,
|
||||||
map_difficulty: i32,
|
map_difficulty: i32
|
||||||
) -> Option<Entity> {
|
) -> Option<Entity> {
|
||||||
if raws.mob_index.contains_key(key) {
|
if raws.mob_index.contains_key(key) {
|
||||||
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
let mob_template = &raws.raws.mobs[raws.mob_index[key]];
|
||||||
|
|
@ -462,7 +458,7 @@ pub fn spawn_named_mob(
|
||||||
mob_level += (player_level - base_mob_level) / 4;
|
mob_level += (player_level - base_mob_level) / 4;
|
||||||
}
|
}
|
||||||
// If the resulting mob level is more than 1.5x the base, lower it to that number
|
// If the resulting mob level is more than 1.5x the base, lower it to that number
|
||||||
mob_level = i32::min(mob_level, (1.5 * base_mob_level as f32).trunc() as i32);
|
mob_level = i32::min(mob_level, (1.5 * (base_mob_level as f32)).trunc() as i32);
|
||||||
|
|
||||||
// Should really use existing RNG here
|
// Should really use existing RNG here
|
||||||
let mut rng = rltk::RandomNumberGenerator::new();
|
let mut rng = rltk::RandomNumberGenerator::new();
|
||||||
|
|
@ -549,10 +545,20 @@ pub fn spawn_named_mob(
|
||||||
}
|
}
|
||||||
|
|
||||||
if LOG_SPAWNING {
|
if LOG_SPAWNING {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"SPAWNLOG: {} ({}HP, {}MANA, {}BAC) spawned at level {} ({}[base], {}[map difficulty], {}[player level]), worth {} XP",
|
format!(
|
||||||
&mob_template.name, mob_hp, mob_mana, mob_bac, mob_level, base_mob_level, map_difficulty, player_level, xp_value
|
"SPAWNLOG: {} ({}HP, {}MANA, {}BAC) spawned at level {} ({}[base], {}[map difficulty], {}[player level]), worth {} XP",
|
||||||
));
|
&mob_template.name,
|
||||||
|
mob_hp,
|
||||||
|
mob_mana,
|
||||||
|
mob_bac,
|
||||||
|
mob_level,
|
||||||
|
base_mob_level,
|
||||||
|
map_difficulty,
|
||||||
|
player_level,
|
||||||
|
xp_value
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_mob = eb.build();
|
let new_mob = eb.build();
|
||||||
|
|
@ -605,11 +611,15 @@ fn spawn_position<'a>(pos: SpawnType, new_entity: EntityBuilder<'a>, tag: &str,
|
||||||
let mut eb = new_entity;
|
let mut eb = new_entity;
|
||||||
|
|
||||||
match pos {
|
match pos {
|
||||||
SpawnType::AtPosition { x, y } => eb = eb.with(Position { x, y }),
|
SpawnType::AtPosition { x, y } => {
|
||||||
SpawnType::Carried { by } => eb = eb.with(InBackpack { owner: by }),
|
eb = eb.with(Position { x, y });
|
||||||
|
}
|
||||||
|
SpawnType::Carried { by } => {
|
||||||
|
eb = eb.with(InBackpack { owner: by });
|
||||||
|
}
|
||||||
SpawnType::Equipped { by } => {
|
SpawnType::Equipped { by } => {
|
||||||
let slot = find_slot_for_equippable_item(tag, raws);
|
let slot = find_slot_for_equippable_item(tag, raws);
|
||||||
eb = eb.with(Equipped { owner: by, slot })
|
eb = eb.with(Equipped { owner: by, slot });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,8 +651,7 @@ pub fn table_by_name(raws: &RawMaster, key: &str, optional_difficulty: Option<i3
|
||||||
|
|
||||||
use super::SpawnTableEntry;
|
use super::SpawnTableEntry;
|
||||||
|
|
||||||
let available_options: Vec<&SpawnTableEntry> = spawn_table
|
let available_options: Vec<&SpawnTableEntry> = spawn_table.table
|
||||||
.table
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|entry| entry.difficulty >= lower_bound && entry.difficulty <= upper_bound)
|
.filter(|entry| entry.difficulty >= lower_bound && entry.difficulty <= upper_bound)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -656,10 +665,15 @@ pub fn table_by_name(raws: &RawMaster, key: &str, optional_difficulty: Option<i3
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rltk::console::log(format!(
|
rltk::console::log(
|
||||||
"DEBUGINFO: Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}]. Returned debug entry.",
|
format!(
|
||||||
key, difficulty, upper_bound, lower_bound
|
"DEBUGINFO: Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}]. Returned debug entry.",
|
||||||
));
|
key,
|
||||||
|
difficulty,
|
||||||
|
upper_bound,
|
||||||
|
lower_bound
|
||||||
|
)
|
||||||
|
);
|
||||||
return RandomTable::new().add("debug", 1);
|
return RandomTable::new().add("debug", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -693,14 +707,30 @@ fn find_slot_for_equippable_item(tag: &str, raws: &RawMaster) -> EquipmentSlot {
|
||||||
if let Some(flags) = &item.flags {
|
if let Some(flags) = &item.flags {
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
match flag.as_str() {
|
match flag.as_str() {
|
||||||
"EQUIP_MELEE" => return EquipmentSlot::Melee,
|
"EQUIP_MELEE" => {
|
||||||
"EQUIP_SHIELD" => return EquipmentSlot::Shield,
|
return EquipmentSlot::Melee;
|
||||||
"EQUIP_BODY" => return EquipmentSlot::Body,
|
}
|
||||||
"EQUIP_HEAD" => return EquipmentSlot::Head,
|
"EQUIP_SHIELD" => {
|
||||||
"EQUIP_FEET" => return EquipmentSlot::Feet,
|
return EquipmentSlot::Shield;
|
||||||
"EQUIP_NECK" => return EquipmentSlot::Neck,
|
}
|
||||||
"EQUIP_BACK" => return EquipmentSlot::Back,
|
"EQUIP_BODY" => {
|
||||||
"EQUIP_HANDS" => return EquipmentSlot::Hands,
|
return EquipmentSlot::Body;
|
||||||
|
}
|
||||||
|
"EQUIP_HEAD" => {
|
||||||
|
return EquipmentSlot::Head;
|
||||||
|
}
|
||||||
|
"EQUIP_FEET" => {
|
||||||
|
return EquipmentSlot::Feet;
|
||||||
|
}
|
||||||
|
"EQUIP_NECK" => {
|
||||||
|
return EquipmentSlot::Neck;
|
||||||
|
}
|
||||||
|
"EQUIP_BACK" => {
|
||||||
|
return EquipmentSlot::Back;
|
||||||
|
}
|
||||||
|
"EQUIP_HANDS" => {
|
||||||
|
return EquipmentSlot::Hands;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -745,8 +775,12 @@ pub fn get_mob_spawn_type(raws: &RawMaster, key: &str) -> SpawnsAs {
|
||||||
if let Some(flags) = &mob_template.flags {
|
if let Some(flags) = &mob_template.flags {
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
match flag.as_str() {
|
match flag.as_str() {
|
||||||
"SMALL_GROUP" => return SpawnsAs::SmallGroup,
|
"SMALL_GROUP" => {
|
||||||
"LARGE_GROUP" => return SpawnsAs::LargeGroup,
|
return SpawnsAs::SmallGroup;
|
||||||
|
}
|
||||||
|
"LARGE_GROUP" => {
|
||||||
|
return SpawnsAs::LargeGroup;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -761,29 +795,27 @@ pub fn get_mob_spawn_amount(rng: &mut RandomNumberGenerator, spawn_type: &Spawns
|
||||||
SpawnsAs::Single => 1,
|
SpawnsAs::Single => 1,
|
||||||
// Small groups either spawn alone or as a small group (2-4).
|
// Small groups either spawn alone or as a small group (2-4).
|
||||||
SpawnsAs::SmallGroup => {
|
SpawnsAs::SmallGroup => {
|
||||||
if rng.roll_dice(1, 2) == 1 {
|
if rng.roll_dice(1, 2) == 1 { 1 } else { 4 }
|
||||||
1
|
|
||||||
} else {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Large groups either spawn in a small group or as a large group (2-11).
|
// Large groups either spawn in a small group or as a large group (2-11).
|
||||||
SpawnsAs::LargeGroup => {
|
SpawnsAs::LargeGroup => {
|
||||||
if rng.roll_dice(1, 2) == 1 {
|
if rng.roll_dice(1, 2) == 1 { 4 } else { 11 }
|
||||||
4
|
|
||||||
} else {
|
|
||||||
11
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let roll = if n == 1 { 1 } else { rng.roll_dice(2, n) };
|
let roll = if n == 1 { 1 } else { rng.roll_dice(2, n) };
|
||||||
// We want to constrain group sizes depending on player's level, so
|
// We want to constrain group sizes depending on player's level, so
|
||||||
// we don't get large groups of mobs when the player is unequipped.
|
// we don't get large groups of mobs when the player is unequipped.
|
||||||
match player_level {
|
match player_level {
|
||||||
0..=2 => return i32::max(1, roll / 4),
|
0..=2 => {
|
||||||
3..=4 => return i32::max(1, roll / 2),
|
return i32::max(1, roll / 4);
|
||||||
_ => return roll,
|
}
|
||||||
};
|
3..=4 => {
|
||||||
|
return i32::max(1, roll / 2);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return roll;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scroll_tags() -> Vec<String> {
|
pub fn get_scroll_tags() -> Vec<String> {
|
||||||
|
|
@ -879,7 +911,7 @@ pub fn get_reactions(
|
||||||
other_entity: Entity,
|
other_entity: Entity,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
ancestries: &ReadStorage<HasAncestry>,
|
ancestries: &ReadStorage<HasAncestry>,
|
||||||
raws: &RawMaster,
|
raws: &RawMaster
|
||||||
) -> Reaction {
|
) -> Reaction {
|
||||||
if let Some(this_ancestry) = ancestries.get(this_entity) {
|
if let Some(this_ancestry) = ancestries.get(this_entity) {
|
||||||
if let Some(other_ancestry) = ancestries.get(other_entity) {
|
if let Some(other_ancestry) = ancestries.get(other_entity) {
|
||||||
|
|
@ -899,12 +931,24 @@ pub fn get_reactions(
|
||||||
|
|
||||||
fn get_ancestry_string(ancestry: Ancestry) -> &'static str {
|
fn get_ancestry_string(ancestry: Ancestry) -> &'static str {
|
||||||
match ancestry {
|
match ancestry {
|
||||||
Ancestry::Human => return "human",
|
Ancestry::Human => {
|
||||||
Ancestry::Elf => return "elf",
|
return "human";
|
||||||
Ancestry::Dwarf => return "dwarf",
|
}
|
||||||
Ancestry::Catfolk => return "catfolk",
|
Ancestry::Elf => {
|
||||||
Ancestry::Gnome => return "gnome",
|
return "elf";
|
||||||
Ancestry::NULL => return "NULL",
|
}
|
||||||
|
Ancestry::Dwarf => {
|
||||||
|
return "dwarf";
|
||||||
|
}
|
||||||
|
Ancestry::Catfolk => {
|
||||||
|
return "catfolk";
|
||||||
|
}
|
||||||
|
Ancestry::Gnome => {
|
||||||
|
return "gnome";
|
||||||
|
}
|
||||||
|
Ancestry::NULL => {
|
||||||
|
return "NULL";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{ HashMap, HashSet };
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct FactionData {
|
pub struct FactionData {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{ Deserialize, Serialize };
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
use super::components::*;
|
use super::components::*;
|
||||||
use specs::error::NoError;
|
use specs::error::NoError;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use specs::saveload::{DeserializeComponents, MarkedBuilder, SerializeComponents, SimpleMarker, SimpleMarkerAllocator};
|
use specs::saveload::{ DeserializeComponents, MarkedBuilder, SerializeComponents, SimpleMarker, SimpleMarkerAllocator };
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
macro_rules! serialize_individually {
|
macro_rules! serialize_individually {
|
||||||
($ecs:expr, $ser:expr, $data:expr, $( $type:ty),*) => {
|
($ecs:expr, $ser:expr, $data:expr, $($type:ty),*) => {
|
||||||
$(
|
$(
|
||||||
SerializeComponents::<NoError, SimpleMarker<SerializeMe>>::serialize(
|
SerializeComponents::<NoError, SimpleMarker<SerializeMe>>::serialize(
|
||||||
&( $ecs.read_storage::<$type>(), ),
|
&( $ecs.read_storage::<$type>(), ),
|
||||||
|
|
@ -28,8 +28,11 @@ pub fn save_game(ecs: &mut World) {
|
||||||
// Create helper
|
// Create helper
|
||||||
let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
|
let mapcopy = ecs.get_mut::<super::map::Map>().unwrap().clone();
|
||||||
let dungeon_master = ecs.get_mut::<super::map::MasterDungeonMap>().unwrap().clone();
|
let dungeon_master = ecs.get_mut::<super::map::MasterDungeonMap>().unwrap().clone();
|
||||||
let savehelper =
|
let savehelper = ecs
|
||||||
ecs.create_entity().with(SerializationHelper { map: mapcopy }).marked::<SimpleMarker<SerializeMe>>().build();
|
.create_entity()
|
||||||
|
.with(SerializationHelper { map: mapcopy })
|
||||||
|
.marked::<SimpleMarker<SerializeMe>>()
|
||||||
|
.build();
|
||||||
let savehelper2 = ecs
|
let savehelper2 = ecs
|
||||||
.create_entity()
|
.create_entity()
|
||||||
.with(DMSerializationHelper {
|
.with(DMSerializationHelper {
|
||||||
|
|
@ -138,7 +141,7 @@ pub fn does_save_exist() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! deserialize_individually {
|
macro_rules! deserialize_individually {
|
||||||
($ecs:expr, $de:expr, $data:expr, $( $type:ty),*) => {
|
($ecs:expr, $de:expr, $data:expr, $($type:ty),*) => {
|
||||||
$(
|
$(
|
||||||
DeserializeComponents::<NoError, _>::deserialize(
|
DeserializeComponents::<NoError, _>::deserialize(
|
||||||
&mut ( &mut $ecs.write_storage::<$type>(), ),
|
&mut ( &mut $ecs.write_storage::<$type>(), ),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{spatial, BlocksTile, Map, Pools, Position};
|
use crate::{ spatial, BlocksTile, Map, Pools, Position };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct MapIndexingSystem {}
|
pub struct MapIndexingSystem {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{tile_walkable, Map, RunState};
|
use crate::{ tile_walkable, Map, RunState };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
|
@ -94,10 +94,7 @@ pub fn is_blocked(idx: usize) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls a function on every entity within a given tile idx.
|
/// Calls a function on every entity within a given tile idx.
|
||||||
pub fn for_each_tile_content<F>(idx: usize, mut f: F)
|
pub fn for_each_tile_content<F>(idx: usize, mut f: F) where F: FnMut(Entity) {
|
||||||
where
|
|
||||||
F: FnMut(Entity),
|
|
||||||
{
|
|
||||||
let lock = SPATIAL_MAP.lock().unwrap();
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
for entity in lock.tile_content[idx].iter() {
|
for entity in lock.tile_content[idx].iter() {
|
||||||
f(entity.0);
|
f(entity.0);
|
||||||
|
|
@ -107,8 +104,7 @@ where
|
||||||
/// Calls a function on every entity within a given tile idx, with the
|
/// Calls a function on every entity within a given tile idx, with the
|
||||||
/// added ability to return a RunState mid-calc.
|
/// added ability to return a RunState mid-calc.
|
||||||
pub fn for_each_tile_content_with_runstate<F>(idx: usize, mut f: F) -> Option<RunState>
|
pub fn for_each_tile_content_with_runstate<F>(idx: usize, mut f: F) -> Option<RunState>
|
||||||
where
|
where F: FnMut(Entity) -> Option<RunState>
|
||||||
F: FnMut(Entity) -> Option<RunState>,
|
|
||||||
{
|
{
|
||||||
let lock = SPATIAL_MAP.lock().unwrap();
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
for entity in lock.tile_content[idx].iter() {
|
for entity in lock.tile_content[idx].iter() {
|
||||||
|
|
@ -121,10 +117,7 @@ where
|
||||||
|
|
||||||
/// Calls a function on every entity within a given tile idx, breaking if
|
/// Calls a function on every entity within a given tile idx, breaking if
|
||||||
/// the closure ever returns false.
|
/// the closure ever returns false.
|
||||||
pub fn for_each_tile_content_with_bool<F>(idx: usize, mut f: F)
|
pub fn for_each_tile_content_with_bool<F>(idx: usize, mut f: F) where F: FnMut(Entity) -> bool {
|
||||||
where
|
|
||||||
F: FnMut(Entity) -> bool,
|
|
||||||
{
|
|
||||||
let lock = SPATIAL_MAP.lock().unwrap();
|
let lock = SPATIAL_MAP.lock().unwrap();
|
||||||
for entity in lock.tile_content[idx].iter() {
|
for entity in lock.tile_content[idx].iter() {
|
||||||
if !f(entity.0) {
|
if !f(entity.0) {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,34 @@
|
||||||
use super::{
|
use super::{
|
||||||
random_table::RandomTable, raws, Attribute, Attributes, Clock, Energy, EquipmentChanged, Faction, HungerClock,
|
random_table::RandomTable,
|
||||||
HungerState, Map, Mind, Name, Player, Pool, Pools, Position, Rect, Renderable, SerializeMe, Skill, Skills,
|
raws,
|
||||||
TileType, Viewshed,
|
Attribute,
|
||||||
|
Attributes,
|
||||||
|
Clock,
|
||||||
|
Energy,
|
||||||
|
EquipmentChanged,
|
||||||
|
Faction,
|
||||||
|
HungerClock,
|
||||||
|
HungerState,
|
||||||
|
Map,
|
||||||
|
Mind,
|
||||||
|
Name,
|
||||||
|
Player,
|
||||||
|
Pool,
|
||||||
|
Pools,
|
||||||
|
Position,
|
||||||
|
Rect,
|
||||||
|
Renderable,
|
||||||
|
SerializeMe,
|
||||||
|
Skill,
|
||||||
|
Skills,
|
||||||
|
TileType,
|
||||||
|
Viewshed,
|
||||||
};
|
};
|
||||||
use crate::config::entity;
|
use crate::config::entity;
|
||||||
use crate::gamesystem::*;
|
use crate::gamesystem::*;
|
||||||
use rltk::{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;
|
||||||
|
|
||||||
/// Spawns the player and returns his/her entity object.
|
/// Spawns the player and returns his/her entity object.
|
||||||
|
|
@ -68,7 +89,7 @@ pub fn spawn_room(
|
||||||
rng: &mut RandomNumberGenerator,
|
rng: &mut RandomNumberGenerator,
|
||||||
room: &Rect,
|
room: &Rect,
|
||||||
spawn_list: &mut Vec<(usize, String)>,
|
spawn_list: &mut Vec<(usize, String)>,
|
||||||
player_level: i32,
|
player_level: i32
|
||||||
) {
|
) {
|
||||||
let mut possible_targets: Vec<usize> = Vec::new();
|
let mut possible_targets: Vec<usize> = Vec::new();
|
||||||
{
|
{
|
||||||
|
|
@ -91,7 +112,7 @@ pub fn spawn_region(
|
||||||
rng: &mut RandomNumberGenerator,
|
rng: &mut RandomNumberGenerator,
|
||||||
area: &[usize],
|
area: &[usize],
|
||||||
spawn_list: &mut Vec<(usize, String)>,
|
spawn_list: &mut Vec<(usize, String)>,
|
||||||
player_level: i32,
|
player_level: i32
|
||||||
) {
|
) {
|
||||||
let mut spawn_points: HashMap<usize, String> = HashMap::new();
|
let mut spawn_points: HashMap<usize, String> = HashMap::new();
|
||||||
let mut areas: Vec<usize> = Vec::from(area);
|
let mut areas: Vec<usize> = Vec::from(area);
|
||||||
|
|
@ -105,9 +126,9 @@ pub fn spawn_region(
|
||||||
let spawn_mob: bool = rng.roll_dice(1, 3) == 1;
|
let spawn_mob: bool = rng.roll_dice(1, 3) == 1;
|
||||||
let num_items = match rng.roll_dice(1, 20) {
|
let num_items = match rng.roll_dice(1, 20) {
|
||||||
1..=2 => 1, // 10% chance of spawning 1 item
|
1..=2 => 1, // 10% chance of spawning 1 item
|
||||||
3 => 2, // 5% chance of spawning 2 items
|
3 => 2, // 5% chance of spawning 2 items
|
||||||
4 => 3, // 5% chance of spawning 3 items
|
4 => 3, // 5% chance of spawning 3 items
|
||||||
_ => 0, // 80% chance of spawning nothing
|
_ => 0, // 80% chance of spawning nothing
|
||||||
};
|
};
|
||||||
let num_traps = match rng.roll_dice(1, 20) {
|
let num_traps = match rng.roll_dice(1, 20) {
|
||||||
1 => 1, // 5% chance of spawning 1 trap
|
1 => 1, // 5% chance of spawning 1 trap
|
||||||
|
|
@ -143,13 +164,16 @@ fn entity_to_spawn_list(
|
||||||
rng: &mut RandomNumberGenerator,
|
rng: &mut RandomNumberGenerator,
|
||||||
possible_areas: &mut Vec<usize>,
|
possible_areas: &mut Vec<usize>,
|
||||||
key: String,
|
key: String,
|
||||||
spawn_points: &mut HashMap<usize, String>,
|
spawn_points: &mut HashMap<usize, String>
|
||||||
) {
|
) {
|
||||||
if possible_areas.len() == 0 {
|
if possible_areas.len() == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let array_idx =
|
let array_idx = if possible_areas.len() == 1 {
|
||||||
if possible_areas.len() == 1 { 0usize } else { (rng.roll_dice(1, possible_areas.len() as i32) - 1) as usize };
|
0usize
|
||||||
|
} else {
|
||||||
|
(rng.roll_dice(1, possible_areas.len() as i32) - 1) as usize
|
||||||
|
};
|
||||||
let map_idx = possible_areas[array_idx];
|
let map_idx = possible_areas[array_idx];
|
||||||
spawn_points.insert(map_idx, key);
|
spawn_points.insert(map_idx, key);
|
||||||
possible_areas.remove(array_idx);
|
possible_areas.remove(array_idx);
|
||||||
|
|
@ -170,7 +194,7 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
||||||
&spawn.1,
|
&spawn.1,
|
||||||
None,
|
None,
|
||||||
raws::SpawnType::AtPosition { x, y },
|
raws::SpawnType::AtPosition { x, y },
|
||||||
map_difficulty,
|
map_difficulty
|
||||||
);
|
);
|
||||||
if spawn_result.is_some() {
|
if spawn_result.is_some() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -191,12 +215,24 @@ fn debug_table() -> RandomTable {
|
||||||
fn get_random_item_category(rng: &mut RandomNumberGenerator, difficulty: Option<i32>) -> RandomTable {
|
fn get_random_item_category(rng: &mut RandomNumberGenerator, difficulty: Option<i32>) -> RandomTable {
|
||||||
let item_category = item_category_table().roll(rng);
|
let item_category = item_category_table().roll(rng);
|
||||||
match item_category.as_ref() {
|
match item_category.as_ref() {
|
||||||
"equipment" => return equipment_table(difficulty),
|
"equipment" => {
|
||||||
"food" => return food_table(difficulty),
|
return equipment_table(difficulty);
|
||||||
"potion" => return potion_table(difficulty),
|
}
|
||||||
"scroll" => return scroll_table(difficulty),
|
"food" => {
|
||||||
"wand" => return wand_table(difficulty),
|
return food_table(difficulty);
|
||||||
_ => return debug_table(),
|
}
|
||||||
|
"potion" => {
|
||||||
|
return potion_table(difficulty);
|
||||||
|
}
|
||||||
|
"scroll" => {
|
||||||
|
return scroll_table(difficulty);
|
||||||
|
}
|
||||||
|
"wand" => {
|
||||||
|
return wand_table(difficulty);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return debug_table();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
use super::{
|
use super::{
|
||||||
effects::{add_effect, aoe_tiles, EffectType, Targets},
|
effects::{ add_effect, aoe_tiles, EffectType, Targets },
|
||||||
gamelog,
|
gamelog,
|
||||||
gui::renderable_colour,
|
gui::renderable_colour,
|
||||||
EntityMoved, EntryTrigger, Map, Name, Point, Position, Renderable, AOE,
|
EntityMoved,
|
||||||
|
EntryTrigger,
|
||||||
|
Map,
|
||||||
|
Name,
|
||||||
|
Point,
|
||||||
|
Position,
|
||||||
|
Renderable,
|
||||||
|
AOE,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -34,7 +41,8 @@ impl<'a> System<'a> for TriggerSystem {
|
||||||
Some(_trigger) => {
|
Some(_trigger) => {
|
||||||
if map.visible_tiles[idx] == true {
|
if map.visible_tiles[idx] == true {
|
||||||
if let Some(name) = names.get(entity_id) {
|
if let Some(name) = names.get(entity_id) {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("The")
|
.append("The")
|
||||||
.colour(renderable_colour(&renderables, entity_id))
|
.colour(renderable_colour(&renderables, entity_id))
|
||||||
.append(&name.name)
|
.append(&name.name)
|
||||||
|
|
@ -43,17 +51,15 @@ impl<'a> System<'a> for TriggerSystem {
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_effect(
|
add_effect(Some(entity_id), EffectType::TriggerFire { trigger: entity_id }, if
|
||||||
Some(entity_id),
|
let Some(aoe) = aoes.get(entity_id)
|
||||||
EffectType::TriggerFire { trigger: entity_id },
|
{
|
||||||
if let Some(aoe) = aoes.get(entity_id) {
|
Targets::TileList {
|
||||||
Targets::TileList {
|
targets: aoe_tiles(&*map, Point::new(pos.x, pos.y), aoe.radius),
|
||||||
targets: aoe_tiles(&*map, Point::new(pos.x, pos.y), aoe.radius),
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
Targets::Tile { target: idx }
|
||||||
Targets::Tile { target: idx }
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{gamelog, Blind, BlocksVisibility, Hidden, Map, Name, Player, Position, Telepath, Viewshed};
|
use super::{ gamelog, Blind, BlocksVisibility, Hidden, Map, Name, Player, Position, Telepath, Viewshed };
|
||||||
use rltk::{FieldOfViewAlg::SymmetricShadowcasting, Point};
|
use rltk::{ FieldOfViewAlg::SymmetricShadowcasting, Point };
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
pub struct VisibilitySystem {}
|
pub struct VisibilitySystem {}
|
||||||
|
|
@ -49,12 +49,12 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
let origin = Point::new(pos.x, pos.y);
|
let origin = Point::new(pos.x, pos.y);
|
||||||
viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, range, &*map);
|
viewshed.visible_tiles = SymmetricShadowcasting.field_of_view(origin, range, &*map);
|
||||||
viewshed.visible_tiles.retain(|p| {
|
viewshed.visible_tiles.retain(|p| {
|
||||||
p.x >= 0
|
p.x >= 0 &&
|
||||||
&& p.x < map.width
|
p.x < map.width &&
|
||||||
&& p.y >= 0
|
p.y >= 0 &&
|
||||||
&& p.y < map.height
|
p.y < map.height &&
|
||||||
&& (map.lit_tiles[map.xy_idx(p.x, p.y)] == true
|
(map.lit_tiles[map.xy_idx(p.x, p.y)] == true ||
|
||||||
|| rltk::DistanceAlg::Pythagoras.distance2d(Point::new(p.x, p.y), origin) < 1.5)
|
rltk::DistanceAlg::Pythagoras.distance2d(Point::new(p.x, p.y), origin) < 1.5)
|
||||||
});
|
});
|
||||||
|
|
||||||
// If this is the player, reveal what they can see
|
// If this is the player, reveal what they can see
|
||||||
|
|
@ -75,7 +75,8 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
if rng.roll_dice(1, 12) == 1 {
|
if rng.roll_dice(1, 12) == 1 {
|
||||||
let name = names.get(e);
|
let name = names.get(e);
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
.append("You spot a")
|
.append("You spot a")
|
||||||
.item_name_n(&name.name)
|
.item_name_n(&name.name)
|
||||||
.period()
|
.period()
|
||||||
|
|
@ -121,11 +122,11 @@ pub fn fast_fov(p_x: i32, p_y: i32, r: i32) -> Vec<Point> {
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i <= 360 {
|
while i <= 360 {
|
||||||
let x: f32 = f32::cos(i as f32 * 0.01745 as f32);
|
let x: f32 = f32::cos((i as f32) * (0.01745 as f32));
|
||||||
let y: f32 = f32::sin(i as f32 * 0.01745 as f32);
|
let y: f32 = f32::sin((i as f32) * (0.01745 as f32));
|
||||||
|
|
||||||
let mut ox: f32 = p_x as f32 + 0.5 as f32;
|
let mut ox: f32 = (p_x as f32) + (0.5 as f32);
|
||||||
let mut oy: f32 = p_y as f32 + 0.5 as f32;
|
let mut oy: f32 = (p_y as f32) + (0.5 as f32);
|
||||||
for _i in 0..r {
|
for _i in 0..r {
|
||||||
visible_tiles.push(Point::new(ox as i32, oy as i32));
|
visible_tiles.push(Point::new(ox as i32, oy as i32));
|
||||||
ox += x;
|
ox += x;
|
||||||
|
|
|
||||||
1648
wasm/rust-llyrl.js
1648
wasm/rust-llyrl.js
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue