sorry - swapping from rustfmt to prettier-rust

This commit is contained in:
Llywelwyn 2023-08-23 01:22:09 +01:00
parent 281396f9ce
commit c2c7e0bd52
93 changed files with 2797 additions and 2021 deletions

3
.prettierrc.json Normal file
View file

@ -0,0 +1,3 @@
{
"printWidth": 120
}

View file

@ -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()));

View file

@ -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 }
} }

View file

@ -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));
}); });

View file

@ -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);

View file

@ -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);

View file

@ -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),
};
} }
} }
} }

View file

@ -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 })

View file

@ -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 );
));
} }
} }
} }

View file

@ -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");
} }
} }

View file

@ -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)

View file

@ -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
}; };

View file

@ -2,7 +2,11 @@ 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 }
); );
} }
} }

View file

@ -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,
)); ));

View file

@ -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;

View file

@ -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)]

View file

@ -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.

View file

@ -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()));

View file

@ -2,7 +2,14 @@ use super::{add_effect, targeting, EffectSpawner, EffectType, Entity, Targets, W
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;

View file

@ -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
}
} }

View file

@ -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,7 +122,8 @@ 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 } =>
targets.iter().for_each(|target| {
if let Some(end_pos) = targeting::entity_position(ecs, *target) { if let Some(end_pos) = targeting::entity_position(ecs, *target) {
spawn_line_particles(ecs, start_pos, end_pos as i32, part); 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) }
); );
} }
} }

View file

@ -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);

View file

@ -23,7 +23,12 @@ 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()
.unwrap()
.iter()
.rev()
.take(len)
.for_each(|log| {
let mut entry_len = -2; let mut entry_len = -2;
// Iterate through each message fragment, and get the total length // Iterate through each message fragment, and get the total length
// in lines, by adding the length of every fragment and dividing it // in lines, by adding the length of every fragment and dividing it
@ -47,15 +52,15 @@ pub fn print_log(console: &mut Box<dyn Console>, pos: Point, _descending: bool,
break; break;
} }
i += 1; i += 1;
if x + part.len() as i32 > pos.x + maximum_len { if x + (part.len() as i32) > pos.x + maximum_len {
if y > pos.y - len as i32 { if y > pos.y - (len as i32) {
console.print(x, y, "-"); console.print(x, y, "-");
} }
y += 1; y += 1;
x = pos.x; x = pos.x;
} }
// Stay within bounds // Stay within bounds
if y > pos.y - len as i32 { if y > pos.y - (len as i32) {
console.print_color(x, y, frag.colour.into(), RGB::named(rltk::BLACK).into(), part); console.print_color(x, y, frag.colour.into(), RGB::named(rltk::BLACK).into(), part);
} }
x += part.len() as i32; x += part.len() as i32;

View file

@ -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),
@ -103,7 +103,8 @@ pub fn get_attribute_rolls(
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])

View file

@ -1,7 +1,18 @@
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 };
@ -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,
Renderable {
glyph: rltk::to_cp437('h'), glyph: rltk::to_cp437('h'),
fg: RGB::named(rltk::RED), fg: RGB::named(rltk::RED),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 0, 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,
Renderable {
glyph: rltk::to_cp437('@'), glyph: rltk::to_cp437('@'),
fg: RGB::named(rltk::GREEN), fg: RGB::named(rltk::GREEN),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 0, 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,34 +303,28 @@ 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,
Attributes {
strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) }, strength: Attribute { base: str, modifiers: 0, bonus: attr_bonus(str) },
dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) }, dexterity: Attribute { base: dex, modifiers: 0, bonus: attr_bonus(dex) },
constitution: Attribute { base: con, modifiers: 0, bonus: attr_bonus(con) }, constitution: Attribute { base: con, modifiers: 0, bonus: attr_bonus(con) },
intelligence: Attribute { base: int, modifiers: 0, bonus: attr_bonus(int) }, intelligence: Attribute { base: int, modifiers: 0, bonus: attr_bonus(int) },
wisdom: Attribute { base: wis, modifiers: 0, bonus: attr_bonus(wis) }, wisdom: Attribute { base: wis, modifiers: 0, bonus: attr_bonus(wis) },
charisma: Attribute { base: cha, modifiers: 0, bonus: attr_bonus(cha) }, 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,
Pools {
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) }, hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) }, mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
xp: 0, xp: 0,
@ -302,8 +332,7 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
bac: 10, bac: 10,
weight: 0.0, weight: 0.0,
god: false, 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 {

View file

@ -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,7 +50,8 @@ 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) =>
match key {
VirtualKeyCode::A => CheatMenuResult::Ascend, VirtualKeyCode::A => CheatMenuResult::Ascend,
VirtualKeyCode::D => CheatMenuResult::Descend, VirtualKeyCode::D => CheatMenuResult::Descend,
VirtualKeyCode::H => CheatMenuResult::Heal, VirtualKeyCode::H => CheatMenuResult::Heal,
@ -58,6 +59,6 @@ pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult {
VirtualKeyCode::G => CheatMenuResult::GodMode, VirtualKeyCode::G => CheatMenuResult::GodMode,
VirtualKeyCode::Escape => CheatMenuResult::Cancel, VirtualKeyCode::Escape => CheatMenuResult::Cancel,
_ => CheatMenuResult::NoResponse, _ => CheatMenuResult::NoResponse,
}, }
} }
} }

