atomises item table into sub-tables, adds table rolls to vaults
This commit is contained in:
parent
72bd7558fa
commit
1f6c04a526
6 changed files with 92 additions and 46 deletions
48
README.md
48
README.md
|
|
@ -1,36 +1,37 @@
|
||||||
## a roguelike in rust, playable @ [llywelwyn.github.io](https://llywelwyn.github.io/)
|
## a roguelike in rust, playable @ [llywelwyn.github.io](https://llywelwyn.github.io/)
|
||||||
#### using _rltk/bracket-lib_, and _specs_
|
|
||||||

|
|
||||||
|
|
||||||
|
#### using _rltk/bracket-lib_, and _specs_
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
this year for roguelikedev does the complete tutorial, i'm following along with thebracket's [_roguelike tutorial - in rust_](https://bfnightly.bracketproductions.com). for most of the 8 weeks, i'll probably just be working through the content rather than diverging too much into doing my own thing, since it's lengthy and i'd rather finish in time. that said, the ultimate aim here is to strip out the vast majority of the existing entities and replace them with my own, using the systems and components from the tutorial as a jumping-off point for something of my own making.
|
this year for roguelikedev does the complete tutorial, i'm following along with thebracket's [_roguelike tutorial - in rust_](https://bfnightly.bracketproductions.com). for most of the 8 weeks, i'll probably just be working through the content rather than diverging too much into doing my own thing, since it's lengthy and i'd rather finish in time. that said, the ultimate aim here is to strip out the vast majority of the existing entities and replace them with my own, using the systems and components from the tutorial as a jumping-off point for something of my own making.
|
||||||
|
|
||||||
i'll try to remember to update the web version on my page at the end of every week
|
i'll try to remember to update the web version on my page at the end of every week
|
||||||
|
|
||||||
- - -
|
---
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>week 1</summary>
|
<summary>week 1</summary>
|
||||||
|
|
||||||
- brogue-like colours
|
- brogue-like colours
|
||||||
|
|
||||||
- i was staring at a horrible-looking game for a while as i tried to figure out how to make it look nice, before deciding to try the brogue method of colour offsets. when a map is generated, it also generates a red, green, and blue offset value for every tile on the map, and applies them during rendering. after making that change i started to miss the previous hue, so i combined the two. as it stands, every tile starts off a subtle green/blue, has rgb offsets applied on top of that, and then has the actual tile colour applied. and it ends up making something like this
|
- i was staring at a horrible-looking game for a while as i tried to figure out how to make it look nice, before deciding to try the brogue method of colour offsets. when a map is generated, it also generates a red, green, and blue offset value for every tile on the map, and applies them during rendering. after making that change i started to miss the previous hue, so i combined the two. as it stands, every tile starts off a subtle green/blue, has rgb offsets applied on top of that, and then has the actual tile colour applied. and it ends up making something like this
|
||||||

|

|
||||||
|
|
||||||
- fov
|
- fov
|
||||||
- decided to use bracket-lib's symmetric shadowcasting for common viewsheds (i.e. sight)
|
|
||||||
- and implemented elig's [raycasting](https://www.roguebasin.com/index.php/Eligloscode) algorithm for any viewsheds that _dont_ need that level of detail. symmetric is great, but when it comes to viewsheds that often _aren't_ symmetric in the first place, it's not really necessary (i.e. it's not often you've got two people with: the same additional viewshed, both within range, etc.). doing it this way comes with the benefit of being able to easily define what blocks a viewshed, rather than having to make a whole new BaseMap to work through bracket-lib
|
- decided to use bracket-lib's symmetric shadowcasting for common viewsheds (i.e. sight)
|
||||||
|
- and implemented elig's [raycasting](https://www.roguebasin.com/index.php/Eligloscode) algorithm for any viewsheds that _dont_ need that level of detail. symmetric is great, but when it comes to viewsheds that often _aren't_ symmetric in the first place, it's not really necessary (i.e. it's not often you've got two people with: the same additional viewshed, both within range, etc.). doing it this way comes with the benefit of being able to easily define what blocks a viewshed, rather than having to make a whole new BaseMap to work through bracket-lib
|
||||||
|
|
||||||
|
- telepaths and having brains
|
||||||
|
- telepathy! a personal favourite rl feature, so i thought it'd be a cool test of the raycasting. right now it's simple, since the point was really just making sure the raycasting worked: there's a component for _being a telepath_, and for _having a mind_. if someone has telepathy, they'll see every entity with a mind within a given radius (defined by their telepath component), even through walls.
|
||||||
|

|
||||||
|
- atomised spawn tables
|
||||||
|
- i tried figuring out how often things would spawn by just looking at the weighted tables, and i had no idea at a glance, so i replaced it with category tables. right now it's just rolling for an entity or a mob, and then rolling on the right table from there, but at least it means easily being able to see how often something will spawn. on average right now, there's 1 item : 3 mobs
|
||||||
|
|
||||||
- telepaths and having brains
|
|
||||||
- telepathy! a personal favourite rl feature, so i thought it'd be a cool test of the raycasting. right now it's simple, since the point was really just making sure the raycasting worked: there's a component for _being a telepath_, and for _having a mind_. if someone has telepathy, they'll see every entity with a mind within a given radius (defined by their telepath component), even through walls.
|
|
||||||

|
|
||||||
|
|
||||||
- atomised spawn tables
|
|
||||||
- i tried figuring out how often things would spawn by just looking at the weighted tables, and i had no idea at a glance, so i replaced it with category tables. right now it's just rolling for an entity or a mob, and then rolling on the right table from there, but at least it means easily being able to see how often something will spawn. on average right now, there's 1 item : 3 mobs
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
- - -
|
---
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>week 2</summary>
|
<summary>week 2</summary>
|
||||||
|
|
@ -41,5 +42,18 @@ i'll try to remember to update the web version on my page at the end of every we
|
||||||
- 8-bit walls
|
- 8-bit walls
|
||||||
- i wasn't happy with how the walls looked, so i made the masks 8-bit instead of just 4-, which means being able to be a lot more specific with which glyphs are used. mainly it means no more grids of ╬. this comes with a side-effect of magic mapping looking a lot better.
|
- i wasn't happy with how the walls looked, so i made the masks 8-bit instead of just 4-, which means being able to be a lot more specific with which glyphs are used. mainly it means no more grids of ╬. this comes with a side-effect of magic mapping looking a lot better.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>week 3</summary>
|
||||||
|
|
||||||
|
- stacking items
|
||||||
|
- finally, identical items in the inventory stack. i waited with this until figuring out a way that would work with extra parameters in the future like BUC. current solution is using a BTreeMap with a tuple containing the parameters that need to be the same (right now just the name) as the key, and the number of those items in the inventory as the value.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
|
||||||
BIN
image.png
Normal file
BIN
image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -304,6 +304,7 @@ pub fn random_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator) ->
|
||||||
builder.start_with(BspInteriorBuilder::new());
|
builder.start_with(BspInteriorBuilder::new());
|
||||||
builder.with(DoorPlacement::new());
|
builder.with(DoorPlacement::new());
|
||||||
builder.with(RoomBasedSpawner::new());
|
builder.with(RoomBasedSpawner::new());
|
||||||
|
builder.with(PrefabBuilder::vaults());
|
||||||
builder.with(RoomBasedStairs::new());
|
builder.with(RoomBasedStairs::new());
|
||||||
builder.with(RoomBasedStartingPosition::new());
|
builder.with(RoomBasedStartingPosition::new());
|
||||||
builder
|
builder
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
use super::{BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType};
|
use super::{
|
||||||
|
spawner::equipment_table, spawner::food_table, spawner::potion_table, spawner::scroll_table, spawner::wand_table,
|
||||||
|
BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType,
|
||||||
|
};
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
pub mod prefab_levels;
|
pub mod prefab_levels;
|
||||||
pub mod prefab_sections;
|
pub mod prefab_sections;
|
||||||
|
|
@ -60,15 +63,15 @@ impl PrefabBuilder {
|
||||||
|
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
PrefabMode::RexLevel { template } => self.load_rex_map(&template, build_data),
|
PrefabMode::RexLevel { template } => self.load_rex_map(&template, rng, build_data),
|
||||||
PrefabMode::Constant { level } => self.load_ascii_map(&level, build_data),
|
PrefabMode::Constant { level } => self.load_ascii_map(&level, rng, build_data),
|
||||||
PrefabMode::Sectional { section } => self.apply_sectional(§ion, rng, build_data),
|
PrefabMode::Sectional { section } => self.apply_sectional(§ion, rng, build_data),
|
||||||
PrefabMode::RoomVaults => self.apply_room_vaults(rng, build_data),
|
PrefabMode::RoomVaults => self.apply_room_vaults(rng, build_data),
|
||||||
}
|
}
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char_to_map(&mut self, ch: char, idx: usize, build_data: &mut BuilderMap) {
|
fn char_to_map(&mut self, ch: char, idx: usize, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
match ch {
|
match ch {
|
||||||
' ' => build_data.map.tiles[idx] = TileType::Floor,
|
' ' => build_data.map.tiles[idx] = TileType::Floor,
|
||||||
'#' => build_data.map.tiles[idx] = TileType::Wall,
|
'#' => build_data.map.tiles[idx] = TileType::Wall,
|
||||||
|
|
@ -98,20 +101,20 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
'%' => {
|
'%' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "rations".to_string()));
|
build_data.spawn_list.push((idx, food_table(build_data.map.depth).roll(rng)));
|
||||||
}
|
}
|
||||||
'!' => {
|
'!' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "health potion".to_string()));
|
build_data.spawn_list.push((idx, potion_table(build_data.map.depth).roll(rng)));
|
||||||
}
|
}
|
||||||
'/' => {
|
'/' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "magic missile wand".to_string()));
|
build_data.spawn_list.push((idx, wand_table(build_data.map.depth).roll(rng)));
|
||||||
// Placeholder for wand spawn
|
// Placeholder for wand spawn
|
||||||
}
|
}
|
||||||
'?' => {
|
'?' => {
|
||||||
build_data.map.tiles[idx] = TileType::Floor;
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
build_data.spawn_list.push((idx, "fireball scroll".to_string()));
|
build_data.spawn_list.push((idx, scroll_table(build_data.map.depth).roll(rng)));
|
||||||
// Placeholder for scroll spawn
|
// Placeholder for scroll spawn
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -121,7 +124,7 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn load_rex_map(&mut self, path: &str, build_data: &mut BuilderMap) {
|
fn load_rex_map(&mut self, path: &str, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
let xp_file = rltk::rex::XpFile::from_resource(path).unwrap();
|
let xp_file = rltk::rex::XpFile::from_resource(path).unwrap();
|
||||||
|
|
||||||
for layer in &xp_file.layers {
|
for layer in &xp_file.layers {
|
||||||
|
|
@ -131,7 +134,7 @@ impl PrefabBuilder {
|
||||||
if x < build_data.map.width as usize && y < build_data.map.height as usize {
|
if x < build_data.map.width as usize && y < build_data.map.height as usize {
|
||||||
let idx = build_data.map.xy_idx(x as i32, y as i32);
|
let idx = build_data.map.xy_idx(x as i32, y as i32);
|
||||||
// We're doing some nasty casting to make it easier to type things like '#' in the match
|
// We're doing some nasty casting to make it easier to type things like '#' in the match
|
||||||
self.char_to_map(cell.ch as u8 as char, idx, build_data);
|
self.char_to_map(cell.ch as u8 as char, idx, rng, build_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +152,12 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn load_ascii_map(&mut self, level: &prefab_levels::PrefabLevel, build_data: &mut BuilderMap) {
|
fn load_ascii_map(
|
||||||
|
&mut self,
|
||||||
|
level: &prefab_levels::PrefabLevel,
|
||||||
|
rng: &mut RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
) {
|
||||||
let string_vec = PrefabBuilder::read_ascii_to_vec(level.template);
|
let string_vec = PrefabBuilder::read_ascii_to_vec(level.template);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
@ -158,7 +166,7 @@ impl PrefabBuilder {
|
||||||
if tx < build_data.map.width as usize && ty < build_data.map.height as usize {
|
if tx < build_data.map.width as usize && ty < build_data.map.height as usize {
|
||||||
let idx = build_data.map.xy_idx(tx as i32, ty as i32);
|
let idx = build_data.map.xy_idx(tx as i32, ty as i32);
|
||||||
if i < string_vec.len() {
|
if i < string_vec.len() {
|
||||||
self.char_to_map(string_vec[i], idx, build_data);
|
self.char_to_map(string_vec[i], idx, rng, build_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
@ -228,7 +236,7 @@ impl PrefabBuilder {
|
||||||
{
|
{
|
||||||
let idx = build_data.map.xy_idx(tx as i32 + chunk_x, ty as i32 + chunk_y);
|
let idx = build_data.map.xy_idx(tx as i32 + chunk_x, ty as i32 + chunk_y);
|
||||||
if i < string_vec.len() {
|
if i < string_vec.len() {
|
||||||
self.char_to_map(string_vec[i], idx, build_data);
|
self.char_to_map(string_vec[i], idx, rng, build_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
@ -385,7 +393,7 @@ impl PrefabBuilder {
|
||||||
}
|
}
|
||||||
let idx = build_data.map.xy_idx(x_ + chunk_x, y_ + chunk_y);
|
let idx = build_data.map.xy_idx(x_ + chunk_x, y_ + chunk_y);
|
||||||
if i < string_vec.len() {
|
if i < string_vec.len() {
|
||||||
self.char_to_map(string_vec[i], idx, build_data);
|
self.char_to_map(string_vec[i], idx, rng, build_data);
|
||||||
}
|
}
|
||||||
used_tiles.insert(idx);
|
used_tiles.insert(idx);
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,18 @@ impl RandomTable {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds two RandomTables together
|
||||||
|
pub fn add_table(mut self, table: RandomTable) -> RandomTable {
|
||||||
|
// For every entry in the table being added, push to self.
|
||||||
|
for entry in table.entries {
|
||||||
|
self.entries.push(entry);
|
||||||
|
}
|
||||||
|
// Add the total weight of the added table to self.
|
||||||
|
self.total_weight += table.total_weight;
|
||||||
|
// Return
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
/// Rolls on an existing RandomTable
|
/// Rolls on an existing RandomTable
|
||||||
pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String {
|
pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String {
|
||||||
// If the table has no weight, return nothing.
|
// If the table has no weight, return nothing.
|
||||||
|
|
|
||||||
|
|
@ -199,35 +199,46 @@ fn mob_table(map_depth: i32) -> RandomTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6 equipment : 10 potions : 10 scrolls : 2 cursed scrolls
|
// 6 equipment : 10 potions : 10 scrolls : 2 cursed scrolls
|
||||||
fn item_table(_map_depth: i32) -> RandomTable {
|
fn item_table(map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new()
|
return RandomTable::new()
|
||||||
// Equipment
|
// Equipment
|
||||||
.add("dagger", 4)
|
.add_table(equipment_table(map_depth))
|
||||||
.add("shortsword", 4)
|
|
||||||
.add("buckler", 4)
|
|
||||||
.add("shield", 2)
|
|
||||||
// Potions
|
// Potions
|
||||||
.add("weak health potion", 14)
|
.add_table(potion_table(map_depth))
|
||||||
.add("health potion", 6)
|
|
||||||
// Scrolls
|
// Scrolls
|
||||||
|
.add_table(scroll_table(map_depth))
|
||||||
|
// Wands
|
||||||
|
.add_table(wand_table(map_depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn equipment_table(_map_depth: i32) -> RandomTable {
|
||||||
|
return RandomTable::new().add("dagger", 4).add("shortsword", 2).add("buckler", 4).add("shield", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn potion_table(_map_depth: i32) -> RandomTable {
|
||||||
|
return RandomTable::new().add("weak health potion", 14).add("health potion", 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_table(_map_depth: i32) -> RandomTable {
|
||||||
|
return RandomTable::new()
|
||||||
.add("fireball scroll", 2)
|
.add("fireball scroll", 2)
|
||||||
.add("cursed fireball scroll", 2)
|
.add("cursed fireball scroll", 2)
|
||||||
.add("confusion scroll", 4)
|
.add("confusion scroll", 4)
|
||||||
.add("magic missile scroll", 10)
|
.add("magic missile scroll", 10)
|
||||||
.add("magic map scroll", 4)
|
.add("magic map scroll", 4)
|
||||||
.add("cursed magic map scroll", 2)
|
.add("cursed magic map scroll", 2);
|
||||||
// Wands
|
|
||||||
.add("magic missile wand", 1)
|
|
||||||
.add("fireball wand", 1)
|
|
||||||
.add("confusion wand", 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn food_table(_map_depth: i32) -> RandomTable {
|
pub fn wand_table(_map_depth: i32) -> RandomTable {
|
||||||
|
return RandomTable::new().add("magic missile wand", 1).add("fireball wand", 1).add("confusion wand", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn food_table(_map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("rations", 1).add("apple", 1);
|
return RandomTable::new().add("rations", 1).add("apple", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trap_table(_map_depth: i32) -> RandomTable {
|
pub fn trap_table(_map_depth: i32) -> RandomTable {
|
||||||
return RandomTable::new().add("bear trap", 0).add("confusion trap", 1);
|
return RandomTable::new().add("bear trap", 2).add("confusion trap", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn door(ecs: &mut World, x: i32, y: i32) {
|
fn door(ecs: &mut World, x: i32, y: i32) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue