mirror of
https://gitlab.com/veloren/veloren.git
synced 2025-07-26 05:12:29 +00:00
more_airship_docks
This commit is contained in:
@ -45,7 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Npcs can catch you stealing.
|
||||
- Button to show unknown recipes.
|
||||
- Water splashes and river particles.
|
||||
- Custom furniture for Coastal Houses
|
||||
- Custom furniture for Coastal Houses.
|
||||
- Airship docks for desert cities, coastal towns and mesa towns.
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
common-signs-keep_out = Keep Out!
|
||||
common-signs-airship_dock = Service interrupted!
|
||||
|
@ -1,18 +0,0 @@
|
||||
/// Distribution of different dungeon levels.
|
||||
///
|
||||
/// first number is dungeon level, integer
|
||||
/// second number is weight, any normal positive float (not a NaN, for example)
|
||||
///
|
||||
/// Values are relative to each other,
|
||||
/// lesser weight means there will be less dungeons of that tier.
|
||||
///
|
||||
/// General rules:
|
||||
/// 1) Weight should not be less then zero
|
||||
/// 2) At least some of weights shouldn't be a zero
|
||||
/// 3) Keep it synced with number of dungeon levels
|
||||
/// 4) Keep these pairs sorted from lowest to highest tier
|
||||
///
|
||||
/// Tips:
|
||||
/// 1) Set every probability to 0.0 and left one with any other number
|
||||
/// and you will have map full of dungeons of same level
|
||||
([])
|
@ -1,16 +0,0 @@
|
||||
#![enable(unwrap_newtypes)]
|
||||
|
||||
[
|
||||
(
|
||||
specifier: "world.structure.dungeon.desert_entrance.1",
|
||||
center: (35, 50, 21)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.desert_entrance.2",
|
||||
center: (21, 21, 41)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.desert_entrance.3",
|
||||
center: (32, 31, 28)
|
||||
),
|
||||
]
|
@ -1,44 +0,0 @@
|
||||
#![enable(unwrap_newtypes)]
|
||||
|
||||
[
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.round.1",
|
||||
center: (21, 17, 28)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.round.2",
|
||||
center: (20, 28, 15)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.1",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.2",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.3",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.4",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.5",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.pillar_entrance.6",
|
||||
center: (18, 16, 17)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.temperate_entrance.ruins_4",
|
||||
center: (13, 11, 14)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.misc_entrance.tower-ruin",
|
||||
center: (13, 16, 9)
|
||||
),
|
||||
]
|
@ -1,16 +0,0 @@
|
||||
#![enable(unwrap_newtypes)]
|
||||
|
||||
[
|
||||
(
|
||||
specifier: "world.structure.dungeon.jungle_entrance.1",
|
||||
center: (50, 40, 10)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.jungle_entrance.2",
|
||||
center: (60, 36, 36)
|
||||
),
|
||||
(
|
||||
specifier: "world.structure.dungeon.jungle_entrance.3",
|
||||
center: (24, 22, 44)
|
||||
),
|
||||
]
|
BIN
assets/world/structure/dungeon/desert_entrance/1.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/desert_entrance/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/desert_entrance/2.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/desert_entrance/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/desert_entrance/3.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/desert_entrance/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/jungle_entrance/1.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/jungle_entrance/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/jungle_entrance/2.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/jungle_entrance/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/jungle_entrance/3.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/jungle_entrance/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/misc_entrance/tower-ruin.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/misc_entrance/tower-ruin.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/1.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/2.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/3.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/4.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/5.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/6.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/6.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/round/1.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/round/1.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/pillar_entrance/round/2.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/pillar_entrance/round/2.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/temperate_entrance/ruins_4.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/temperate_entrance/ruins_4.vox
(Stored with Git LFS)
Binary file not shown.
@ -1231,7 +1231,11 @@ fn pilot<S: State>(ship: common::comp::ship::Body) -> impl Action<S> {
|
||||
.filter(|plot| {
|
||||
matches!(
|
||||
plot.kind(),
|
||||
PlotKind::AirshipDock(_) | PlotKind::SavannahAirshipDock(_)
|
||||
PlotKind::AirshipDock(_)
|
||||
| PlotKind::SavannahAirshipDock(_)
|
||||
| PlotKind::DesertCityAirshipDock(_)
|
||||
| PlotKind::CoastalAirshipDock(_)
|
||||
| PlotKind::CliffTownAirshipDock(_)
|
||||
)
|
||||
})
|
||||
.map(|plot| site.tile_center_wpos(plot.root_tile()))
|
||||
|
@ -2162,6 +2162,8 @@ impl SiteKind {
|
||||
},
|
||||
SiteKind::DesertCity => {
|
||||
(0.9..1.0).contains(&chunk.temp) && !chunk.near_cliffs() && suitable_for_town()
|
||||
&& on_land()
|
||||
&& !chunk.river.near_water()
|
||||
},
|
||||
SiteKind::ChapelSite => {
|
||||
matches!(chunk.get_biome(), BiomeKind::Ocean)
|
||||
|
@ -1358,39 +1358,87 @@ impl Site {
|
||||
};
|
||||
let mut campfires = 0;
|
||||
site.make_plaza(land, &mut rng);
|
||||
for _ in 0..30 {
|
||||
// CliffTower
|
||||
let size = (9.0 + rng.gen::<f32>().powf(5.0) * 1.0).round() as u32;
|
||||
let campfire = campfires < 4;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(&mut rng, 8..(size + 1).pow(2), Extent2::broadcast(size))
|
||||
}) {
|
||||
let cliff_tower = plot::CliffTower::generate(
|
||||
land,
|
||||
index,
|
||||
&mut reseed(&mut rng),
|
||||
&site,
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
campfire,
|
||||
);
|
||||
let cliff_tower_alt = cliff_tower.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::CliffTower(cliff_tower),
|
||||
root_tile: aabr.center(),
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
});
|
||||
let build_chance = Lottery::from(vec![(30.0, 1), (50.0, 2)]);
|
||||
let mut airship_docks = 0;
|
||||
for _ in 0..80 {
|
||||
match *build_chance.choose_seeded(rng.gen()) {
|
||||
1 => {
|
||||
// CliffTower
|
||||
let size = (9.0 + rng.gen::<f32>().powf(5.0) * 1.0).round() as u32;
|
||||
let campfire = campfires < 4;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(
|
||||
&mut rng,
|
||||
8..(size + 1).pow(2),
|
||||
Extent2::broadcast(size),
|
||||
)
|
||||
}) {
|
||||
let cliff_tower = plot::CliffTower::generate(
|
||||
land,
|
||||
index,
|
||||
&mut reseed(&mut rng),
|
||||
&site,
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
campfire,
|
||||
);
|
||||
let cliff_tower_alt = cliff_tower.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::CliffTower(cliff_tower),
|
||||
root_tile: aabr.center(),
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(cliff_tower_alt),
|
||||
});
|
||||
campfires += 1;
|
||||
} else {
|
||||
site.make_plaza(land, &mut rng);
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(cliff_tower_alt),
|
||||
});
|
||||
campfires += 1;
|
||||
} else {
|
||||
site.make_plaza(land, &mut rng);
|
||||
}
|
||||
},
|
||||
2 if airship_docks < 1 => {
|
||||
// CliffTownAirshipDock
|
||||
let size = (9.0 + rng.gen::<f32>().powf(5.0) * 1.0).round() as u32;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(
|
||||
&mut rng,
|
||||
8..(size + 1).pow(2),
|
||||
Extent2::broadcast(size),
|
||||
)
|
||||
}) {
|
||||
let cliff_town_airship_dock = plot::CliffTownAirshipDock::generate(
|
||||
land,
|
||||
index,
|
||||
&mut reseed(&mut rng),
|
||||
&site,
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
);
|
||||
let cliff_town_airship_dock_alt = cliff_town_airship_dock.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::CliffTownAirshipDock(cliff_town_airship_dock),
|
||||
root_tile: aabr.center(),
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(cliff_town_airship_dock_alt),
|
||||
});
|
||||
airship_docks += 1;
|
||||
} else {
|
||||
site.make_plaza(land, &mut rng);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1410,7 +1458,7 @@ impl Site {
|
||||
site.make_plaza(land, &mut rng);
|
||||
|
||||
let mut airship_dock = 0;
|
||||
let build_chance = Lottery::from(vec![(25.0, 1), (7.0, 2), (3.0, 3), (15.0, 4)]);
|
||||
let build_chance = Lottery::from(vec![(25.0, 1), (5.0, 2), (5.0, 3), (15.0, 4)]);
|
||||
|
||||
for _ in 0..50 {
|
||||
match *build_chance.choose_seeded(rng.gen()) {
|
||||
@ -1489,7 +1537,7 @@ impl Site {
|
||||
3 if airship_dock < 1 => {
|
||||
// SavannahAirshipDock
|
||||
|
||||
let size = (4.0 + rng.gen::<f32>().powf(5.0) * 1.5).round() as u32;
|
||||
let size = (6.0 + rng.gen::<f32>().powf(5.0) * 1.5).round() as u32;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(
|
||||
&mut rng,
|
||||
@ -1518,10 +1566,10 @@ impl Site {
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(savannah_airship_dock_alt),
|
||||
});
|
||||
airship_dock += 1;
|
||||
} else {
|
||||
site.make_plaza(land, &mut rng);
|
||||
}
|
||||
airship_dock += 1;
|
||||
},
|
||||
// Field
|
||||
4 => {
|
||||
@ -1543,9 +1591,9 @@ impl Site {
|
||||
site.demarcate_obstacles(land);
|
||||
|
||||
site.make_plaza(land, &mut rng);
|
||||
let build_chance = Lottery::from(vec![(38.0, 1), (7.0, 2), (15.0, 3)]);
|
||||
|
||||
for _ in 0..45 {
|
||||
let build_chance = Lottery::from(vec![(38.0, 1), (7.0, 2), (15.0, 3), (15.0, 4)]);
|
||||
let mut airship_docks = 0;
|
||||
for _ in 0..55 {
|
||||
match *build_chance.choose_seeded(rng.gen()) {
|
||||
1 => {
|
||||
// CoastalHouse
|
||||
@ -1619,8 +1667,44 @@ impl Site {
|
||||
site.make_plaza(land, &mut rng);
|
||||
}
|
||||
},
|
||||
3 if airship_docks < 1 => {
|
||||
// CoastalAirshipDock
|
||||
let size = (7.0 + rng.gen::<f32>().powf(5.0) * 1.5).round() as u32;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(
|
||||
&mut rng,
|
||||
7..(size + 1).pow(2),
|
||||
Extent2::broadcast(size),
|
||||
)
|
||||
}) {
|
||||
let coastal_airship_dock = plot::CoastalAirshipDock::generate(
|
||||
land,
|
||||
&mut reseed(&mut rng),
|
||||
&site,
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
);
|
||||
let coastal_airship_dock_alt = coastal_airship_dock.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::CoastalAirshipDock(coastal_airship_dock),
|
||||
root_tile: aabr.center(),
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(coastal_airship_dock_alt),
|
||||
});
|
||||
airship_docks += 1;
|
||||
} else {
|
||||
site.make_plaza(land, &mut rng);
|
||||
}
|
||||
},
|
||||
// Field
|
||||
3 => {
|
||||
4 => {
|
||||
Self::generate_farm(false, &mut rng, &mut site, land);
|
||||
},
|
||||
_ => {},
|
||||
@ -1665,12 +1749,13 @@ impl Site {
|
||||
hard_alt: Some(desert_city_arena_alt),
|
||||
});
|
||||
|
||||
let build_chance = Lottery::from(vec![(20.0, 1), (10.0, 2), (10.0, 3)]);
|
||||
let build_chance = Lottery::from(vec![(20.0, 1), (10.0, 2), (5.0, 3), (10.0, 4)]);
|
||||
|
||||
let mut temples = 0;
|
||||
let mut airship_docks = 0;
|
||||
let mut campfires = 0;
|
||||
|
||||
for _ in 0..30 {
|
||||
for _ in 0..35 {
|
||||
match *build_chance.choose_seeded(rng.gen()) {
|
||||
// DesertCityMultiplot
|
||||
1 => {
|
||||
@ -1744,8 +1829,42 @@ impl Site {
|
||||
temples += 1;
|
||||
}
|
||||
},
|
||||
// DesertCityAirshipDock
|
||||
3 if airship_docks < 1 => {
|
||||
let size = (6.0 + rng.gen::<f32>().powf(5.0) * 1.5).round() as u32;
|
||||
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
|
||||
site.find_roadside_aabr(
|
||||
&mut rng,
|
||||
8..(size + 1).pow(2),
|
||||
Extent2::broadcast(size),
|
||||
)
|
||||
}) {
|
||||
let desert_city_airship_dock = plot::DesertCityAirshipDock::generate(
|
||||
land,
|
||||
&mut reseed(&mut rng),
|
||||
&site,
|
||||
door_tile,
|
||||
door_dir,
|
||||
aabr,
|
||||
);
|
||||
let desert_city_airship_dock_alt = desert_city_airship_dock.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::DesertCityAirshipDock(desert_city_airship_dock),
|
||||
root_tile: aabr.center(),
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
hard_alt: Some(desert_city_airship_dock_alt),
|
||||
});
|
||||
airship_docks += 1;
|
||||
}
|
||||
},
|
||||
// cactus farm
|
||||
3 => {
|
||||
4 => {
|
||||
Self::generate_farm(true, &mut rng, &mut site, land);
|
||||
},
|
||||
_ => {},
|
||||
@ -2491,6 +2610,9 @@ impl Site {
|
||||
},
|
||||
PlotKind::GliderFinish(glider_finish) => glider_finish.render_collect(self, canvas),
|
||||
PlotKind::Tavern(tavern) => tavern.render_collect(self, canvas),
|
||||
PlotKind::CoastalAirshipDock(coastal_airship_dock) => {
|
||||
coastal_airship_dock.render_collect(self, canvas)
|
||||
},
|
||||
PlotKind::CoastalHouse(coastal_house) => coastal_house.render_collect(self, canvas),
|
||||
PlotKind::CoastalWorkshop(coastal_workshop) => {
|
||||
coastal_workshop.render_collect(self, canvas)
|
||||
@ -2504,6 +2626,9 @@ impl Site {
|
||||
PlotKind::Haniwa(haniwa) => haniwa.render_collect(self, canvas),
|
||||
PlotKind::GiantTree(giant_tree) => giant_tree.render_collect(self, canvas),
|
||||
PlotKind::CliffTower(cliff_tower) => cliff_tower.render_collect(self, canvas),
|
||||
PlotKind::CliffTownAirshipDock(cliff_town_airship_dock) => {
|
||||
cliff_town_airship_dock.render_collect(self, canvas)
|
||||
},
|
||||
PlotKind::Sahagin(sahagin) => sahagin.render_collect(self, canvas),
|
||||
PlotKind::SavannahAirshipDock(savannah_airship_dock) => {
|
||||
savannah_airship_dock.render_collect(self, canvas)
|
||||
@ -2541,6 +2666,9 @@ impl Site {
|
||||
PlotKind::DesertCityArena(desert_city_arena) => {
|
||||
desert_city_arena.render_collect(self, canvas)
|
||||
},
|
||||
PlotKind::DesertCityAirshipDock(desert_city_airship_dock) => {
|
||||
desert_city_airship_dock.render_collect(self, canvas)
|
||||
},
|
||||
PlotKind::Citadel(citadel) => citadel.render_collect(self, canvas),
|
||||
PlotKind::Bridge(bridge) => bridge.render_collect(self, canvas),
|
||||
PlotKind::PirateHideout(pirate_hideout) => {
|
||||
|
@ -4,18 +4,25 @@ use crate::{
|
||||
util::{RandomField, Sampler},
|
||||
Land,
|
||||
};
|
||||
use common::terrain::{Block, BlockKind, SpriteKind};
|
||||
use common::{
|
||||
comp::Content,
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteCfg, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
/// Represents house data generated by the `generate()` method
|
||||
pub struct AirshipDock {
|
||||
/// Axis aligned bounding region for the house
|
||||
bounds: Aabr<i32>,
|
||||
/// Approximate altitude of the door tile
|
||||
pub(crate) alt: i32,
|
||||
rotation: f32,
|
||||
pub door_tile: Vec2<i32>,
|
||||
center: Vec2<i32>,
|
||||
base: i32,
|
||||
height: i32,
|
||||
pub docking_positions: Vec<Vec3<i32>>,
|
||||
campfire_pos: Vec3<i32>,
|
||||
}
|
||||
|
||||
impl AirshipDock {
|
||||
@ -32,6 +39,10 @@ impl AirshipDock {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
let center = bounds.center();
|
||||
let alt = land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32;
|
||||
let base = alt + 3;
|
||||
let height = base + 28;
|
||||
let rotation = if door_dir.y < 0 {
|
||||
PI
|
||||
} else if door_dir.x < 0 {
|
||||
@ -41,12 +52,20 @@ impl AirshipDock {
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let docking_positions = vec![
|
||||
(center + (door_dir * 16)).with_z(height + 9),
|
||||
(center - (door_dir * 21)).with_z(height + 9),
|
||||
];
|
||||
let campfire_pos = (center - (door_dir * 10)).with_z(height + 9);
|
||||
Self {
|
||||
door_tile: door_tile_pos,
|
||||
bounds,
|
||||
alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32,
|
||||
alt,
|
||||
rotation,
|
||||
center,
|
||||
base,
|
||||
height,
|
||||
docking_positions,
|
||||
campfire_pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,11 +80,9 @@ impl Structure for AirshipDock {
|
||||
let wood = Fill::Brick(BlockKind::Rock, Rgb::new(45, 28, 21), 24);
|
||||
let woodalt = Fill::Brick(BlockKind::Rock, Rgb::new(30, 22, 15), 24);
|
||||
|
||||
let base = self.alt + 3;
|
||||
let center = self.bounds.center();
|
||||
let height = base + 28;
|
||||
|
||||
//rotation
|
||||
let base = self.base;
|
||||
let center = self.center;
|
||||
let height = self.height;
|
||||
|
||||
//lower doorway
|
||||
painter
|
||||
@ -724,5 +741,17 @@ impl Structure for AirshipDock {
|
||||
)));
|
||||
}
|
||||
}
|
||||
// campfire
|
||||
painter.spawn(
|
||||
EntityInfo::at(self.campfire_pos.map(|e| e as f32 + 0.5))
|
||||
.into_special(SpecialEntity::Waypoint),
|
||||
);
|
||||
// dock
|
||||
for dock_pos in &self.docking_positions {
|
||||
painter.rotated_sprite_with_cfg(*dock_pos, SpriteKind::Sign, 2, SpriteCfg {
|
||||
unlock: None,
|
||||
content: Some(Content::localized("common-signs-airship_dock")),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
590
world/src/site2/plot/cliff_town_airship_dock.rs
Normal file
590
world/src/site2/plot/cliff_town_airship_dock.rs
Normal file
@ -0,0 +1,590 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
site2::util::gradient::WrapMode,
|
||||
util::{RandomField, Sampler, DIAGONALS, LOCALITY, NEIGHBORS},
|
||||
Land,
|
||||
};
|
||||
use common::{
|
||||
comp::Content,
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteCfg, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::{f32::consts::TAU, mem};
|
||||
use vek::*;
|
||||
|
||||
/// Represents house data generated by the `generate()` method
|
||||
pub struct CliffTownAirshipDock {
|
||||
/// Tile position of the door tile
|
||||
pub door_tile: Vec2<i32>,
|
||||
/// Approximate altitude of the door tile
|
||||
pub(crate) alt: i32,
|
||||
door_dir: Vec2<i32>,
|
||||
surface_color: Rgb<f32>,
|
||||
sub_surface_color: Rgb<f32>,
|
||||
center: Vec2<i32>,
|
||||
variant: i32,
|
||||
storeys: i32,
|
||||
platform_length: i32,
|
||||
pub docking_positions: Vec<Vec3<i32>>,
|
||||
}
|
||||
|
||||
impl CliffTownAirshipDock {
|
||||
pub fn generate(
|
||||
land: &Land,
|
||||
index: IndexRef,
|
||||
_rng: &mut impl Rng,
|
||||
site: &Site,
|
||||
door_tile: Vec2<i32>,
|
||||
door_dir: Vec2<i32>,
|
||||
tile_aabr: Aabr<i32>,
|
||||
) -> Self {
|
||||
let door_tile_pos = site.tile_center_wpos(door_tile);
|
||||
let bounds = Aabr {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
let center = bounds.center();
|
||||
let alt = land.get_alt_approx(door_tile_pos) as i32;
|
||||
let variant = 15;
|
||||
let storeys = 5 + (variant / 2);
|
||||
let platform_length = 2 * variant;
|
||||
let mut docking_positions = vec![];
|
||||
let mut platform_level = alt - 40;
|
||||
let mut platform_height = 18 + variant / 2;
|
||||
for s in 0..storeys {
|
||||
if s == (storeys - 1) {
|
||||
for dir in CARDINALS {
|
||||
let docking_pos = center + dir * (platform_length + 7);
|
||||
docking_positions.push(docking_pos.with_z(platform_level + 1));
|
||||
}
|
||||
}
|
||||
platform_height += -1;
|
||||
platform_level += platform_height;
|
||||
}
|
||||
|
||||
let (surface_color, sub_surface_color) =
|
||||
if let Some(sample) = land.column_sample(bounds.center(), index) {
|
||||
(sample.surface_color, sample.sub_surface_color)
|
||||
} else {
|
||||
(Rgb::new(161.0, 116.0, 86.0), Rgb::new(88.0, 64.0, 64.0))
|
||||
};
|
||||
Self {
|
||||
door_tile: door_tile_pos,
|
||||
alt,
|
||||
door_dir,
|
||||
surface_color,
|
||||
sub_surface_color,
|
||||
center,
|
||||
variant,
|
||||
storeys,
|
||||
platform_length,
|
||||
docking_positions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for CliffTownAirshipDock {
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"render_cliff_town_airship_dock\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_cliff_town_airship_dock")]
|
||||
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||
let base = self.alt;
|
||||
let plot_center = self.center;
|
||||
let door_dir = self.door_dir;
|
||||
|
||||
let surface_color = self.surface_color.map(|e| (e * 255.0) as u8);
|
||||
let sub_surface_color = self.sub_surface_color.map(|e| (e * 255.0) as u8);
|
||||
let gradient_center = Vec3::new(
|
||||
plot_center.x as f32,
|
||||
plot_center.y as f32,
|
||||
(base + 1) as f32,
|
||||
);
|
||||
let gradient_var_1 = RandomField::new(0).get(plot_center.with_z(base)) as i32 % 8;
|
||||
let gradient_var_2 = RandomField::new(0).get(plot_center.with_z(base + 1)) as i32 % 10;
|
||||
|
||||
let brick = Fill::Gradient(
|
||||
util::gradient::Gradient::new(
|
||||
gradient_center,
|
||||
8.0 + gradient_var_1 as f32,
|
||||
util::gradient::Shape::Point,
|
||||
(surface_color, sub_surface_color),
|
||||
)
|
||||
.with_repeat(if gradient_var_2 > 5 {
|
||||
WrapMode::Repeat
|
||||
} else {
|
||||
WrapMode::PingPong
|
||||
}),
|
||||
BlockKind::Rock,
|
||||
);
|
||||
|
||||
let wood = Fill::Brick(BlockKind::Wood, Rgb::new(106, 83, 51), 12);
|
||||
let color = Fill::Block(Block::air(SpriteKind::CliffDecorBlock));
|
||||
let window = Fill::Block(Block::air(SpriteKind::WindowArabic));
|
||||
let window2 = Fill::Block(Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap());
|
||||
let rope = Fill::Block(Block::air(SpriteKind::Rope));
|
||||
|
||||
let tube_var = RandomField::new(0).get(plot_center.with_z(base)) as i32 % 6;
|
||||
let radius = 10.0 + tube_var as f32;
|
||||
let tubes = 3.0 + tube_var as f32;
|
||||
let phi = TAU / tubes;
|
||||
for n in 1..=tubes as i32 {
|
||||
let center = Vec2::new(
|
||||
plot_center.x + (radius * ((n as f32 * phi).cos())) as i32,
|
||||
plot_center.y + (radius * ((n as f32 * phi).sin())) as i32,
|
||||
);
|
||||
// common superquadric degree for rooms
|
||||
let sq_type = 3.5;
|
||||
let storeys = self.storeys;
|
||||
let variant = self.variant;
|
||||
let mut length = 16 + (variant / 2);
|
||||
let mut width = 7 * length / 8;
|
||||
let mut height = 18 + variant / 2;
|
||||
let mut floor_level = self.alt - 40;
|
||||
let platform_length = self.platform_length;
|
||||
let mut ground_entries = 0;
|
||||
for s in 0..storeys {
|
||||
let x_offset = RandomField::new(0).get((center - length).with_z(base)) as i32 % 10;
|
||||
let y_offset = RandomField::new(0).get((center + length).with_z(base)) as i32 % 10;
|
||||
let super_center =
|
||||
Vec2::new(center.x - 3 + x_offset / 2, center.y - 3 + y_offset / 2);
|
||||
// CliffTower Hoodoo Overlay
|
||||
painter
|
||||
.cubic_bezier(
|
||||
super_center.with_z(floor_level + (height / 2)),
|
||||
(super_center - x_offset).with_z(floor_level + height),
|
||||
(super_center - y_offset).with_z(floor_level + (height) + (height / 2)),
|
||||
super_center.with_z(floor_level + (2 * height)),
|
||||
(length - 1) as f32,
|
||||
)
|
||||
.fill(brick.clone());
|
||||
if s == (storeys - 1) {
|
||||
for dir in LOCALITY {
|
||||
let cone_pos = super_center + (dir * 2);
|
||||
let cone_var =
|
||||
4 + RandomField::new(0).get(cone_pos.with_z(base)) as i32 % 4;
|
||||
painter
|
||||
.cone_with_radius(
|
||||
cone_pos.with_z(floor_level + (2 * height) + 5),
|
||||
(length / 2) as f32,
|
||||
(length + cone_var) as f32,
|
||||
)
|
||||
.fill(brick.clone());
|
||||
}
|
||||
}
|
||||
// center tube with rooms
|
||||
if n == tubes as i32 {
|
||||
// ground_entries
|
||||
if ground_entries < 1 && floor_level > (base - 6) {
|
||||
for dir in CARDINALS {
|
||||
let entry_pos_inner = plot_center + (dir * (2 * length) - 4);
|
||||
let entry_pos_outer = plot_center + (dir * (3 * length) + 4);
|
||||
painter
|
||||
.line(
|
||||
entry_pos_inner.with_z(floor_level + 6),
|
||||
entry_pos_outer.with_z(base + 35),
|
||||
6.0,
|
||||
)
|
||||
.clear();
|
||||
}
|
||||
let door_start = plot_center + door_dir * ((3 * (length / 2)) + 1);
|
||||
painter
|
||||
.line(
|
||||
door_start.with_z(floor_level + 2),
|
||||
self.door_tile.with_z(base),
|
||||
4.0,
|
||||
)
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.line(
|
||||
door_start.with_z(floor_level + 7),
|
||||
self.door_tile.with_z(base + 6),
|
||||
7.0,
|
||||
)
|
||||
.clear();
|
||||
ground_entries += 1;
|
||||
}
|
||||
painter
|
||||
.cubic_bezier(
|
||||
plot_center.with_z(floor_level + (height / 2)),
|
||||
(plot_center - x_offset).with_z(floor_level + height),
|
||||
(plot_center - y_offset).with_z(floor_level + (height) + (height / 2)),
|
||||
plot_center.with_z(floor_level + (2 * height)),
|
||||
(length + 2) as f32,
|
||||
)
|
||||
.fill(brick.clone());
|
||||
// platform
|
||||
if s == (storeys - 1) {
|
||||
let limit_up = painter.aabb(Aabb {
|
||||
min: (plot_center - platform_length - 2).with_z(floor_level - 4),
|
||||
max: (plot_center + platform_length + 2).with_z(floor_level + 1),
|
||||
});
|
||||
painter
|
||||
.superquadric(
|
||||
Aabb {
|
||||
min: (plot_center - platform_length - 2)
|
||||
.with_z(floor_level - 4),
|
||||
max: (plot_center + platform_length + 2)
|
||||
.with_z(floor_level + 6),
|
||||
},
|
||||
4.0,
|
||||
)
|
||||
.intersect(limit_up)
|
||||
.fill(wood.clone());
|
||||
// lanterns & cargo
|
||||
for dir in NEIGHBORS {
|
||||
let lantern_pos = plot_center + (dir * (platform_length - 6));
|
||||
|
||||
painter.sprite(
|
||||
lantern_pos.with_z(floor_level + 1),
|
||||
SpriteKind::StreetLamp,
|
||||
);
|
||||
}
|
||||
for dir in DIAGONALS {
|
||||
let cargo_pos = plot_center + (dir * (2 * length));
|
||||
|
||||
for dir in CARDINALS {
|
||||
let sprite_pos = cargo_pos + dir;
|
||||
let rows =
|
||||
(RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
|
||||
for r in 0..rows {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (sprite_pos).with_z(floor_level + 1 + r),
|
||||
max: (sprite_pos + 1).with_z(floor_level + 2 + r),
|
||||
})
|
||||
.fill(Fill::Block(Block::air(
|
||||
match (RandomField::new(0)
|
||||
.get(sprite_pos.with_z(base + r))
|
||||
% 2)
|
||||
as i32
|
||||
{
|
||||
0 => SpriteKind::Barrel,
|
||||
_ => SpriteKind::CrateBlock,
|
||||
},
|
||||
)));
|
||||
if r > 0 {
|
||||
painter.owned_resource_sprite(
|
||||
sprite_pos.with_z(floor_level + 2 + r),
|
||||
SpriteKind::Crate,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for dir in CARDINALS {
|
||||
// docks
|
||||
let dock_pos = plot_center + (dir * platform_length);
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 8).with_z(floor_level),
|
||||
max: (dock_pos + 8).with_z(floor_level + 1),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 7).with_z(floor_level - 1),
|
||||
max: (dock_pos + 7).with_z(floor_level),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
}
|
||||
// campfire
|
||||
let campfire_pos =
|
||||
Vec2::new(plot_center.x - platform_length - 2, plot_center.y)
|
||||
.with_z(floor_level);
|
||||
painter.spawn(
|
||||
EntityInfo::at(campfire_pos.map(|e| e as f32 + 0.5))
|
||||
.into_special(SpecialEntity::Waypoint),
|
||||
);
|
||||
}
|
||||
|
||||
// clear rooms and entries & decor
|
||||
if floor_level > (base - 6) {
|
||||
// decor
|
||||
painter
|
||||
.line(
|
||||
Vec2::new(plot_center.x, plot_center.y - length)
|
||||
.with_z(floor_level + 5),
|
||||
Vec2::new(plot_center.x, plot_center.y + length)
|
||||
.with_z(floor_level + 5),
|
||||
4.0,
|
||||
)
|
||||
.fill(color.clone());
|
||||
painter
|
||||
.line(
|
||||
Vec2::new(plot_center.x - length, plot_center.y)
|
||||
.with_z(floor_level + 5),
|
||||
Vec2::new(plot_center.x + length, plot_center.y)
|
||||
.with_z(floor_level + 5),
|
||||
4.0,
|
||||
)
|
||||
.fill(color.clone());
|
||||
// entries
|
||||
painter
|
||||
.line(
|
||||
Vec2::new(plot_center.x, plot_center.y - (2 * length) - 4)
|
||||
.with_z(floor_level + 4),
|
||||
Vec2::new(plot_center.x, plot_center.y + (2 * length) + 4)
|
||||
.with_z(floor_level + 4),
|
||||
4.0,
|
||||
)
|
||||
.clear();
|
||||
painter
|
||||
.line(
|
||||
Vec2::new(plot_center.x - (2 * length) - 4, plot_center.y)
|
||||
.with_z(floor_level + 4),
|
||||
Vec2::new(plot_center.x + (2 * length) + 4, plot_center.y)
|
||||
.with_z(floor_level + 4),
|
||||
4.0,
|
||||
)
|
||||
.clear();
|
||||
painter
|
||||
.superquadric(
|
||||
Aabb {
|
||||
min: (plot_center - length - 1).with_z(floor_level),
|
||||
max: (plot_center + length + 1)
|
||||
.with_z(floor_level + height - 4),
|
||||
},
|
||||
sq_type,
|
||||
)
|
||||
.clear();
|
||||
// room floor
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (plot_center - length - 3).with_z(floor_level),
|
||||
max: (plot_center + length + 3).with_z(floor_level + 1),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (plot_center - length + 1).with_z(floor_level),
|
||||
max: (plot_center + length - 1).with_z(floor_level + 1),
|
||||
})
|
||||
.fill(color.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (plot_center - length + 2).with_z(floor_level),
|
||||
max: (plot_center + length - 2).with_z(floor_level + 1),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
// entry sprites
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - 3, plot_center.y + length)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + 4, plot_center.y + length + 1)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.fill(window2.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - 2, plot_center.y + length)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + 3, plot_center.y + length + 1)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - 3, plot_center.y - length - 1)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + 4, plot_center.y - length)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.fill(window2.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - 2, plot_center.y - length - 1)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + 3, plot_center.y - length)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.clear();
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x + length, plot_center.y - 3)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + length + 1, plot_center.y + 4)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.fill(window.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x + length, plot_center.y - 2)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x + length + 1, plot_center.y + 3)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - length - 1, plot_center.y - 3)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x - length, plot_center.y + 4)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.fill(window.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(plot_center.x - length - 1, plot_center.y - 2)
|
||||
.with_z(floor_level + 2),
|
||||
max: Vec2::new(plot_center.x - length, plot_center.y + 3)
|
||||
.with_z(floor_level + 7),
|
||||
})
|
||||
.clear();
|
||||
// cargo in rooms
|
||||
for dir in DIAGONALS {
|
||||
let cargo_pos = plot_center + (dir * (length / 2));
|
||||
for dir in CARDINALS {
|
||||
let sprite_pos = cargo_pos + dir;
|
||||
let rows =
|
||||
(RandomField::new(0).get(sprite_pos.with_z(base)) % 4) as i32;
|
||||
for r in 0..rows {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (sprite_pos).with_z(floor_level + 1 + r),
|
||||
max: (sprite_pos + 1).with_z(floor_level + 2 + r),
|
||||
})
|
||||
.fill(Fill::Block(Block::air(
|
||||
match (RandomField::new(0)
|
||||
.get(sprite_pos.with_z(base + r))
|
||||
% 2)
|
||||
as i32
|
||||
{
|
||||
0 => SpriteKind::Barrel,
|
||||
_ => SpriteKind::CrateBlock,
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wall lamps
|
||||
let corner_pos_1 = Vec2::new(plot_center.x - length, plot_center.y - 5);
|
||||
let corner_pos_2 = Vec2::new(plot_center.x - 5, plot_center.y - length);
|
||||
for dir in SQUARE_4 {
|
||||
let lamp_pos_1 = Vec2::new(
|
||||
corner_pos_1.x + (dir.x * ((2 * length) - 1)),
|
||||
corner_pos_1.y + (dir.y * 10),
|
||||
)
|
||||
.with_z(floor_level + 7);
|
||||
painter.rotated_sprite(
|
||||
lamp_pos_1,
|
||||
SpriteKind::WallLampMesa,
|
||||
(2 + (4 * dir.x)) as u8,
|
||||
);
|
||||
let lamp_pos_2 = Vec2::new(
|
||||
corner_pos_2.x + (dir.x * 10),
|
||||
corner_pos_2.y + (dir.y * ((2 * length) - 1)),
|
||||
)
|
||||
.with_z(floor_level + 7);
|
||||
painter.rotated_sprite(
|
||||
lamp_pos_2,
|
||||
SpriteKind::WallLampMesa,
|
||||
(4 - (4 * dir.y)) as u8,
|
||||
);
|
||||
}
|
||||
}
|
||||
// stairs
|
||||
if floor_level > (base + 8) {
|
||||
let stairs_level = floor_level + 1;
|
||||
let stairs_start = plot_center + door_dir * ((2 * length) - 7);
|
||||
let mid_dir = if door_dir.x != 0 {
|
||||
door_dir.x
|
||||
} else {
|
||||
door_dir.y
|
||||
};
|
||||
let stairs_mid = Vec2::new(
|
||||
plot_center.x + mid_dir * (3 * (length / 2)),
|
||||
plot_center.y + mid_dir * (3 * (length / 2)),
|
||||
);
|
||||
let stairs_end = Vec2::new(
|
||||
plot_center.x + door_dir.y * ((2 * length) - 7),
|
||||
plot_center.y + door_dir.x * ((2 * length) - 7),
|
||||
);
|
||||
let rope_pos = Vec2::new(
|
||||
plot_center.x + mid_dir * ((3 * (length / 2)) + 2),
|
||||
plot_center.y + mid_dir * ((3 * (length / 2)) + 2),
|
||||
);
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (stairs_start - 6).with_z(stairs_level - 1),
|
||||
max: (stairs_start + 6).with_z(stairs_level),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (stairs_mid - 6).with_z(stairs_level - (height / 2) - 1),
|
||||
max: (stairs_mid + 6).with_z(stairs_level - (height / 2)),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (stairs_end - 6).with_z(stairs_level - height - 1),
|
||||
max: (stairs_end + 6).with_z(stairs_level - height),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
|
||||
for n in 0..2 {
|
||||
let stairs = painter
|
||||
.line(
|
||||
stairs_start.with_z(stairs_level + (n * 2)),
|
||||
stairs_mid.with_z(stairs_level - (height / 2) + (n * 2)),
|
||||
4.0 + (n as f32 / 2.0),
|
||||
)
|
||||
.union(painter.line(
|
||||
stairs_mid.with_z(stairs_level - (height / 2) + (n * 2)),
|
||||
stairs_end.with_z(stairs_level - height + (n * 2)),
|
||||
4.0 + (n as f32 / 2.0),
|
||||
));
|
||||
match n {
|
||||
0 => stairs.fill(wood.clone()),
|
||||
_ => stairs.clear(),
|
||||
};
|
||||
}
|
||||
painter
|
||||
.line(
|
||||
rope_pos.with_z(stairs_level + (height / 2) - 3),
|
||||
(plot_center - (length / 2))
|
||||
.with_z(stairs_level + (height / 2) + 2),
|
||||
1.5,
|
||||
)
|
||||
.fill(wood.clone());
|
||||
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: rope_pos.with_z(stairs_level - (height / 2) - 1),
|
||||
max: (rope_pos + 1).with_z(stairs_level + (height / 2) - 3),
|
||||
})
|
||||
.fill(rope.clone());
|
||||
}
|
||||
}
|
||||
// vary next storey
|
||||
length += -1;
|
||||
width += -1;
|
||||
height += -1;
|
||||
floor_level += height;
|
||||
mem::swap(&mut length, &mut width);
|
||||
}
|
||||
}
|
||||
for dock_pos in &self.docking_positions {
|
||||
painter.rotated_sprite_with_cfg(
|
||||
*dock_pos,
|
||||
SpriteKind::Sign,
|
||||
Dir::from_vec2(dock_pos.xy() - self.center).sprite_ori(),
|
||||
SpriteCfg {
|
||||
unlock: None,
|
||||
content: Some(Content::localized("common-signs-airship_dock")),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
294
world/src/site2/plot/coastal_airship_dock.rs
Normal file
294
world/src/site2/plot/coastal_airship_dock.rs
Normal file
@ -0,0 +1,294 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
site2::gen::place_circular,
|
||||
util::{RandomField, Sampler, CARDINALS},
|
||||
Land,
|
||||
};
|
||||
use common::{
|
||||
comp::Content,
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteCfg, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
/// Represents house data generated by the `generate()` method
|
||||
pub struct CoastalAirshipDock {
|
||||
/// Tile position of the door tile
|
||||
pub door_tile: Vec2<i32>,
|
||||
/// Approximate altitude of the door tile
|
||||
pub(crate) alt: i32,
|
||||
base: i32,
|
||||
center: Vec2<i32>,
|
||||
size: i32,
|
||||
bldg_height: i32,
|
||||
diameter: i32,
|
||||
pub docking_positions: Vec<Vec3<i32>>,
|
||||
}
|
||||
|
||||
impl CoastalAirshipDock {
|
||||
pub fn generate(
|
||||
land: &Land,
|
||||
_rng: &mut impl Rng,
|
||||
site: &Site,
|
||||
door_tile: Vec2<i32>,
|
||||
door_dir: Vec2<i32>,
|
||||
tile_aabr: Aabr<i32>,
|
||||
) -> Self {
|
||||
let door_tile_pos = site.tile_center_wpos(door_tile);
|
||||
let bounds = Aabr {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
let diameter = (bounds.max.x - bounds.min.x).min(bounds.max.y - bounds.min.y);
|
||||
let alt = land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2;
|
||||
let size = (diameter / 3) + 2;
|
||||
let bldg_height = 12;
|
||||
let base = alt + 1;
|
||||
let center = bounds.center();
|
||||
let mut docking_positions = vec![];
|
||||
let top_floor = base + (bldg_height * 6) - 3;
|
||||
for dir in CARDINALS {
|
||||
let docking_pos = center + dir * size;
|
||||
docking_positions.push(docking_pos.with_z(top_floor));
|
||||
}
|
||||
Self {
|
||||
door_tile: door_tile_pos,
|
||||
alt,
|
||||
base,
|
||||
center,
|
||||
size,
|
||||
bldg_height,
|
||||
diameter,
|
||||
docking_positions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for CoastalAirshipDock {
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"render_coastal_airship_dock\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_coastal_airship_dock")]
|
||||
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||
let base = self.base;
|
||||
let center = self.center;
|
||||
let white = Fill::Sampling(Arc::new(|center| {
|
||||
Some(match (RandomField::new(0).get(center)) % 37 {
|
||||
0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
|
||||
9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
|
||||
18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
|
||||
27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
|
||||
_ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
|
||||
})
|
||||
}));
|
||||
let blue_broken = Fill::Sampling(Arc::new(|center| {
|
||||
Some(match (RandomField::new(0).get(center)) % 20 {
|
||||
0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
|
||||
_ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
|
||||
})
|
||||
}));
|
||||
|
||||
let length = self.diameter / 2;
|
||||
let width = (self.diameter / 2) - 1;
|
||||
let height = 15;
|
||||
// fence, blue gates
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
|
||||
max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
|
||||
})
|
||||
.fill(blue_broken.clone());
|
||||
|
||||
for dir in CARDINALS {
|
||||
let frame_pos = Vec2::new(
|
||||
center.x + dir.x * (length + 5),
|
||||
center.y + dir.y * (width + 5),
|
||||
);
|
||||
painter
|
||||
.line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
|
||||
.fill(blue_broken.clone());
|
||||
}
|
||||
// foundation
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
|
||||
max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
|
||||
})
|
||||
.fill(white.clone());
|
||||
for f in 0..8 {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
|
||||
.with_z(base - 3 - f),
|
||||
max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
|
||||
.with_z(base - 2 - f),
|
||||
})
|
||||
.fill(white.clone());
|
||||
}
|
||||
// clear yard
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
|
||||
max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
|
||||
})
|
||||
.clear();
|
||||
// clear entries
|
||||
for dir in CARDINALS {
|
||||
let clear_pos = Vec2::new(
|
||||
center.x + dir.x * (length + 7),
|
||||
center.y + dir.y * (width + 7),
|
||||
);
|
||||
painter
|
||||
.line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
|
||||
.clear();
|
||||
}
|
||||
|
||||
// rooms
|
||||
let size = self.size;
|
||||
let room_offset = size / 6;
|
||||
let bldg_height = self.bldg_height;
|
||||
for r in 0..=4 {
|
||||
let bldg_size = size - (room_offset * r);
|
||||
let bldg_base = base + ((bldg_height + 2) * r);
|
||||
if r == 4 {
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (center - bldg_size - 2).with_z(bldg_base + bldg_height - 1),
|
||||
max: (center + bldg_size + 2).with_z(bldg_base + bldg_height),
|
||||
})
|
||||
.fill(white.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (center - bldg_size - 2).with_z(bldg_base + bldg_height),
|
||||
max: (center + bldg_size + 2).with_z(bldg_base + bldg_height + 1),
|
||||
})
|
||||
.fill(blue_broken.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (center - bldg_size - 1).with_z(bldg_base + bldg_height),
|
||||
max: (center + bldg_size + 1).with_z(bldg_base + bldg_height + 1),
|
||||
})
|
||||
.clear();
|
||||
|
||||
let cargo_pos = Vec2::new(center.x, center.y + 5);
|
||||
for dir in CARDINALS {
|
||||
let sprite_pos = cargo_pos + dir;
|
||||
let rows = 1 + (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
|
||||
for r in 0..rows {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (sprite_pos).with_z(bldg_base + bldg_height + r),
|
||||
max: (sprite_pos + 1).with_z(bldg_base + bldg_height + 1 + r),
|
||||
})
|
||||
.fill(Fill::Block(Block::air(
|
||||
match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2)
|
||||
as i32
|
||||
{
|
||||
0 => SpriteKind::Barrel,
|
||||
_ => SpriteKind::CrateBlock,
|
||||
},
|
||||
)));
|
||||
if r > 1 {
|
||||
painter.owned_resource_sprite(
|
||||
sprite_pos.with_z(bldg_base + bldg_height + 1 + r),
|
||||
SpriteKind::Crate,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// docks
|
||||
let gangway_pos = center + dir * (size / 2);
|
||||
let dock_pos = center + dir * (size - 3);
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (gangway_pos - 3).with_z(bldg_base + bldg_height - 1),
|
||||
max: (gangway_pos + 3).with_z(bldg_base + bldg_height),
|
||||
})
|
||||
.fill(white.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 4).with_z(bldg_base + bldg_height),
|
||||
max: (dock_pos + 4).with_z(bldg_base + bldg_height + 1),
|
||||
})
|
||||
.fill(blue_broken.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 3).with_z(bldg_base + bldg_height - 1),
|
||||
max: (dock_pos + 3).with_z(bldg_base + bldg_height + 1),
|
||||
})
|
||||
.fill(white.clone());
|
||||
}
|
||||
// campfire
|
||||
let campfire_pos = center.with_z(bldg_base + bldg_height);
|
||||
painter.spawn(
|
||||
EntityInfo::at(campfire_pos.map(|e| e as f32 + 0.5))
|
||||
.into_special(SpecialEntity::Waypoint),
|
||||
);
|
||||
}
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (center - bldg_size).with_z(bldg_base - 2),
|
||||
max: (center + bldg_size).with_z(bldg_base + bldg_height),
|
||||
})
|
||||
.fill(white.clone());
|
||||
}
|
||||
for r in 0..=4 {
|
||||
let bldg_size = size - (room_offset * r);
|
||||
let bldg_base = base + ((bldg_height + 2) * r);
|
||||
|
||||
let step_positions = place_circular(center, (bldg_size - 1) as f32, 14);
|
||||
for (s, step_pos) in step_positions.enumerate() {
|
||||
let step_size = (size / 3) - r;
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (step_pos - step_size).with_z(bldg_base - 2 + s as i32),
|
||||
max: (step_pos + step_size).with_z(bldg_base + 4 + s as i32),
|
||||
})
|
||||
.clear();
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (step_pos - step_size).with_z(bldg_base - 3 + s as i32),
|
||||
max: (step_pos + step_size).with_z(bldg_base - 2 + s as i32),
|
||||
})
|
||||
.fill(blue_broken.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (step_pos - step_size + 1).with_z(bldg_base - 4 + s as i32),
|
||||
max: (step_pos + step_size - 1).with_z(bldg_base - 2 + s as i32),
|
||||
})
|
||||
.fill(white.clone());
|
||||
}
|
||||
let lamp_positions = place_circular(center, (bldg_size + 1) as f32, 14);
|
||||
for (l, lamp_pos) in lamp_positions.enumerate() {
|
||||
if (RandomField::new(0).get(lamp_pos.with_z(base)) % 4) < 1 {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (lamp_pos - 1).with_z(bldg_base - 3 + l as i32),
|
||||
max: (lamp_pos + 1).with_z(bldg_base - 2 + l as i32),
|
||||
})
|
||||
.fill(blue_broken.clone());
|
||||
|
||||
painter.sprite(
|
||||
lamp_pos.with_z(bldg_base - 2 + l as i32),
|
||||
SpriteKind::FireBowlGround,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
for dock_pos in &self.docking_positions {
|
||||
painter.rotated_sprite_with_cfg(
|
||||
*dock_pos,
|
||||
SpriteKind::Sign,
|
||||
Dir::from_vec2(dock_pos.xy() - self.center).sprite_ori(),
|
||||
SpriteCfg {
|
||||
unlock: None,
|
||||
content: Some(Content::localized("common-signs-airship_dock")),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
404
world/src/site2/plot/desert_city_airship_dock.rs
Normal file
404
world/src/site2/plot/desert_city_airship_dock.rs
Normal file
@ -0,0 +1,404 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
util::{RandomField, Sampler, DIAGONALS},
|
||||
Land,
|
||||
};
|
||||
use common::{
|
||||
comp::Content,
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteCfg, SpriteKind},
|
||||
};
|
||||
|
||||
use rand::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
/// Represents house data generated by the `generate()` method
|
||||
pub struct DesertCityAirshipDock {
|
||||
/// Tile position of the door tile
|
||||
pub door_tile: Vec2<i32>,
|
||||
/// Axis aligned bounding region for the house
|
||||
bounds: Aabr<i32>,
|
||||
/// Approximate altitude of the door tile
|
||||
pub(crate) alt: i32,
|
||||
pub docking_positions: Vec<Vec3<i32>>,
|
||||
center: Vec2<i32>,
|
||||
base: i32,
|
||||
length: i32,
|
||||
height: i32,
|
||||
floors: i32,
|
||||
}
|
||||
|
||||
impl DesertCityAirshipDock {
|
||||
pub fn generate(
|
||||
land: &Land,
|
||||
_rng: &mut impl Rng,
|
||||
site: &Site,
|
||||
door_tile: Vec2<i32>,
|
||||
door_dir: Vec2<i32>,
|
||||
tile_aabr: Aabr<i32>,
|
||||
) -> Self {
|
||||
let door_tile_pos = site.tile_center_wpos(door_tile);
|
||||
let bounds = Aabr {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
let alt = land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32;
|
||||
let center = bounds.center();
|
||||
let length = 14;
|
||||
let height = 2 * (length / 3);
|
||||
let floors = 4;
|
||||
let mut docking_positions = vec![];
|
||||
let base = alt + 1;
|
||||
let top_floor = base + 5 + (height * (floors + 1));
|
||||
for dir in CARDINALS {
|
||||
let docking_pos = center + dir * (length * 2);
|
||||
docking_positions.push(docking_pos.with_z(top_floor));
|
||||
}
|
||||
Self {
|
||||
bounds,
|
||||
door_tile: door_tile_pos,
|
||||
alt,
|
||||
docking_positions,
|
||||
center,
|
||||
base,
|
||||
length,
|
||||
height,
|
||||
floors,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for DesertCityAirshipDock {
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"render_desertcityairshipdock\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_desertcityairshipdock")]
|
||||
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||
let sandstone = Fill::Sampling(Arc::new(|center| {
|
||||
Some(match (RandomField::new(0).get(center)) % 37 {
|
||||
0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
|
||||
9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
|
||||
18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
|
||||
27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
|
||||
_ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
|
||||
})
|
||||
}));
|
||||
let sandstone_broken = Fill::Sampling(Arc::new(|center| {
|
||||
Some(match (RandomField::new(0).get(center)) % 42 {
|
||||
0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)),
|
||||
9..=17 => Block::new(BlockKind::Rock, Rgb::new(246, 214, 133)),
|
||||
18..=26 => Block::new(BlockKind::Rock, Rgb::new(247, 216, 136)),
|
||||
27..=35 => Block::new(BlockKind::Rock, Rgb::new(248, 219, 142)),
|
||||
36..=40 => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
|
||||
_ => Block::new(BlockKind::Rock, Rgb::new(235, 178, 99)),
|
||||
})
|
||||
}));
|
||||
let wood = Fill::Brick(BlockKind::Wood, Rgb::new(71, 33, 11), 12);
|
||||
let base = self.base;
|
||||
let center = self.center;
|
||||
// Fence
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
|
||||
max: Vec2::new(self.bounds.min.x + 2, self.bounds.max.y).with_z(base + 2),
|
||||
})
|
||||
.union(painter.aabb(Aabb {
|
||||
min: Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 1).with_z(base - 20),
|
||||
max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
|
||||
}))
|
||||
.union(painter.aabb(Aabb {
|
||||
min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1).with_z(base - 20),
|
||||
max: Vec2::new(self.bounds.max.x, self.bounds.min.y + 2).with_z(base + 2),
|
||||
}))
|
||||
.union(painter.aabb(Aabb {
|
||||
min: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 1).with_z(base - 20),
|
||||
max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(base + 2),
|
||||
}))
|
||||
.fill(sandstone_broken);
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(self.bounds.min.x + 1, center.y - 8).with_z(base),
|
||||
max: Vec2::new(self.bounds.max.x, center.y + 8).with_z(base + 7),
|
||||
})
|
||||
.clear();
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(center.x - 7, self.bounds.min.y + 1).with_z(base),
|
||||
max: Vec2::new(center.x + 9, self.bounds.max.y).with_z(base + 7),
|
||||
})
|
||||
.clear();
|
||||
// Foundation
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (self.bounds.min + 1).with_z(base - 20),
|
||||
max: (self.bounds.max).with_z(base),
|
||||
})
|
||||
.fill(sandstone.clone());
|
||||
|
||||
// rooms
|
||||
let length = self.length;
|
||||
let height = self.height;
|
||||
let floors = self.floors;
|
||||
let carve = length / 4;
|
||||
|
||||
for f in 0..=floors {
|
||||
let bldg_base = base + f * (height + 1);
|
||||
let bldg_length = length;
|
||||
// room
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - bldg_length).with_z(bldg_base),
|
||||
max: (center + bldg_length).with_z(bldg_base + height),
|
||||
})
|
||||
.fill(sandstone.clone());
|
||||
// roof floor
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - bldg_length - 1 - f).with_z(bldg_base + height),
|
||||
max: (center + bldg_length + 1 + f).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - bldg_length - f).with_z(bldg_base + height),
|
||||
max: (center + bldg_length + f).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.fill(sandstone.clone());
|
||||
// clear room
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - bldg_length + 1).with_z(bldg_base),
|
||||
max: (center + bldg_length - 1).with_z(bldg_base + height - 1),
|
||||
})
|
||||
.clear();
|
||||
|
||||
let clear_limit_1 = painter.aabb(Aabb {
|
||||
min: Vec2::new(center.x - bldg_length, center.y - bldg_length + 1)
|
||||
.with_z(bldg_base),
|
||||
max: Vec2::new(center.x + bldg_length, center.y + bldg_length - 1)
|
||||
.with_z(bldg_base + height),
|
||||
});
|
||||
let clear_limit_2 = painter.aabb(Aabb {
|
||||
min: Vec2::new(center.x - bldg_length + 1, center.y - bldg_length)
|
||||
.with_z(bldg_base),
|
||||
max: Vec2::new(center.x + bldg_length - 1, center.y + bldg_length)
|
||||
.with_z(bldg_base + height),
|
||||
});
|
||||
for c in 0..=4 {
|
||||
let space = c * ((2 * carve) + 1);
|
||||
painter
|
||||
.vault(
|
||||
Aabb {
|
||||
min: Vec2::new(
|
||||
center.x - bldg_length,
|
||||
center.y + space - bldg_length - carve + 1,
|
||||
)
|
||||
.with_z(bldg_base + (height / 2)),
|
||||
max: Vec2::new(
|
||||
center.x + bldg_length,
|
||||
center.y + space - bldg_length + carve - 1,
|
||||
)
|
||||
.with_z(bldg_base + height - 1),
|
||||
},
|
||||
Dir::X,
|
||||
)
|
||||
.intersect(clear_limit_1)
|
||||
.clear();
|
||||
painter
|
||||
.vault(
|
||||
Aabb {
|
||||
min: Vec2::new(
|
||||
center.x + space - bldg_length - carve + 1,
|
||||
center.y - bldg_length,
|
||||
)
|
||||
.with_z(bldg_base + (height / 2)),
|
||||
max: Vec2::new(
|
||||
center.x + space - bldg_length + carve - 1,
|
||||
center.y + bldg_length,
|
||||
)
|
||||
.with_z(bldg_base + height - 1),
|
||||
},
|
||||
Dir::Y,
|
||||
)
|
||||
.intersect(clear_limit_2)
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(
|
||||
center.x - bldg_length,
|
||||
center.y + space - bldg_length - carve,
|
||||
)
|
||||
.with_z(bldg_base),
|
||||
max: Vec2::new(
|
||||
center.x + bldg_length,
|
||||
center.y + space - bldg_length + carve,
|
||||
)
|
||||
.with_z(bldg_base + (height / 2)),
|
||||
})
|
||||
.intersect(clear_limit_1)
|
||||
.clear();
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(
|
||||
center.x + space - bldg_length - carve,
|
||||
center.y - bldg_length,
|
||||
)
|
||||
.with_z(bldg_base),
|
||||
max: Vec2::new(
|
||||
center.x + space - bldg_length + carve,
|
||||
center.y + bldg_length,
|
||||
)
|
||||
.with_z(bldg_base + (height / 2)),
|
||||
})
|
||||
.intersect(clear_limit_2)
|
||||
.clear();
|
||||
}
|
||||
for dir in DIAGONALS {
|
||||
let clear_pos = center + dir * bldg_length;
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (clear_pos - 1).with_z(bldg_base),
|
||||
max: (clear_pos + 1).with_z(bldg_base + height - 1),
|
||||
})
|
||||
.clear();
|
||||
}
|
||||
for dir in DIAGONALS {
|
||||
let lamp_pos = center + dir * (bldg_length - 1);
|
||||
painter.sprite(lamp_pos.with_z(bldg_base), SpriteKind::StreetLamp);
|
||||
if f == 4 {
|
||||
let lamp_pos = center + dir * bldg_length;
|
||||
painter.sprite(
|
||||
lamp_pos.with_z(bldg_base + height + 1),
|
||||
SpriteKind::StreetLamp,
|
||||
);
|
||||
|
||||
let cargo_pos = center + (dir * ((bldg_length / 2) + 1));
|
||||
for dir in CARDINALS {
|
||||
let sprite_pos = cargo_pos + dir;
|
||||
let rows = (RandomField::new(0).get(sprite_pos.with_z(base)) % 3) as i32;
|
||||
for r in 0..rows {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (sprite_pos).with_z(bldg_base + height + 1 + r),
|
||||
max: (sprite_pos + 1).with_z(bldg_base + height + 2 + r),
|
||||
})
|
||||
.fill(Fill::Block(Block::air(
|
||||
match (RandomField::new(0).get(sprite_pos.with_z(base + r)) % 2)
|
||||
as i32
|
||||
{
|
||||
0 => SpriteKind::Barrel,
|
||||
_ => SpriteKind::CrateBlock,
|
||||
},
|
||||
)));
|
||||
if r > 0 {
|
||||
painter.owned_resource_sprite(
|
||||
sprite_pos.with_z(bldg_base + height + 2 + r),
|
||||
SpriteKind::Crate,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// docks
|
||||
if f == 4 {
|
||||
for dir in CARDINALS {
|
||||
let gangway_pos_1 = center + dir * (3 * (bldg_length / 2));
|
||||
let gangway_pos_2 = center + dir * ((3 * (bldg_length / 2)) - 4);
|
||||
let dock_pos = center + dir * ((bldg_length * 2) - 3);
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (gangway_pos_2 - 3).with_z(bldg_base + height - 1),
|
||||
max: (gangway_pos_2 + 3).with_z(bldg_base + height),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (gangway_pos_1 - 3).with_z(bldg_base + height),
|
||||
max: (gangway_pos_1 + 3).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 4).with_z(bldg_base + height),
|
||||
max: (dock_pos + 4).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 3).with_z(bldg_base + height - 1),
|
||||
max: (dock_pos + 3).with_z(bldg_base + height),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
}
|
||||
// campfire
|
||||
painter.spawn(
|
||||
EntityInfo::at(
|
||||
Vec2::new(center.x + bldg_length - 2, center.y)
|
||||
.with_z(bldg_base + height + 1)
|
||||
.map(|e| e as f32 + 0.5),
|
||||
)
|
||||
.into_special(SpecialEntity::Waypoint),
|
||||
);
|
||||
}
|
||||
for dock_pos in &self.docking_positions {
|
||||
painter.rotated_sprite_with_cfg(
|
||||
*dock_pos,
|
||||
SpriteKind::Sign,
|
||||
Dir::from_vec2(dock_pos.xy() - self.center).sprite_ori(),
|
||||
SpriteCfg {
|
||||
unlock: None,
|
||||
content: Some(Content::localized("common-signs-airship_dock")),
|
||||
},
|
||||
);
|
||||
}
|
||||
// stairs
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - (bldg_length / 2) - 1).with_z(bldg_base + height - 1),
|
||||
max: (center + (bldg_length / 2) + 1).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (center - (bldg_length / 2)).with_z(bldg_base + height - 1),
|
||||
max: (center + (bldg_length / 2)).with_z(bldg_base + height + 1),
|
||||
})
|
||||
.clear();
|
||||
|
||||
for w in 0..((bldg_length / 2) + 2) {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(
|
||||
center.x - (bldg_length / 2) - 2 + (2 * w),
|
||||
center.y - (bldg_length / 2),
|
||||
)
|
||||
.with_z(bldg_base + w),
|
||||
max: Vec2::new(
|
||||
center.x - (bldg_length / 2) - 2 + (2 * w) + 2,
|
||||
center.y + (bldg_length / 2),
|
||||
)
|
||||
.with_z(bldg_base + 1 + w),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(
|
||||
center.x - (bldg_length / 2) - 2 + (2 * w),
|
||||
center.y - (bldg_length / 2),
|
||||
)
|
||||
.with_z(bldg_base - 1 + w),
|
||||
max: Vec2::new(
|
||||
center.x - (bldg_length / 2) - 2 + (2 * w) + 2,
|
||||
center.y + (bldg_length / 2),
|
||||
)
|
||||
.with_z(bldg_base + w),
|
||||
})
|
||||
.fill(sandstone.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,9 +5,12 @@ mod camp;
|
||||
mod castle;
|
||||
mod citadel;
|
||||
mod cliff_tower;
|
||||
mod cliff_town_airship_dock;
|
||||
mod coastal_airship_dock;
|
||||
mod coastal_house;
|
||||
mod coastal_workshop;
|
||||
mod cultist;
|
||||
mod desert_city_airship_dock;
|
||||
mod desert_city_arena;
|
||||
mod desert_city_multiplot;
|
||||
mod desert_city_temple;
|
||||
@ -40,8 +43,10 @@ mod workshop;
|
||||
|
||||
pub use self::{
|
||||
adlet::AdletStronghold, airship_dock::AirshipDock, bridge::Bridge, camp::Camp, castle::Castle,
|
||||
citadel::Citadel, cliff_tower::CliffTower, coastal_house::CoastalHouse,
|
||||
coastal_workshop::CoastalWorkshop, cultist::Cultist, desert_city_arena::DesertCityArena,
|
||||
citadel::Citadel, cliff_tower::CliffTower, cliff_town_airship_dock::CliffTownAirshipDock,
|
||||
coastal_airship_dock::CoastalAirshipDock, coastal_house::CoastalHouse,
|
||||
coastal_workshop::CoastalWorkshop, cultist::Cultist,
|
||||
desert_city_airship_dock::DesertCityAirshipDock, desert_city_arena::DesertCityArena,
|
||||
desert_city_multiplot::DesertCityMultiPlot, desert_city_temple::DesertCityTemple,
|
||||
dwarven_mine::DwarvenMine, farm_field::FarmField, giant_tree::GiantTree,
|
||||
glider_finish::GliderFinish, glider_platform::GliderPlatform, glider_ring::GliderRing,
|
||||
@ -98,12 +103,14 @@ pub enum PlotKind {
|
||||
GliderPlatform(GliderPlatform),
|
||||
GliderFinish(GliderFinish),
|
||||
Tavern(Tavern),
|
||||
CoastalAirshipDock(CoastalAirshipDock),
|
||||
CoastalHouse(CoastalHouse),
|
||||
CoastalWorkshop(CoastalWorkshop),
|
||||
Workshop(Workshop),
|
||||
DesertCityMultiPlot(DesertCityMultiPlot),
|
||||
DesertCityTemple(DesertCityTemple),
|
||||
DesertCityArena(DesertCityArena),
|
||||
DesertCityAirshipDock(DesertCityAirshipDock),
|
||||
SeaChapel(SeaChapel),
|
||||
JungleRuin(JungleRuin),
|
||||
Plaza,
|
||||
@ -115,6 +122,7 @@ pub enum PlotKind {
|
||||
Haniwa(Haniwa),
|
||||
GiantTree(GiantTree),
|
||||
CliffTower(CliffTower),
|
||||
CliffTownAirshipDock(CliffTownAirshipDock),
|
||||
Sahagin(Sahagin),
|
||||
Citadel(Citadel),
|
||||
SavannahAirshipDock(SavannahAirshipDock),
|
||||
@ -141,9 +149,11 @@ macro_rules! foreach_plot {
|
||||
match $p {
|
||||
PlotKind::House($x) => $y,
|
||||
PlotKind::AirshipDock($x) => $y,
|
||||
PlotKind::CoastalAirshipDock($x) => $y,
|
||||
PlotKind::CoastalHouse($x) => $y,
|
||||
PlotKind::CoastalWorkshop($x) => $y,
|
||||
PlotKind::Workshop($x) => $y,
|
||||
PlotKind::DesertCityAirshipDock($x) => $y,
|
||||
PlotKind::DesertCityMultiPlot($x) => $y,
|
||||
PlotKind::DesertCityTemple($x) => $y,
|
||||
PlotKind::DesertCityArena($x) => $y,
|
||||
@ -156,6 +166,7 @@ macro_rules! foreach_plot {
|
||||
PlotKind::Adlet($x) => $y,
|
||||
PlotKind::GiantTree($x) => $y,
|
||||
PlotKind::CliffTower($x) => $y,
|
||||
PlotKind::CliffTownAirshipDock($x) => $y,
|
||||
PlotKind::Citadel($x) => $y,
|
||||
PlotKind::SavannahAirshipDock($x) => $y,
|
||||
PlotKind::SavannahHut($x) => $y,
|
||||
|
@ -4,7 +4,11 @@ use crate::{
|
||||
util::{RandomField, Sampler, CARDINALS, DIAGONALS},
|
||||
Land,
|
||||
};
|
||||
use common::terrain::{BlockKind, SpriteKind};
|
||||
use common::{
|
||||
comp::Content,
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteCfg, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::{f32::consts::TAU, sync::Arc};
|
||||
use vek::*;
|
||||
@ -13,10 +17,12 @@ use vek::*;
|
||||
pub struct SavannahAirshipDock {
|
||||
/// Tile position of the door tile
|
||||
pub door_tile: Vec2<i32>,
|
||||
/// Axis aligned bounding region for the house
|
||||
bounds: Aabr<i32>,
|
||||
/// Approximate altitude of the door tile
|
||||
pub(crate) alt: i32,
|
||||
center: Vec2<i32>,
|
||||
length: i32,
|
||||
platform_height: i32,
|
||||
pub docking_positions: Vec<Vec3<i32>>,
|
||||
}
|
||||
|
||||
impl SavannahAirshipDock {
|
||||
@ -33,10 +39,25 @@ impl SavannahAirshipDock {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
let center = bounds.center();
|
||||
let alt = land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2;
|
||||
let base = alt + 1;
|
||||
let length = 18;
|
||||
let platform_height = 40;
|
||||
let mut docking_positions = vec![];
|
||||
let top_floor = base + platform_height - 2;
|
||||
for dir in CARDINALS {
|
||||
let docking_pos = center + dir * (length + 5);
|
||||
docking_positions.push(docking_pos.with_z(top_floor));
|
||||
}
|
||||
|
||||
Self {
|
||||
bounds,
|
||||
door_tile: door_tile_pos,
|
||||
alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2,
|
||||
alt,
|
||||
center,
|
||||
length,
|
||||
platform_height,
|
||||
docking_positions,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,8 +69,7 @@ impl Structure for SavannahAirshipDock {
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_savannah_airship_dock")]
|
||||
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||
let base = self.alt + 1;
|
||||
let center = self.bounds.center();
|
||||
|
||||
let center = self.center;
|
||||
let wood_dark = Fill::Brick(BlockKind::Misc, Rgb::new(142, 67, 27), 12);
|
||||
let reed = Fill::Brick(BlockKind::Misc, Rgb::new(72, 55, 46), 22);
|
||||
let clay = Fill::Brick(BlockKind::Misc, Rgb::new(209, 124, 57), 22);
|
||||
@ -64,10 +84,10 @@ impl Structure for SavannahAirshipDock {
|
||||
_ => Block::new(BlockKind::GlowingRock, Rgb::new(178, 124, 90)),
|
||||
})
|
||||
}));
|
||||
let length = 18;
|
||||
let length = self.length;
|
||||
let height = length / 2;
|
||||
let platform_height = self.platform_height;
|
||||
let storeys = 1;
|
||||
let platform_height = 40;
|
||||
let radius = length + (length / 3);
|
||||
let reed_var = (1 + RandomField::new(0).get(center.with_z(base)) % 4) as f32;
|
||||
let reed_parts = 36_f32 + reed_var;
|
||||
@ -123,6 +143,35 @@ impl Structure for SavannahAirshipDock {
|
||||
max: (center + length + 1).with_z(base + platform_height - 2),
|
||||
})
|
||||
.fill(clay.clone());
|
||||
// docks
|
||||
for dir in CARDINALS {
|
||||
let dock_pos = center + dir * (length + 2);
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 5).with_z(base + platform_height - 3),
|
||||
max: (dock_pos + 5).with_z(base + platform_height - 2),
|
||||
})
|
||||
.fill(color.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (dock_pos - 4).with_z(base + platform_height - 3),
|
||||
max: (dock_pos + 4).with_z(base + platform_height - 2),
|
||||
})
|
||||
.fill(wood_dark.clone());
|
||||
}
|
||||
|
||||
for dock_pos in &self.docking_positions {
|
||||
painter.rotated_sprite_with_cfg(
|
||||
*dock_pos,
|
||||
SpriteKind::Sign,
|
||||
Dir::from_vec2(dock_pos.xy() - self.center).sprite_ori(),
|
||||
SpriteCfg {
|
||||
unlock: None,
|
||||
content: Some(Content::localized("common-signs-airship_dock")),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// lanterns, crates & barrels
|
||||
for dir in CARDINALS {
|
||||
let lantern_pos = center + (dir * length);
|
||||
@ -160,6 +209,12 @@ impl Structure for SavannahAirshipDock {
|
||||
}
|
||||
}
|
||||
}
|
||||
// campfire
|
||||
let campfire_pos = (center - (2 * (length / 3)) - 1).with_z(base + platform_height);
|
||||
painter.spawn(
|
||||
EntityInfo::at(campfire_pos.map(|e| e as f32 + 0.5))
|
||||
.into_special(SpecialEntity::Waypoint),
|
||||
);
|
||||
for b in 0..2 {
|
||||
let base = base + (b * platform_height);
|
||||
let radius = radius - (b * (radius / 3));
|
||||
|
Reference in New Issue
Block a user