View file

@ -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,20 +117,25 @@ 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) =>
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => { _ => {
let selection = rltk::letter_to_option(key); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { if selection > -1 && selection < (count as i32) {
let item = inventory_ids.iter().nth(selection as usize).unwrap().1; let item = inventory_ids
gamelog::Logger::new() .iter()
.nth(selection as usize)
.unwrap().1;
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)
@ -119,6 +146,6 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
} }
(ItemMenuResult::NoResponse, None) (ItemMenuResult::NoResponse, None)
} }
}, }
} }
} }

View file

@ -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) =>
match key {
VirtualKeyCode::Y => Some(true), VirtualKeyCode::Y => Some(true),
VirtualKeyCode::N => Some(false), VirtualKeyCode::N => Some(false),
_ => None, _ => 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, }
Some(key) =>
match key {
VirtualKeyCode::Escape => {
return RunState::AwaitingInput;
}
// Cardinals // Cardinals
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => return function(-1, 0, ecs), VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => return function(1, 0, ecs), 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), VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
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 // Diagonals
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => return function(1, -1, ecs), VirtualKeyCode::Numpad9 | VirtualKeyCode::U => {
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => return function(-1, -1, ecs), return function(1, -1, ecs);
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => return function(1, 1, ecs), }
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => return function(-1, 1, ecs), VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => {
_ => return RunState::ActionWithDirection { function }, 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,7 +666,8 @@ 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) =>
match key {
VirtualKeyCode::Escape => YesNoResult::Yes, VirtualKeyCode::Escape => YesNoResult::Yes,
VirtualKeyCode::Slash => { VirtualKeyCode::Slash => {
if ctx.shift { if ctx.shift {
@ -610,7 +676,7 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
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) =>
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => { _ => {
let selection = letter_to_option::letter_to_option(key, ctx.shift); let selection = letter_to_option::letter_to_option(key, ctx.shift);
if selection > -1 && selection < count as i32 { if selection > -1 && selection < (count as i32) {
return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1)); 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) =>
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => { _ => {
let selection = rltk::letter_to_option(key); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { if selection > -1 && selection < (count as i32) {
return (ItemMenuResult::Selected, Some(*inventory_ids.iter().nth(selection as usize).unwrap().1)); 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) =>
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => { _ => {
let selection = rltk::letter_to_option(key); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { if selection > -1 && selection < (count as i32) {
return (ItemMenuResult::Selected, Some(equippable[selection as usize].0)); 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,19 +1021,32 @@ 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::Escape | VirtualKeyCode::C => {
return MainMenuResult::NoSelection { selected: MainMenuSelection::Quit };
}
VirtualKeyCode::N => {
return MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame };
}
VirtualKeyCode::L => {
return MainMenuResult::NoSelection { selected: MainMenuSelection::LoadGame };
} }
VirtualKeyCode::N => return MainMenuResult::NoSelection { selected: MainMenuSelection::NewGame },
VirtualKeyCode::L => return MainMenuResult::NoSelection { selected: MainMenuSelection::LoadGame },
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => { VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
let mut new_selection; let mut new_selection;
match selection { match selection {
MainMenuSelection::NewGame => new_selection = MainMenuSelection::LoadGame, MainMenuSelection::NewGame => {
MainMenuSelection::LoadGame => new_selection = MainMenuSelection::Quit, new_selection = MainMenuSelection::LoadGame;
MainMenuSelection::Quit => new_selection = MainMenuSelection::NewGame, }
MainMenuSelection::LoadGame => {
new_selection = MainMenuSelection::Quit;
}
MainMenuSelection::Quit => {
new_selection = MainMenuSelection::NewGame;
}
} }
if new_selection == MainMenuSelection::LoadGame && !save_exists { if new_selection == MainMenuSelection::LoadGame && !save_exists {
new_selection = MainMenuSelection::NewGame; new_selection = MainMenuSelection::NewGame;
@ -946,9 +1056,15 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => { VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
let mut new_selection; let mut new_selection;
match selection { match selection {
MainMenuSelection::NewGame => new_selection = MainMenuSelection::Quit, MainMenuSelection::NewGame => {
MainMenuSelection::LoadGame => new_selection = MainMenuSelection::NewGame, new_selection = MainMenuSelection::Quit;
MainMenuSelection::Quit => new_selection = MainMenuSelection::LoadGame, }
MainMenuSelection::LoadGame => {
new_selection = MainMenuSelection::NewGame;
}
MainMenuSelection::Quit => {
new_selection = MainMenuSelection::LoadGame;
}
} }
if new_selection == MainMenuSelection::LoadGame && !save_exists { if new_selection == MainMenuSelection::LoadGame && !save_exists {
new_selection = MainMenuSelection::Quit; new_selection = MainMenuSelection::Quit;
@ -956,10 +1072,12 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
return MainMenuResult::NoSelection { selected: new_selection }; return MainMenuResult::NoSelection { selected: new_selection };
} }
VirtualKeyCode::Return | VirtualKeyCode::NumpadEnter => { VirtualKeyCode::Return | VirtualKeyCode::NumpadEnter => {
return MainMenuResult::Selected { selected: selection } return MainMenuResult::Selected { selected: selection };
}
_ => {
return MainMenuResult::NoSelection { 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) =>
match key {
VirtualKeyCode::Escape => YesNoResult::Yes, VirtualKeyCode::Escape => YesNoResult::Yes,
_ => YesNoResult::NoSelection, _ => YesNoResult::NoSelection,
}, }
} }
} }

View file

@ -1,5 +1,10 @@
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 };
@ -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,20 +101,25 @@ 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) =>
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => { _ => {
let selection = rltk::letter_to_option(key); let selection = rltk::letter_to_option(key);
if selection > -1 && selection < count as i32 { if selection > -1 && selection < (count as i32) {
let item = inventory_ids.iter().nth(selection as usize).unwrap().1; let item = inventory_ids
gamelog::Logger::new() .iter()
.nth(selection as usize)
.unwrap().1;
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)
@ -117,6 +130,6 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
} }
(ItemMenuResult::NoResponse, None) (ItemMenuResult::NoResponse, None)
} }
}, }
} }
} }

View file

@ -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);
} }
} }
} }

