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::*;
pub struct DesertCityAirshipDock {
pub door_tile: Vec2<i32>,
bounds: Aabr<i32>,
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;
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();
painter
.aabb(Aabb {
min: (self.bounds.min + 1).with_z(base - 20),
max: (self.bounds.max).with_z(base),
})
.fill(sandstone.clone());
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;
painter
.aabb(Aabb {
min: (center - bldg_length).with_z(bldg_base),
max: (center + bldg_length).with_z(bldg_base + height),
})
.fill(sandstone.clone());
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());
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,
);
}
}
}
}
}
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());
}
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")),
},
);
}
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());
}
}
}
}