more work on tavern

This commit is contained in:
Isse 2023-10-16 01:51:30 +02:00
parent 9903b53105
commit 4fa52db71d
8 changed files with 530 additions and 31 deletions

View File

@ -207,7 +207,9 @@ impl BlocksOfInterest {
)
.with_z(0.0),
)),
Some(SpriteKind::Sign) => interactables.push((pos, Interaction::Read)),
Some(SpriteKind::Sign | SpriteKind::HangingSign) => {
interactables.push((pos, Interaction::Read))
},
_ if block.is_mountable() => interactables.push((pos, Interaction::Mount)),
_ => {},
},

View File

@ -689,4 +689,163 @@ impl<'a, R: Rng> NameGen<'a, R> {
];
self.generate_theme_from_parts(&start, &middle, &vowel, &end)
}
pub fn generate_tavern(&mut self) -> String {
let adjectives = [
"Crazy",
"Big",
"Tiny",
"Slimy",
"Warm",
"Rigid",
"Soft",
"Wet",
"Humid",
"Smelly",
"Hidden",
"Smart",
"Fragile",
"Strong",
"Weak",
"Happy",
"Sad",
"Glad",
"Scared",
"Emberrassed",
"Goofy",
"Spicy",
"Salty",
"Peaceful",
"Awful",
"Sweet",
"Colossal",
"Puzzled",
"Cheap",
"Valuable",
"Rich",
"Obnoxious",
"Puzzled",
"Snoring",
"Fast",
"Quick",
"Magical",
"Violet",
"Red",
"Blue",
"Green",
"Yellow",
"Golden",
"Shiny",
"Tired",
"Twin",
"Incompetent",
"Light",
"Dark",
"Glorious",
"Best",
"Free",
"Odd",
"Juicy",
"Shaking",
"Tall",
"Short",
"Precious",
"Regular",
"Slow",
"Anxious",
"Naive",
"Sore",
"Next",
"Silver",
"Secret",
"Honorable",
"Rapid",
"Sleepy",
"Lying",
"Zesty",
"Fancy",
"Stylish",
];
let tavern_synonyms = ["Tavern", "Bar", "Pub"];
let subjectives = [
"Apple",
"Pumpkin",
"Cucumber",
"Squash",
"Demons",
"Mango",
"Coconut",
"Cats",
"Hill",
"Mountain",
"Squirrel",
"Rabbit",
"Moose",
"Driggle",
"Iron",
"Velorite",
"Plate",
"Eagle",
"Birds",
"Drumstick",
"Dog",
"Tiger",
"Knight",
"Leader",
"Huntress",
"Hunter",
"Dwarf",
"Toad",
"Clams",
"Bell",
"Avocado",
"Egg",
"Spade",
"Stream",
"Cabbage",
"Tomato",
"Rapier",
"Katana",
"Whisper",
"Hammer",
"Axe",
"Sword",
"Saurok",
"Danari",
"Elf",
"Human",
"Draugr",
"Orc",
"Pie",
"Stick",
"Rope",
"Knife",
"Shield",
"Bow",
"Spear",
"Staff",
"Crow",
"Crown",
"Parrot",
"Parrots",
"Pelican",
"Whale",
"Cube",
"Minotaur",
"Oni",
"Monster",
];
let kind = self.rng.gen_range(0..10);
let mut choose = |slice: &[&'static str]| *slice.choose(self.rng).unwrap();
match kind {
0 => format!("The {} {}", choose(&adjectives), choose(&tavern_synonyms)),
1..=7 => format!("The {} {}", choose(&adjectives), choose(&subjectives)),
_ => format!(
"The {} {} {}",
choose(&adjectives),
choose(&subjectives),
choose(&tavern_synonyms)
),
}
}
}

View File

@ -939,7 +939,7 @@ impl Site {
&mut reseed(&mut rng),
&site,
door_tile,
Dir::from_vector(door_dir),
Dir::from_vec2(door_dir),
aabr,
);
let tavern_alt = tavern.door_wpos.z;