View file

@ -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,7 +91,9 @@ 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 =>
gamelog::Logger
::new()
.append("You feel") .append("You feel")
.colour(get_hunger_colour(hunger_clock.state)) .colour(get_hunger_colour(hunger_clock.state))
.append_n("satiated") .append_n("satiated")
@ -95,28 +101,36 @@ impl<'a> System<'a> for HungerSystem {
.period() .period()
.log(), .log(),
HungerState::Normal => {} HungerState::Normal => {}
HungerState::Hungry => gamelog::Logger::new() HungerState::Hungry =>
gamelog::Logger
::new()
.append("You feel") .append("You feel")
.colour(get_hunger_colour(hunger_clock.state)) .colour(get_hunger_colour(hunger_clock.state))
.append_n("hungry") .append_n("hungry")
.colour(WHITE) .colour(WHITE)
.period() .period()
.log(), .log(),
HungerState::Weak => gamelog::Logger::new() HungerState::Weak =>
gamelog::Logger
::new()
.append("You feel") .append("You feel")
.colour(get_hunger_colour(hunger_clock.state)) .colour(get_hunger_colour(hunger_clock.state))
.append_n("weak with hunger") .append_n("weak with hunger")
.colour(WHITE) .colour(WHITE)
.period() .period()
.log(), .log(),
HungerState::Fainting => gamelog::Logger::new() HungerState::Fainting =>
gamelog::Logger
::new()
.append("You feel") .append("You feel")
.colour(get_hunger_colour(hunger_clock.state)) .colour(get_hunger_colour(hunger_clock.state))
.append_n("hungry enough to faint") .append_n("hungry enough to faint")
.colour(WHITE) .colour(WHITE)
.period() .period()
.log(), .log(),
_ => gamelog::Logger::new() _ =>
gamelog::Logger
::new()
.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("You can't go on without food!")
.log(), .log(),

View file

@ -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,9 +55,11 @@ 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( obfuscate_name(
pickup.item, pickup.item,
@ -57,9 +69,9 @@ impl<'a> System<'a> for ItemCollectionSystem {
&beatitudes, &beatitudes,
&dm, &dm,
Some(&wands) Some(&wands)
).0
)
) )
.0
))
.period() .period()
.log(); .log();
} }

View file

@ -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,9 +63,11 @@ 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( obfuscate_name(
to_drop.item, to_drop.item,
@ -65,9 +77,9 @@ impl<'a> System<'a> for ItemDropSystem {
&beatitudes, &beatitudes,
&dm, &dm,
Some(&wands) Some(&wands)
).0
)
) )
.0
))
.period() .period()
.log(); .log();
} }

View file

@ -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 {})

View file

@ -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,
}; };

View file

@ -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()

View file

@ -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,10 +37,7 @@ 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),
EffectType::ItemUse { item: useitem.item },
match useitem.target {
None => Targets::Entity { target: *player_entity }, None => Targets::Entity { target: *player_entity },
Some(target) => { Some(target) => {
if let Some(aoe) = aoe.get(useitem.item) { if let Some(aoe) = aoe.get(useitem.item) {
@ -44,8 +46,7 @@ impl<'a> System<'a> for ItemUseSystem {
Targets::Tile { target: map.xy_idx(target.x, target.y) } Targets::Tile { target: map.xy_idx(target.x, target.y) }
} }
} }
}, });
);
} }
wants_use.clear(); wants_use.clear();
} }

View file

@ -53,18 +53,32 @@ pub enum RunState {
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,14 +464,15 @@ 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 } =>
match selected {
gui::MainMenuSelection::NewGame => { gui::MainMenuSelection::NewGame => {
new_runstate = RunState::CharacterCreation { new_runstate = RunState::CharacterCreation {
ancestry: gui::Ancestry::Human, ancestry: gui::Ancestry::Human,
class: gui::Class::Fighter, class: gui::Class::Fighter,
} };
} }
gui::MainMenuSelection::LoadGame => { gui::MainMenuSelection::LoadGame => {
saveload_system::load_game(&mut self.ecs); saveload_system::load_game(&mut self.ecs);
@ -442,14 +482,14 @@ impl GameState for State {
gui::MainMenuSelection::Quit => { gui::MainMenuSelection::Quit => {
::std::process::exit(0); ::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 };

View file

@ -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;
} }
} }
} }

View file

@ -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
); );
} }
} }

View file

@ -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);
} }

View file

@ -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;
@ -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);
} }

View file

@ -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

View file

@ -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 });
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }

View file

@ -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 {

View file

@ -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() {

View file

@ -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();
} }
} }
} }

View file

@ -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;
} }

View file

@ -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();
} }
} }
} }

View file

@ -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);

View file

@ -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;
} }
} }
} }

View file

@ -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;

View file

@ -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 {

View file

@ -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 {

View file

@ -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;
} }
} }

View file

@ -29,13 +29,32 @@ 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
.as_mut()
.unwrap()
.sort_by(|a: &Rect, b: &Rect| {
let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1); let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1);
let b_centre_pt = rltk::Point::new(b.centre().0, b.centre().1); 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_a = rltk::DistanceAlg::Pythagoras.distance2d(a_centre_pt, map_centre);

View file

@ -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() {

View file

@ -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);

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -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)
), ),
)); ));
} }

View file

@ -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;

View file

@ -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
); );
} }
} }

View file