View File

@ -129,7 +129,7 @@ impl AdletStronghold {
let mut outer_structures = Vec::<(AdletStructure, Vec2<i32>, Dir)>::new();
let entrance_dir = Dir::from_vector(entrance - cavern_center);
let entrance_dir = Dir::from_vec2(entrance - cavern_center);
outer_structures.push((AdletStructure::TunnelEntrance, Vec2::zero(), entrance_dir));
let desired_structures = surface_radius.pow(2) / 100;
@ -176,7 +176,7 @@ impl AdletStronghold {
Some((structure_center, structure_kind))
}
}) {
let dir_to_wall = Dir::from_vector(rpos);
let dir_to_wall = Dir::from_vec2(rpos);
let door_rng: u32 = rng.gen_range(0..9);
let door_dir = match door_rng {
0..=3 => dir_to_wall,
@ -352,7 +352,7 @@ impl AdletStronghold {
.then_some((structure, rpos))
}) {
// Direction facing the central bonfire
let dir = Dir::from_vector(rpos).opposite();
let dir = Dir::from_vec2(rpos).opposite();
cavern_structures.push((structure, rpos, dir));
}
}
@ -493,7 +493,7 @@ impl Structure for AdletStronghold {
// Tunnel
let dist: f32 = self.cavern_center.as_().distance(self.entrance.as_());
let dir = Dir::from_vector(self.entrance - self.cavern_center);
let dir = Dir::from_vec2(self.entrance - self.cavern_center);
let tunnel_start: Vec3<f32> = match dir {
Dir::X => Vec2::new(self.entrance.x + 7, self.entrance.y),
Dir::Y => Vec2::new(self.entrance.x, self.entrance.y + 7),

View File

@ -884,7 +884,7 @@ impl Bridge {
let min_water_dist = 5;
let find_edge = |start: Vec2<i32>, end: Vec2<i32>| {
let mut test_start = start;
let dir = Dir::from_vector(end - start).to_vec2();
let dir = Dir::from_vec2(end - start).to_vec2();
let mut last_alt = if let Some(col) = land.column_sample(start, index) {
col.alt as i32
} else {
@ -938,7 +938,7 @@ impl Bridge {
start,
end,
center,
dir: Dir::from_vector(end.xy() - start.xy()),
dir: Dir::from_vec2(end.xy() - start.xy()),
kind: bridge,
biome: land
.get_chunk_wpos(center.xy())

View File

@ -237,7 +237,7 @@ impl GnarlingFortification {
))
}
}) {
let dir_to_center = Dir::from_vector(hut_loc.xy()).opposite();
let dir_to_center = Dir::from_vec2(hut_loc.xy()).opposite();
let door_rng: u32 = rng.gen_range(0..9);
let door_dir = match door_rng {
0..=3 => dir_to_center,
@ -262,7 +262,7 @@ impl GnarlingFortification {
let chieftain_hut_loc = ((inner_tower_locs[0] + inner_tower_locs[1])
+ 2 * outer_wall_corners[chieftain_indices[1]])
/ 4;
let chieftain_hut_ori = Dir::from_vector(chieftain_hut_loc).opposite();
let chieftain_hut_ori = Dir::from_vec2(chieftain_hut_loc).opposite();
structure_locations.push((
GnarlingStructure::ChieftainHut,
chieftain_hut_loc.with_z(rpos_height(chieftain_hut_loc)),

View File

@ -1,9 +1,10 @@
use std::{cmp::Ordering, mem::swap, ops::RangeInclusive};
use common::{
comp::Content,
lottery::Lottery,
store::{Id, Store},
terrain::{Block, BlockKind, SpriteKind},
terrain::{Block, BlockKind, SpriteCfg, SpriteKind},
};
use enum_map::EnumMap;
use hashbrown::HashSet;
@ -12,7 +13,9 @@ use strum::{EnumIter, IntoEnumIterator};
use vek::*;
use crate::{
site2::{Dir, Fill, Site, Structure},
site::namegen,
site2::{gen::PrimitiveTransform, Dir, Fill, Site, Structure},
util::RandomField,
IndexRef, Land,
};
@ -66,6 +69,7 @@ struct Stairs {
}
pub struct Tavern {
name: String,
rooms: Store<Room>,
stairs: Store<Stairs>,
walls: Store<Wall>,
@ -204,7 +208,7 @@ impl Tavern {
top_alt: entrance_room_aabb.max.z,
from: None,
to: Some(entrance_id),
to_dir: door_dir,
to_dir: -door_dir,
door: Some(door_dir.rotated_cw().select(door_wpos.xy() - start).abs()),
});
rooms[entrance_id].walls[door_dir].push(wall_id);
@ -504,7 +508,7 @@ impl Tavern {
let p1 = n_room_bounds.projected_point(room_bounds.center());
let p0 = room_bounds.projected_point(p1);
let to_dir = Dir::from_vector(p1 - p0);
let to_dir = Dir::from_vec2(p1 - p0);
let intersection = to_dir
.extend_aabr(room_bounds, 1)
@ -566,31 +570,46 @@ impl Tavern {
// Compute detail areas
for room in rooms.values_mut() {
room.detail_areas.push(to_aabr(room.bounds));
let bounds = to_aabr(room.bounds);
let c = bounds.center();
let mut b = bounds.split_at_x(c.x);
b[0].max.x -= 1;
room.detail_areas.extend(b.into_iter().flat_map(|b| {
let mut b = b.split_at_y(c.y);
b[0].max.y -= 1;
b
}));
for (dir, dir_walls) in room.walls.iter() {
for door_pos in dir_walls.iter().filter_map(|wall_id| {
let wall = &walls[*wall_id];
wall.door.map(|door| {
let wall_dir = Dir::from_vector(wall.end - wall.start);
let wall_dir = Dir::from_vec2(wall.end - wall.start);
wall.start + wall_dir.to_vec2() * door
})
}) {
let orth = dir.orthogonal();
for i in 0..room.detail_areas.len() {
if let Some([a, b]) =
orth.try_split_aabr(room.detail_areas[i], orth.select(door_pos))
{
room.detail_areas[i] = a;
room.detail_areas.push(b);
let bc = room.detail_areas[i].center();
// Check if we are on the doors side of the center of the room.
if dir.select(bc - c) * dir.signum() >= 0 {
if let Some([a, b]) =
orth.try_split_aabr(room.detail_areas[i], orth.select(door_pos))
{
room.detail_areas[i] = orth.extend_aabr(a, -1);
room.detail_areas.push(orth.opposite().extend_aabr(b, -1));
}
}
}
room.detail_areas.retain(|area| area.is_valid());
}
}
room.detail_areas.retain(|area| area.size().product() >= 4);
}
let name = namegen::NameGen::location(rng).generate_tavern();
Self {
name,
rooms,
stairs,
walls,
@ -620,7 +639,9 @@ impl Structure for Tavern {
let stone = Fill::Brick(BlockKind::Rock, Rgb::new(70, 70, 70), 10);
let wood = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(106, 73, 64)));
let dark_wood = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(80, 53, 48)));
let field = RandomField::new(740384);
painter
.aabb(aabb(Aabb {
min: bounds.min.with_z(self.door_wpos.z - 10),
@ -637,20 +658,244 @@ impl Structure for Tavern {
}))
.fill(wood.clone());
let room_aabr = Aabr {
min: room.bounds.min.xy(),
max: room.bounds.max.xy(),
};
let table_set = |pos, bounds: Aabr<i32>| -> bool {
if bounds.size().reduce_min() >= 1 {
painter.sprite(pos, SpriteKind::TableDining);
for dir in Dir::iter() {
let pos = pos + dir.to_vec2();
if bounds.contains_point(pos.xy()) {
painter.rotated_sprite(
pos,
SpriteKind::ChairSingle,
dir.opposite().sprite_ori(),
);
}
}
true
} else {
false
}
};
for (i, aabr) in room.detail_areas.iter().enumerate() {
let color = fxhash::hash32(&i).to_le_bytes();
painter
.aabb(aabb(Aabb {
min: aabr.min.with_z(room.bounds.min.z - 1),
max: aabr.max.with_z(room.bounds.min.z - 1),
}))
.fill(Fill::Block(Block::new(
BlockKind::Rock,
Rgb::new(color[0], color[1], color[3]),
)));
}
match room.kind {
RoomKind::Garden => {
for aabr in room.detail_areas.iter() {
let pos = aabr.center().with_z(room.bounds.min.z);
if field.chance(pos, 0.6) {
table_set(pos, *aabr);
}
}
let dir = Dir::from_vec2(room_aabr.size().into());
painter
.aabb(aabb(Aabb {
min: dir
.select_aabr_with(room_aabr, room_aabr.min - 2)
.with_z(room.bounds.max.z + 1),
max: dir
.select_aabr_with(room_aabr, room_aabr.max + 2)
.with_z(room.bounds.max.z + 1),
}))
.repeat(
-dir.to_vec3() * 2,
(dir.select(room_aabr.size()) as u32 + 3) / 2,
)
.fill(dark_wood.clone())
},
RoomKind::StageRoom => {
let mut stage = None;
let mut stage_score = 0;
for aabr in room.detail_areas.iter() {
let edges = Dir::iter()
.filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr))
.count() as i32;
let test_stage_score = edges * aabr.size().product();
let Some(aabr) = (if stage_score < test_stage_score {
stage_score = test_stage_score;
stage.replace(*aabr)
} else {
Some(*aabr)
}) else {
continue;
};
table_set(aabr.center().with_z(room.bounds.min.z), aabr);
for dir in Dir::iter().filter(|dir| {
dir.select_aabr(aabr) == dir.select_aabr(room_aabr)
&& dir.rotated_cw().select_aabr(aabr)
== dir.rotated_cw().select_aabr(room_aabr)
}) {
let pos = dir.select_aabr_with(
aabr,
Vec2::broadcast(dir.rotated_cw().select_aabr(aabr)),
);
painter.sprite(pos.with_z(room.bounds.min.z), SpriteKind::StreetLamp);
}
}
if let Some(aabr) = stage {
painter
.aabb(aabb(Aabb {
min: aabr.min.with_z(room.bounds.min.z),
max: aabr.max.with_z(room.bounds.min.z),
}))
.fill(Fill::Sprite(SpriteKind::Apple))
.fill(stone.clone());
painter
.aabb(aabb(Aabb {
min: (aabr.min + 1).with_z(room.bounds.min.z),
max: (aabr.max - 1).with_z(room.bounds.min.z),
}))
.fill(wood.clone());
for dir in Dir::iter().filter(|dir| {
dir.select_aabr(aabr) != dir.select_aabr(room_aabr)
&& dir.rotated_cw().select_aabr(aabr)
!= dir.rotated_cw().select_aabr(room_aabr)
}) {
let pos = dir.select_aabr_with(
aabr,
Vec2::broadcast(dir.rotated_cw().select_aabr(aabr)),
);
painter
.column(pos, room.bounds.min.z..=room.bounds.max.z)
.fill(dark_wood.clone());
for dir in Dir::iter() {
painter.rotated_sprite(
pos.with_z(room.bounds.center().z + 1) + dir.to_vec2(),
SpriteKind::WallSconce,
dir.sprite_ori(),
);
}
}
}
},
RoomKind::BarRoom => {
let mut bar = None;
let mut bar_score = 0;
for aabr in room.detail_areas.iter() {
let test_stage_score = Dir::iter()
.any(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr))
as i32
* aabr.size().product();
let Some(aabr) = (if bar_score < test_stage_score {
bar_score = test_stage_score;
bar.replace(*aabr)
} else {
Some(*aabr)
}) else {
continue;
};
for dir in Dir::iter()
.filter(|dir| dir.select_aabr(aabr) == dir.select_aabr(room_aabr))
{
let pos = dir
.select_aabr_with(aabr, aabr.center())
.with_z(room.bounds.center().z);
painter.rotated_sprite(
pos,
SpriteKind::WallLampSmall,
dir.opposite().sprite_ori(),
);
}
}
if let Some(aabr) = bar {
for dir in Dir::iter() {
let edge = dir.select_aabr(aabr);
let rot_dir = if field.chance(aabr.center().with_z(0), 0.5) {
dir.rotated_cw()
} else {
dir.rotated_ccw()
};
let rot_edge = rot_dir.select_aabr(aabr);
match (
edge == dir.select_aabr(room_aabr),
rot_edge == rot_dir.select_aabr(room_aabr),
) {
(false, _) => {
let (min, max) = (
dir.select_aabr_with(
aabr,
Vec2::broadcast(rot_dir.select_aabr(aabr)),
),
dir.select_aabr_with(
aabr,
Vec2::broadcast(rot_dir.opposite().select_aabr(aabr)),
),
);
painter
.aabb(aabb(Aabb {
min: (min - rot_dir.to_vec2())
.with_z(room.bounds.min.z),
max: max.with_z(room.bounds.min.z),
}))
.fill(dark_wood.clone());
painter
.aabb(aabb(Aabb {
min: min.with_z(room.bounds.min.z + 3),
max: max.with_z(room.bounds.max.z),
}))
.fill(dark_wood.clone());
},
(true, true) => {
painter.sprite(
dir.vec2(edge, rot_edge).with_z(room.bounds.min.z),
SpriteKind::CookingPot,
);
},
(true, false) => {},
}
}
}
},
RoomKind::EntranceRoom => {
for aabr in room.detail_areas.iter() {
let edges = Dir::iter()
.filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr))
.count();
let hanger_pos = if edges == 2 {
let pos = aabr.center().with_z(room.bounds.min.z);
painter.sprite(pos, SpriteKind::CoatRack);
Some(pos)
} else {
None
};
for dir in Dir::iter()
.filter(|dir| dir.select_aabr(*aabr) == dir.select_aabr(room_aabr))
{
let pos = dir
.select_aabr_with(*aabr, aabr.center())
.with_z(room.bounds.center().z + 1);
if hanger_pos.map_or(false, |p| p.xy() != pos.xy()) {
painter.rotated_sprite(
pos,
SpriteKind::WallLampSmall,
dir.opposite().sprite_ori(),
);
}
}
}
},
RoomKind::StageRoom => {},
RoomKind::BarRoom => {},
RoomKind::EntranceRoom => {},
}
}
@ -660,27 +905,53 @@ impl Structure for Tavern {
min: wall.start.with_z(wall.base_alt),
max: wall.end.with_z(wall.top_alt),
};
let wall_dir = Dir::from_vec2(wall.end - wall.start);
match (wall.from.map(get_kind), wall.to.map(get_kind)) {
(Some(RoomKind::Garden), Some(RoomKind::Garden) | None)
| (None, Some(RoomKind::Garden)) => {
let hgt = wall_aabb.min.z..=wall_aabb.max.z;
painter
.column(wall_aabb.min.xy(), hgt.clone())
.fill(wood.clone());
painter.column(wall_aabb.max.xy(), hgt).fill(wood.clone());
.fill(dark_wood.clone());
painter
.column(wall_aabb.max.xy(), hgt)
.fill(dark_wood.clone());
let z = (wall.base_alt + wall.top_alt) / 2;
painter.rotated_sprite(
wall_aabb.min.with_z(z) + wall_dir.to_vec2(),
SpriteKind::WallSconce,
wall_dir.sprite_ori(),
);
painter.rotated_sprite(
wall_aabb.max.with_z(z) - wall_dir.to_vec2(),
SpriteKind::WallSconce,
wall_dir.opposite().sprite_ori(),
);
painter
.aabb(aabb(Aabb {
min: wall_aabb.min,
max: wall_aabb.max.with_z(wall_aabb.min.z),
}))
.fill(wood.clone());
.fill(dark_wood.clone());
painter
.aabb(aabb(Aabb {
min: wall_aabb.min.with_z(wall_aabb.max.z),
max: wall_aabb.max,
}))
.fill(dark_wood.clone());
},
(None, None) => {},
_ => {
painter.aabb(aabb(wall_aabb)).fill(wood.clone());
painter
.column(wall.start, wall.base_alt..=wall.top_alt)
.fill(dark_wood.clone());
painter
.column(wall.end, wall.base_alt..=wall.top_alt)
.fill(dark_wood.clone());
},
}
let wall_dir = Dir::from_vector(wall.end - wall.start);
if let Some(door) = wall.door {
let door_pos = wall.start + wall_dir.to_vec2() * door;
let min = match wall.from {
@ -698,6 +969,64 @@ impl Structure for Tavern {
}))
.clear();
}
if let (Some(room), to @ None) | (None, to @ Some(room)) =
(wall.from.map(get_kind), wall.to.map(get_kind))
{
let dir = if to.is_none() {
-wall.to_dir
} else {
wall.to_dir
};
let width = dir.orthogonal().select(wall.end - wall.start).abs();
let wall_center = (wall.start + wall.end) / 2;
let d = wall_dir.select(wall_center - wall.start) * wall_dir.signum();
match room {
RoomKind::Garden => {
if wall.door.map_or(true, |door| (door - d).abs() >= 2) {
painter.rotated_sprite(
wall_center.with_z(wall.base_alt + 1),
SpriteKind::Planter,
dir.sprite_ori(),
);
}
},
_ => {
if width >= 5 && wall.door.map_or(true, |door| (door - d).abs() > 3) {
painter
.aabb(aabb(Aabb {
min: (wall_center + dir.rotated_ccw().to_vec2())
.with_z(wall.base_alt + 1),
max: (wall_center + dir.rotated_cw().to_vec2())
.with_z(wall.base_alt + 2),
}))
.fill(Fill::RotatedSprite(SpriteKind::Window1, dir.sprite_ori()));
}
},
}
if let Some(door) = wall.door {
let door_pos = wall.start + wall_dir.to_vec2() * door;
let diff = door_pos - wall_aabb.center().xy();
let orth = if diff == Vec2::zero() {
wall_dir
} else {
Dir::from_vec2(diff)
};
let pos = door_pos - dir.to_vec2() + orth.to_vec2();
let (sprite, z) = match room {
RoomKind::Garden => (SpriteKind::Sign, 0),
_ => (SpriteKind::HangingSign, 2),
};
painter.rotated_sprite_with_cfg(
pos.with_z(wall.base_alt + z),
sprite,
dir.opposite().sprite_ori(),
SpriteCfg {
unlock: None,
content: Some(Content::Plain(self.name.clone())),
},
);
}
}
}
for (_, stairs) in self.stairs.iter() {

View File

@ -26,7 +26,7 @@ impl Dir {
}
}
pub fn from_vector(vec: Vec2<i32>) -> Dir {
pub fn from_vec2(vec: Vec2<i32>) -> Dir {
if vec.x.abs() > vec.y.abs() {
if vec.x > 0 { Dir::X } else { Dir::NegX }
} else if vec.y > 0 {
@ -110,6 +110,15 @@ impl Dir {
}
}
pub fn vec2(self, x: i32, y: i32) -> Vec2<i32> {
match self {
Dir::X => Vec2::new(x, y),
Dir::NegX => Vec2::new(x, y),
Dir::Y => Vec2::new(y, x),
Dir::NegY => Vec2::new(y, x),
}
}
/// Returns a 3x3 matrix that rotates Vec3(1, 0, 0) to the direction you get
/// in to_vec3. Inteded to be used with Primitive::Rotate.
///