@ -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,7 +211,8 @@ 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(
format!(
"ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)", "ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)",
&name.name, &name.name,
attack_verb, attack_verb,
@ -197,7 +222,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
monster_v_player_bonus, monster_v_player_bonus,
armour_class_roll, armour_class_roll,
attacker_bonuses 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,7 +249,8 @@ 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(
format!(
"ATTACKLOG: {} HIT for {} ({}[{}d{}]+{}[skill]+{}[attr])", "ATTACKLOG: {} HIT for {} ({}[{}d{}]+{}[skill]+{}[attr])",
&name.name, &name.name,
damage, damage,
@ -228,28 +259,33 @@ impl<'a> System<'a> for MeleeCombatSystem {
weapon_info.damage_die_type, weapon_info.damage_die_type,
skill_damage_bonus, skill_damage_bonus,
attribute_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(
format!(
"ATTACKLOG: {} reduced their damage taken by {} (1dAC), and took {} hp damage.", "ATTACKLOG: {} reduced their damage taken by {} (1dAC), and took {} hp damage.",
&target_name.name, ac_damage_reduction, 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()));

View file

@ -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 })

View file

@ -4,9 +4,31 @@ use super::{
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 };
@ -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!")
@ -235,7 +267,8 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
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()
@ -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,11 +494,14 @@ 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;
}
Some(key) =>
match key {
// Cardinals // Cardinals
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => { 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::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => { VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
return try_move_player(1, 0, &mut gs.ecs); return try_move_player(1, 0, &mut gs.ecs);
@ -475,10 +513,18 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
return try_move_player(0, 1, &mut gs.ecs); return try_move_player(0, 1, &mut gs.ecs);
} }
// Diagonals // Diagonals
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => return try_move_player(1, -1, &mut gs.ecs), VirtualKeyCode::Numpad9 | VirtualKeyCode::U => {
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => return try_move_player(-1, -1, &mut gs.ecs), return try_move_player(1, -1, &mut gs.ecs);
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), 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);
}
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => {
return try_move_player(-1, 1, &mut gs.ecs);
}
// id // id
VirtualKeyCode::Period => { VirtualKeyCode::Period => {
if ctx.shift { if ctx.shift {
@ -508,22 +554,38 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
} }
// 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::O => {
return RunState::ActionWithDirection { function: open };
}
VirtualKeyCode::F => {
return RunState::ActionWithDirection { function: kick };
}
VirtualKeyCode::G => { VirtualKeyCode::G => {
return get_item(&mut gs.ecs); return get_item(&mut gs.ecs);
} }
VirtualKeyCode::I => return RunState::ShowInventory, VirtualKeyCode::I => {
VirtualKeyCode::D => return RunState::ShowDropItem, return RunState::ShowInventory;
VirtualKeyCode::R => return RunState::ShowRemoveItem, }
VirtualKeyCode::D => {
return RunState::ShowDropItem;
}
VirtualKeyCode::R => {
return RunState::ShowRemoveItem;
}
// Other // Other
VirtualKeyCode::Minus => return RunState::ShowCheatMenu, VirtualKeyCode::Minus => {
VirtualKeyCode::Escape => return RunState::SaveGame, return RunState::ShowCheatMenu;
}
VirtualKeyCode::Escape => {
return RunState::SaveGame;
}
_ => { _ => {
return RunState::AwaitingInput; 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;
} }
} }

View file

@ -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>);

View file

@ -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(),
match other.1.as_str() {
"flee" => Reaction::Flee, "flee" => Reaction::Flee,
"attack" => Reaction::Attack, "attack" => Reaction::Attack,
_ => Reaction::Ignore, _ => 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(
format!(
"SPAWNLOG: {} ({}HP, {}MANA, {}BAC) spawned at level {} ({}[base], {}[map difficulty], {}[player level]), worth {} XP", "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 &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(
format!(
"DEBUGINFO: Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}]. Returned debug entry.", "DEBUGINFO: Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}]. Returned debug entry.",
key, difficulty, upper_bound, lower_bound 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";
}
} }
} }

View file

@ -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 {

View file

@ -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) {

View file

@ -1,7 +1,28 @@
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::*;
@ -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);
@ -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();
}
}; };
} }

View file

@ -2,7 +2,14 @@ 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 }
}, });
);
} }
} }
} }

View file

@ -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;

View file

@ -316,16 +316,22 @@ function __wbg_get_imports() {
const ret = typeof (v) === 'boolean' ? (v ? 1 : 0) : 2; const ret = typeof (v) === 'boolean' ? (v ? 1 : 0) : 2;
return ret; return ret;
}; };
imports.wbg.__wbg_randomFillSync_bf67eeddb65b346b = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_randomFillSync_bf67eeddb65b346b = function () {
return handleError(function (arg0, arg1, arg2) {
getObject(arg0).randomFillSync(getArrayU8FromWasm0(arg1, arg2)); getObject(arg0).randomFillSync(getArrayU8FromWasm0(arg1, arg2));
}, arguments) }; }, arguments)
imports.wbg.__wbg_getRandomValues_f6c9b08ef5448767 = function() { return handleError(function (arg0, arg1) { };
imports.wbg.__wbg_getRandomValues_f6c9b08ef5448767 = function () {
return handleError(function (arg0, arg1) {
getObject(arg0).getRandomValues(getObject(arg1)); getObject(arg0).getRandomValues(getObject(arg1));
}, arguments) }; }, arguments)
imports.wbg.__wbg_self_1c2814d86e6e51e3 = function() { return handleError(function () { };
imports.wbg.__wbg_self_1c2814d86e6e51e3 = function () {
return handleError(function () {
const ret = self.self; const ret = self.self;
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_crypto_70532d614bc7e028 = function (arg0) { imports.wbg.__wbg_crypto_70532d614bc7e028 = function (arg0) {
const ret = getObject(arg0).crypto; const ret = getObject(arg0).crypto;
return addHeapObject(ret); return addHeapObject(ret);
@ -342,10 +348,12 @@ function __wbg_get_imports() {
const ret = module; const ret = module;
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_require_9ace3ae680954e98 = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_require_9ace3ae680954e98 = function () {
return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).require(getStringFromWasm0(arg1, arg2)); const ret = getObject(arg0).require(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_instanceof_WebGl2RenderingContext_f921526c513bf717 = function (arg0) { imports.wbg.__wbg_instanceof_WebGl2RenderingContext_f921526c513bf717 = function (arg0) {
let result; let result;
try { try {
@ -366,9 +374,11 @@ function __wbg_get_imports() {
const ret = getObject(arg0).createVertexArray(); const ret = getObject(arg0).createVertexArray();
return isLikeNone(ret) ? 0 : addHeapObject(ret); return isLikeNone(ret) ? 0 : addHeapObject(ret);
}; };
imports.wbg.__wbg_texImage2D_07240affd06971e9 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { imports.wbg.__wbg_texImage2D_07240affd06971e9 = function () {
return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9)); getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9));
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_attachShader_47256b6b3d42a22e = function (arg0, arg1, arg2) { imports.wbg.__wbg_attachShader_47256b6b3d42a22e = function (arg0, arg1, arg2) {
getObject(arg0).attachShader(getObject(arg1), getObject(arg2)); getObject(arg0).attachShader(getObject(arg1), getObject(arg2));
}; };
@ -435,10 +445,12 @@ function __wbg_get_imports() {
const ret = getObject(arg0).getError(); const ret = getObject(arg0).getError();
return ret; return ret;
}; };
imports.wbg.__wbg_getExtension_77909f6d51d49d4d = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_getExtension_77909f6d51d49d4d = function () {
return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).getExtension(getStringFromWasm0(arg1, arg2)); const ret = getObject(arg0).getExtension(getStringFromWasm0(arg1, arg2));
return isLikeNone(ret) ? 0 : addHeapObject(ret); return isLikeNone(ret) ? 0 : addHeapObject(ret);
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_getProgramInfoLog_b81bc53188e286fa = function (arg0, arg1, arg2) { imports.wbg.__wbg_getProgramInfoLog_b81bc53188e286fa = function (arg0, arg1, arg2) {
const ret = getObject(arg1).getProgramInfoLog(getObject(arg2)); const ret = getObject(arg1).getProgramInfoLog(getObject(arg2));
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@ -506,10 +518,12 @@ function __wbg_get_imports() {
imports.wbg.__wbg_setheight_a747d440760fe5aa = function (arg0, arg1) { imports.wbg.__wbg_setheight_a747d440760fe5aa = function (arg0, arg1) {
getObject(arg0).height = arg1 >>> 0; getObject(arg0).height = arg1 >>> 0;
}; };
imports.wbg.__wbg_getContext_7c5944ea807bf5d3 = function() { return handleError(function (arg0, arg1, arg2) { imports.wbg.__wbg_getContext_7c5944ea807bf5d3 = function () {
return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2)); const ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2));
return isLikeNone(ret) ? 0 : addHeapObject(ret); return isLikeNone(ret) ? 0 : addHeapObject(ret);
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_offsetX_5a58f16f6c3a41b6 = function (arg0) { imports.wbg.__wbg_offsetX_5a58f16f6c3a41b6 = function (arg0) {
const ret = getObject(arg0).offsetX; const ret = getObject(arg0).offsetX;
return ret; return ret;
@ -565,10 +579,12 @@ function __wbg_get_imports() {
imports.wbg.__wbg_setonkeyup_0dfb23e81d0afdde = function (arg0, arg1) { imports.wbg.__wbg_setonkeyup_0dfb23e81d0afdde = function (arg0, arg1) {
getObject(arg0).onkeyup = getObject(arg1); getObject(arg0).onkeyup = getObject(arg1);
}; };
imports.wbg.__wbg_requestAnimationFrame_d082200514b6674d = function() { return handleError(function (arg0, arg1) { imports.wbg.__wbg_requestAnimationFrame_d082200514b6674d = function () {
return handleError(function (arg0, arg1) {
const ret = getObject(arg0).requestAnimationFrame(getObject(arg1)); const ret = getObject(arg0).requestAnimationFrame(getObject(arg1));
return ret; return ret;
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_setonmousedown_4f38d9c057bbfcbd = function (arg0, arg1) { imports.wbg.__wbg_setonmousedown_4f38d9c057bbfcbd = function (arg0, arg1) {
getObject(arg0).onmousedown = getObject(arg1); getObject(arg0).onmousedown = getObject(arg1);
}; };
@ -581,9 +597,11 @@ function __wbg_get_imports() {
imports.wbg.__wbg_bufferData_a11a9f65f31e7256 = function (arg0, arg1, arg2, arg3) { imports.wbg.__wbg_bufferData_a11a9f65f31e7256 = function (arg0, arg1, arg2, arg3) {
getObject(arg0).bufferData(arg1 >>> 0, getObject(arg2), arg3 >>> 0); getObject(arg0).bufferData(arg1 >>> 0, getObject(arg2), arg3 >>> 0);
}; };
imports.wbg.__wbg_texImage2D_6175916e58c59bc7 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { imports.wbg.__wbg_texImage2D_6175916e58c59bc7 = function () {
return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9)); getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9));
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_attachShader_b65b695055670cb5 = function (arg0, arg1, arg2) { imports.wbg.__wbg_attachShader_b65b695055670cb5 = function (arg0, arg1, arg2) {
getObject(arg0).attachShader(getObject(arg1), getObject(arg2)); getObject(arg0).attachShader(getObject(arg1), getObject(arg2));
}; };
@ -708,30 +726,42 @@ function __wbg_get_imports() {
const ret = new Function(getStringFromWasm0(arg0, arg1)); const ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_get_97b561fb56f034b5 = function() { return handleError(function (arg0, arg1) { imports.wbg.__wbg_get_97b561fb56f034b5 = function () {
return handleError(function (arg0, arg1) {
const ret = Reflect.get(getObject(arg0), getObject(arg1)); const ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
imports.wbg.__wbg_call_cb65541d95d71282 = function() { return handleError(function (arg0, arg1) { };
imports.wbg.__wbg_call_cb65541d95d71282 = function () {
return handleError(function (arg0, arg1) {
const ret = getObject(arg0).call(getObject(arg1)); const ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
imports.wbg.__wbg_self_1ff1d729e9aae938 = function() { return handleError(function () { };
imports.wbg.__wbg_self_1ff1d729e9aae938 = function () {
return handleError(function () {
const ret = self.self; const ret = self.self;
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
imports.wbg.__wbg_window_5f4faef6c12b79ec = function() { return handleError(function () { };
imports.wbg.__wbg_window_5f4faef6c12b79ec = function () {
return handleError(function () {
const ret = window.window; const ret = window.window;
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
imports.wbg.__wbg_globalThis_1d39714405582d3c = function() { return handleError(function () { };
imports.wbg.__wbg_globalThis_1d39714405582d3c = function () {
return handleError(function () {
const ret = globalThis.globalThis; const ret = globalThis.globalThis;
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
imports.wbg.__wbg_global_651f05c6a0944d1c = function() { return handleError(function () { };
imports.wbg.__wbg_global_651f05c6a0944d1c = function () {
return handleError(function () {
const ret = global.global; const ret = global.global;
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments)
};
imports.wbg.__wbg_now_9c5990bda04c7e53 = function () { imports.wbg.__wbg_now_9c5990bda04c7e53 = function () {
const ret = Date.now(); const ret = Date.now();
return ret; return ret;