mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'new_sahagin' into 'master'
new_sahagin See merge request veloren/veloren!4467
This commit is contained in:
commit
eeb68797e7
@ -633,6 +633,9 @@
|
||||
Simple(
|
||||
"common.items.keys.quarry_keys.forge_key",
|
||||
): "object-key-forge",
|
||||
Simple(
|
||||
"common.items.keys.sahagin_key",
|
||||
): "object-key-sahagin",
|
||||
Simple(
|
||||
"common.items.weapons.shield.shield_1",
|
||||
): "weapon-shield-wood-0",
|
||||
|
10
assets/common/items/keys/sahagin_key.ron
Normal file
10
assets/common/items/keys/sahagin_key.ron
Normal file
@ -0,0 +1,10 @@
|
||||
ItemDef(
|
||||
legacy_name: "Sahagin Key",
|
||||
legacy_description: "Used to open doors. Will break after use.",
|
||||
kind: Utility(
|
||||
kind: Key,
|
||||
),
|
||||
quality: Common,
|
||||
tags: [Utility],
|
||||
)
|
||||
|
3
assets/common/loot_tables/dungeon/sahagin/key_chest.ron
Normal file
3
assets/common/loot_tables/dungeon/sahagin/key_chest.ron
Normal file
@ -0,0 +1,3 @@
|
||||
[
|
||||
(1.0, Item("common.items.keys.sahagin_key")),
|
||||
]
|
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior_bg.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior_bg.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior_hover.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/ui/map/buttons/tidal_warrior_hover.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -37,5 +37,6 @@ hud-map-chapel_site = Sea Chapel
|
||||
hud-map-adlet = Adlet Stronghold
|
||||
hud-map-haniwa = Haniwa Catacomb
|
||||
hud-map-cultist = Cultist Dungeon
|
||||
hud-map-sahagin = Sahagin Island
|
||||
hud-map-terracotta = Terracotta Ruins
|
||||
hud-map-placed_by = Placed by { $name }
|
||||
|
@ -24,3 +24,6 @@ object-key-terracotta_chest = Terracotta Chest Key
|
||||
|
||||
object-key-terracotta_door = Terracotta Door Key
|
||||
.desc = Used to open doors. Will break after use.
|
||||
|
||||
object-key-sahagin = Sahagin Key
|
||||
.desc = Used to open doors. Will break after use.
|
||||
|
@ -4986,6 +4986,10 @@
|
||||
"voxel.object.key_haniwa",
|
||||
(0.0, 0.0, 0.0), (-100.0, 250.0, 15.0), 1.0,
|
||||
),
|
||||
Simple("common.items.keys.sahagin_key"): VoxTrans(
|
||||
"voxel.object.key_sahagin",
|
||||
(0.0, 0.0, 0.0), (-100.0, 250.0, 15.0), 1.0,
|
||||
),
|
||||
Simple("common.items.keys.glass_key"): VoxTrans(
|
||||
"voxel.object.key_glass",
|
||||
(0.0, 0.0, 0.0), (-100.0, 250.0, 15.0), 1.0,
|
||||
|
@ -959,6 +959,7 @@
|
||||
Simple("common.items.keys.rusty_tower_key"): "voxel.object.key_rusty-0",
|
||||
Simple("common.items.keys.bone_key"): "voxel.object.key_bone",
|
||||
Simple("common.items.keys.haniwa_key"): "voxel.object.key_haniwa",
|
||||
Simple("common.items.keys.sahagin_key"): "voxel.object.key_sahagin",
|
||||
Simple("common.items.keys.glass_key"): "voxel.object.key_glass",
|
||||
Simple("common.items.utility.lockpick_0"): "voxel.object.lockpick",
|
||||
Simple("common.items.keys.quarry_keys.forge_key"): "voxel.object.key_rusty-0",
|
||||
|
BIN
assets/voxygen/voxel/object/key_sahagin.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/key_sahagin.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_sahagin.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_sahagin.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/furniture/sahagin_keydoor.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/furniture/sahagin_keydoor.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/furniture/sahagin_keyhole.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/furniture/sahagin_keyhole.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1419,6 +1419,37 @@
|
||||
],
|
||||
wind_sway: 0.0,
|
||||
),
|
||||
// Sahagin Door, Keyhole, Chest, Statue
|
||||
(SahaginKeyDoor, ()): (
|
||||
variations: [
|
||||
(
|
||||
model: "voxygen.voxel.sprite.furniture.sahagin_keydoor",
|
||||
offset: (-5.5, -5.5, 0.0),
|
||||
lod_axes: (0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
wind_sway: 0.0,
|
||||
),
|
||||
(SahaginKeyhole, ()): (
|
||||
variations: [
|
||||
(
|
||||
model: "voxygen.voxel.sprite.furniture.sahagin_keyhole",
|
||||
offset: (-5.5, -5.5, 0.0),
|
||||
lod_axes: (0.0, 0.0, 0.0),
|
||||
),
|
||||
],
|
||||
wind_sway: 0.0,
|
||||
),
|
||||
(SahaginChest, ()): (
|
||||
variations: [
|
||||
(
|
||||
model: "voxygen.voxel.sprite.chests.chest_sahagin",
|
||||
offset: (-7.0, -5.0, -0.0),
|
||||
lod_axes: (1.0, 1.0, 1.0),
|
||||
),
|
||||
],
|
||||
wind_sway: 0.0,
|
||||
),
|
||||
// Terracotta Door, Keyhole, Chest, Statue
|
||||
(TerracottaKeyDoor, ()): (
|
||||
variations: [
|
||||
|
@ -16,6 +16,5 @@
|
||||
/// 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
|
||||
([
|
||||
(2, 0.20),
|
||||
(4, 0.10),
|
||||
])
|
||||
|
@ -155,6 +155,7 @@ pub enum SiteKind {
|
||||
Haniwa,
|
||||
DwarvenMine,
|
||||
Cultist,
|
||||
Sahagin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
@ -206,6 +206,7 @@ impl From<SpriteKind> for Option<SpriteInteractKind> {
|
||||
SpriteKind::Keyhole
|
||||
| SpriteKind::BoneKeyhole
|
||||
| SpriteKind::HaniwaKeyhole
|
||||
| SpriteKind::SahaginKeyhole
|
||||
| SpriteKind::GlassKeyhole
|
||||
| SpriteKind::KeyholeBars
|
||||
| SpriteKind::TerracottaKeyhole => Some(SpriteInteractKind::Unlock),
|
||||
|
@ -372,6 +372,7 @@ impl Block {
|
||||
| SpriteKind::CoralChest
|
||||
| SpriteKind::HaniwaUrn
|
||||
| SpriteKind::TerracottaChest
|
||||
| SpriteKind::SahaginChest
|
||||
| SpriteKind::Crate => Some(rtsim::ChunkResource::Loot),
|
||||
_ => None,
|
||||
}
|
||||
@ -533,6 +534,7 @@ impl Block {
|
||||
| SpriteKind::HaniwaTrapTriggered
|
||||
| SpriteKind::ChestBuried
|
||||
| SpriteKind::TerracottaChest
|
||||
| SpriteKind::SahaginChest
|
||||
| SpriteKind::SeaDecorBlock
|
||||
| SpriteKind::SeaDecorChain
|
||||
| SpriteKind::SeaDecorWindowHor
|
||||
@ -543,6 +545,8 @@ impl Block {
|
||||
| SpriteKind::FireBlock
|
||||
| SpriteKind::GlassBarrier
|
||||
| SpriteKind::GlassKeyhole
|
||||
| SpriteKind::SahaginKeyhole
|
||||
| SpriteKind::SahaginKeyDoor
|
||||
| SpriteKind::TerracottaKeyDoor
|
||||
| SpriteKind::TerracottaKeyhole
|
||||
| SpriteKind::TerracottaStatue
|
||||
|
@ -19,6 +19,7 @@ pub enum DungeonKindMeta {
|
||||
SeaChapel,
|
||||
Terracotta,
|
||||
Cultist,
|
||||
Sahagin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
|
@ -128,11 +128,12 @@ sprites! {
|
||||
CoralChest = 0x37,
|
||||
HaniwaUrn = 0x38,
|
||||
TerracottaChest = 0x39,
|
||||
CommonLockedChest = 0x3A,
|
||||
ChestBuried = 0x3B,
|
||||
Crate = 0x3C,
|
||||
Barrel = 0x3D,
|
||||
CrateBlock = 0x3E,
|
||||
SahaginChest = 0x3A,
|
||||
CommonLockedChest = 0x3B,
|
||||
ChestBuried = 0x3C,
|
||||
Crate = 0x3D,
|
||||
Barrel = 0x3E,
|
||||
CrateBlock = 0x3F,
|
||||
// Wall
|
||||
HangingBasket = 0x50,
|
||||
HangingSign = 0x51,
|
||||
@ -312,6 +313,9 @@ sprites! {
|
||||
HaniwaKeyhole = 0x0A,
|
||||
TerracottaKeyDoor = 0x0B,
|
||||
TerracottaKeyhole = 0x0C,
|
||||
SahaginKeyhole = 0x0D,
|
||||
SahaginKeyDoor = 0x0E,
|
||||
|
||||
// Windows
|
||||
Window1 = 0x10,
|
||||
Window2 = 0x11,
|
||||
@ -438,6 +442,7 @@ impl SpriteKind {
|
||||
SpriteKind::DungeonChest5 => 1.09,
|
||||
SpriteKind::CoralChest => 1.09,
|
||||
SpriteKind::HaniwaUrn => 1.09,
|
||||
SpriteKind::SahaginChest => 1.09,
|
||||
SpriteKind::TerracottaChest => 1.09,
|
||||
SpriteKind::TerracottaStatue => 5.29,
|
||||
SpriteKind::TerracottaBlock => 1.00,
|
||||
@ -515,6 +520,8 @@ impl SpriteKind {
|
||||
| SpriteKind::BoneKeyDoor
|
||||
| SpriteKind::HaniwaKeyhole
|
||||
| SpriteKind::HaniwaKeyDoor
|
||||
| SpriteKind::SahaginKeyhole
|
||||
| SpriteKind::SahaginKeyDoor
|
||||
| SpriteKind::HaniwaTrap
|
||||
| SpriteKind::HaniwaTrapTriggered
|
||||
| SpriteKind::TerracottaKeyDoor
|
||||
@ -690,6 +697,7 @@ impl SpriteKind {
|
||||
SpriteKind::TerracottaChest => {
|
||||
table("common.loot_tables.dungeon.terracotta.chest_terracotta")
|
||||
},
|
||||
SpriteKind::SahaginChest => table("common.loot_tables.dungeon.sahagin.key_chest"),
|
||||
SpriteKind::Mud => table("common.loot_tables.sprite.mud"),
|
||||
SpriteKind::Grave => table("common.loot_tables.sprite.mud"),
|
||||
SpriteKind::Crate => table("common.loot_tables.sprite.crate"),
|
||||
@ -705,6 +713,7 @@ impl SpriteKind {
|
||||
| SpriteKind::HaniwaKeyhole
|
||||
| SpriteKind::GlassKeyhole
|
||||
| SpriteKind::KeyholeBars
|
||||
| SpriteKind::SahaginKeyhole
|
||||
| SpriteKind::TerracottaKeyhole => {
|
||||
return Some(None);
|
||||
},
|
||||
@ -809,6 +818,9 @@ impl SpriteKind {
|
||||
SpriteKind::GlassKeyhole => UnlockKind::Consumes(
|
||||
ItemDefinitionId::Simple("common.items.keys.glass_key").to_owned(),
|
||||
),
|
||||
SpriteKind::SahaginKeyhole => UnlockKind::Consumes(
|
||||
ItemDefinitionId::Simple("common.items.keys.sahagin_key").to_owned(),
|
||||
),
|
||||
SpriteKind::TerracottaChest => UnlockKind::Consumes(
|
||||
ItemDefinitionId::Simple("common.items.keys.terracotta_key_chest").to_owned(),
|
||||
),
|
||||
|
@ -49,10 +49,11 @@ make_case_elim!(
|
||||
KeyholeBars(consumes: String) = 29,
|
||||
HaniwaKeyhole(consumes: String) = 30,
|
||||
TerracottaKeyhole(consumes: String) = 31,
|
||||
MapleLeaves = 32,
|
||||
CherryLeaves = 33,
|
||||
AutumnLeaves = 34,
|
||||
RedwoodWood = 35,
|
||||
SahaginKeyhole(consumes: String) = 32,
|
||||
MapleLeaves = 33,
|
||||
CherryLeaves = 34,
|
||||
AutumnLeaves = 35,
|
||||
RedwoodWood = 36,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -33,6 +33,7 @@ impl Site {
|
||||
| SiteKind::Terracotta(_)
|
||||
| SiteKind::Gnarling(_)
|
||||
| SiteKind::Cultist(_)
|
||||
| SiteKind::Sahagin(_)
|
||||
| SiteKind::PirateHideout(_)
|
||||
| SiteKind::JungleRuin(_)
|
||||
| SiteKind::RockCircle(_)
|
||||
|
@ -4494,7 +4494,7 @@ impl<'a> AgentData<'a> {
|
||||
read_data,
|
||||
)
|
||||
};
|
||||
|
||||
let home = agent.patrol_origin.unwrap_or(self.pos.0.round());
|
||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||
// it was already initialized
|
||||
if !agent.combat_state.conditions
|
||||
@ -4544,15 +4544,14 @@ impl<'a> AgentData<'a> {
|
||||
controller.push_basic_input(InputKind::Secondary);
|
||||
}
|
||||
}
|
||||
// Always attempt to path towards target
|
||||
self.path_toward_target(
|
||||
agent,
|
||||
controller,
|
||||
tgt_data.pos.0,
|
||||
read_data,
|
||||
Path::Partial,
|
||||
None,
|
||||
);
|
||||
let path = if tgt_data.pos.0.z < self.pos.0.z {
|
||||
home
|
||||
} else {
|
||||
tgt_data.pos.0
|
||||
};
|
||||
// attempt to path towards target, move away from exiit if target is cheesing
|
||||
// from below
|
||||
self.path_toward_target(agent, controller, path, read_data, Path::Partial, None);
|
||||
}
|
||||
|
||||
pub fn handle_yeti_attack(
|
||||
|
@ -411,6 +411,9 @@ impl ServerEvent for InventoryManipEvent {
|
||||
Some(SpriteKind::Keyhole) => Some(SpriteKind::KeyDoor),
|
||||
Some(SpriteKind::BoneKeyhole) => Some(SpriteKind::BoneKeyDoor),
|
||||
Some(SpriteKind::HaniwaKeyhole) => Some(SpriteKind::HaniwaKeyDoor),
|
||||
Some(SpriteKind::SahaginKeyhole) => {
|
||||
Some(SpriteKind::SahaginKeyDoor)
|
||||
},
|
||||
Some(SpriteKind::GlassKeyhole) => Some(SpriteKind::GlassBarrier),
|
||||
Some(SpriteKind::KeyholeBars) => Some(SpriteKind::DoorBars),
|
||||
Some(SpriteKind::TerracottaKeyhole) => {
|
||||
|
@ -588,6 +588,9 @@ image_ids! {
|
||||
mmap_site_cultist: "voxygen.element.ui.map.buttons.mindflayer",
|
||||
mmap_site_cultist_hover: "voxygen.element.ui.map.buttons.mindflayer_hover",
|
||||
mmap_site_cultist_bg: "voxygen.element.ui.map.buttons.mindflayer_bg",
|
||||
mmap_site_sahagin: "voxygen.element.ui.map.buttons.tidal_warrior",
|
||||
mmap_site_sahagin_hover: "voxygen.element.ui.map.buttons.tidal_warrior_hover",
|
||||
mmap_site_sahagin_bg: "voxygen.element.ui.map.buttons.tidal_warrior_bg",
|
||||
mmap_site_minotaur: "voxygen.element.ui.map.buttons.minotaur",
|
||||
mmap_site_minotaur_hover: "voxygen.element.ui.map.buttons.minotaur_hover",
|
||||
mmap_site_minotaur_bg: "voxygen.element.ui.map.buttons.minotaur_bg",
|
||||
|
@ -929,6 +929,7 @@ impl<'a> Widget for Map<'a> {
|
||||
SiteKind::Adlet => i18n.get_msg("hud-map-adlet"),
|
||||
SiteKind::Haniwa => i18n.get_msg("hud-map-haniwa"),
|
||||
SiteKind::Cultist => i18n.get_msg("hud-map-cultist"),
|
||||
SiteKind::Sahagin => i18n.get_msg("hud-map-sahagin"),
|
||||
SiteKind::DwarvenMine => i18n.get_msg("hud-map-df_mine"),
|
||||
});
|
||||
let (difficulty, desc) = match &site.kind {
|
||||
@ -960,6 +961,7 @@ impl<'a> Widget for Map<'a> {
|
||||
SiteKind::Adlet => (Some(1), i18n.get_msg("hud-map-adlet")),
|
||||
SiteKind::Haniwa => (Some(3), i18n.get_msg("hud-map-haniwa")),
|
||||
SiteKind::Cultist => (Some(5), i18n.get_msg("hud-map-cultist")),
|
||||
SiteKind::Sahagin => (Some(2), i18n.get_msg("hud-map-sahagin")),
|
||||
SiteKind::DwarvenMine => (Some(5), i18n.get_msg("hud-map-df_mine")),
|
||||
};
|
||||
let desc = desc.into_owned() + &get_site_economy(site_rich);
|
||||
@ -974,6 +976,7 @@ impl<'a> Widget for Map<'a> {
|
||||
SiteKind::Adlet => self.imgs.mmap_site_adlet,
|
||||
SiteKind::Haniwa => self.imgs.mmap_site_haniwa,
|
||||
SiteKind::Cultist => self.imgs.mmap_site_cultist,
|
||||
SiteKind::Sahagin => self.imgs.mmap_site_sahagin,
|
||||
SiteKind::DwarvenMine => self.imgs.mmap_site_mine,
|
||||
SiteKind::Dungeon { difficulty } => match difficulty {
|
||||
4 => self.imgs.mmap_site_minotaur,
|
||||
@ -999,6 +1002,7 @@ impl<'a> Widget for Map<'a> {
|
||||
SiteKind::Adlet => self.imgs.mmap_site_adlet_hover,
|
||||
SiteKind::Haniwa => self.imgs.mmap_site_haniwa_hover,
|
||||
SiteKind::Cultist => self.imgs.mmap_site_cultist_hover,
|
||||
SiteKind::Sahagin => self.imgs.mmap_site_sahagin_hover,
|
||||
SiteKind::DwarvenMine => self.imgs.mmap_site_mine_hover,
|
||||
SiteKind::Dungeon { difficulty } => match difficulty {
|
||||
4 => self.imgs.mmap_site_minotaur_hover,
|
||||
@ -1021,6 +1025,7 @@ impl<'a> Widget for Map<'a> {
|
||||
| SiteKind::Adlet
|
||||
| SiteKind::Haniwa
|
||||
| SiteKind::Cultist
|
||||
| SiteKind::Sahagin
|
||||
| SiteKind::DwarvenMine => match difficulty {
|
||||
Some(0) => QUALITY_LOW,
|
||||
Some(1) => QUALITY_COMMON,
|
||||
@ -1050,6 +1055,7 @@ impl<'a> Widget for Map<'a> {
|
||||
| SiteKind::DwarvenMine
|
||||
| SiteKind::Haniwa
|
||||
| SiteKind::Cultist
|
||||
| SiteKind::Sahagin
|
||||
| SiteKind::Terracotta
|
||||
| SiteKind::Adlet => show_dungeons,
|
||||
SiteKind::Castle => show_castles,
|
||||
@ -1113,6 +1119,7 @@ impl<'a> Widget for Map<'a> {
|
||||
| SiteKind::ChapelSite
|
||||
| SiteKind::Haniwa
|
||||
| SiteKind::Cultist
|
||||
| SiteKind::Sahagin
|
||||
| SiteKind::Terracotta
|
||||
| SiteKind::Adlet => {
|
||||
if show_dungeons {
|
||||
|
@ -707,6 +707,7 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
SiteKind::Gnarling => Some(0),
|
||||
SiteKind::Bridge => None,
|
||||
SiteKind::Adlet => Some(1),
|
||||
SiteKind::Sahagin => Some(2),
|
||||
SiteKind::Haniwa => Some(3),
|
||||
SiteKind::Cultist => Some(5),
|
||||
SiteKind::DwarvenMine => Some(5),
|
||||
@ -725,6 +726,7 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
SiteKind::Adlet => self.imgs.mmap_site_adlet_bg,
|
||||
SiteKind::Haniwa => self.imgs.mmap_site_haniwa_bg,
|
||||
SiteKind::Cultist => self.imgs.mmap_site_cultist_bg,
|
||||
SiteKind::Sahagin => self.imgs.mmap_site_sahagin_bg,
|
||||
SiteKind::DwarvenMine => self.imgs.mmap_site_mine_bg,
|
||||
})
|
||||
.x_y_position_relative_to(
|
||||
@ -756,6 +758,7 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
SiteKind::Adlet => self.imgs.mmap_site_adlet,
|
||||
SiteKind::Haniwa => self.imgs.mmap_site_haniwa,
|
||||
SiteKind::Cultist => self.imgs.mmap_site_cultist,
|
||||
SiteKind::Sahagin => self.imgs.mmap_site_sahagin,
|
||||
SiteKind::DwarvenMine => self.imgs.mmap_site_mine,
|
||||
})
|
||||
.middle_of(state.ids.mmap_site_icons_bgs[i])
|
||||
|
@ -5312,6 +5312,7 @@ pub fn get_sprite_desc(sprite: SpriteKind, localized_strings: &Localization) ->
|
||||
| SpriteKind::DungeonChest3
|
||||
| SpriteKind::DungeonChest4
|
||||
| SpriteKind::DungeonChest5
|
||||
| SpriteKind::SahaginChest
|
||||
| SpriteKind::TerracottaChest => "common-sprite-chest",
|
||||
SpriteKind::Mud => "common-sprite-mud",
|
||||
SpriteKind::Grave => "common-sprite-grave",
|
||||
|
@ -389,6 +389,17 @@ pub fn block_from_structure(
|
||||
}),
|
||||
));
|
||||
},
|
||||
StructureBlock::SahaginKeyhole(consumes) => {
|
||||
return Some((
|
||||
Block::air(SpriteKind::SahaginKeyhole),
|
||||
Some(SpriteCfg {
|
||||
unlock: Some(UnlockKind::Consumes(ItemDefinitionIdOwned::Simple(
|
||||
consumes.clone(),
|
||||
))),
|
||||
..SpriteCfg::default()
|
||||
}),
|
||||
));
|
||||
},
|
||||
StructureBlock::RedwoodWood => {
|
||||
let wpos = pos + structure_pos;
|
||||
if (wpos.x / 2 + wpos.y) % 5 > 1 && ((wpos.x + 1) / 2 + wpos.y + 2) % 5 > 1 {
|
||||
|
@ -278,7 +278,7 @@ impl Civs {
|
||||
let world_dims = ctx.sim.get_aabr();
|
||||
for _ in 0..initial_civ_count * 3 {
|
||||
attempt(5, || {
|
||||
let (loc, kind) = match ctx.rng.gen_range(0..95) {
|
||||
let (loc, kind) = match ctx.rng.gen_range(0..101) {
|
||||
0..=4 => {
|
||||
if index.features().site2_giant_trees {
|
||||
(
|
||||
@ -424,7 +424,17 @@ impl Civs {
|
||||
)?,
|
||||
SiteKind::Cultist,
|
||||
),
|
||||
/*97..=102 => (
|
||||
91..=95 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.sahagin_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Sahagin,
|
||||
)?,
|
||||
SiteKind::Sahagin,
|
||||
),
|
||||
/*96..=109 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
@ -435,7 +445,7 @@ impl Civs {
|
||||
)?,
|
||||
SiteKind::Castle,
|
||||
),
|
||||
103..=108 => (SiteKind::Citadel, (&castle_enemies, 20)),
|
||||
110..=115 => (SiteKind::Citadel, (&castle_enemies, 20)),
|
||||
*/
|
||||
_ => (
|
||||
find_site_loc(
|
||||
@ -491,6 +501,7 @@ impl Civs {
|
||||
SiteKind::Camp => (4i32, 1.5),
|
||||
SiteKind::DwarvenMine => (8i32, 3.0),
|
||||
SiteKind::Cultist => (24i32, 10.0),
|
||||
SiteKind::Sahagin => (8i32, 3.0),
|
||||
};
|
||||
|
||||
let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind {
|
||||
@ -679,6 +690,12 @@ impl Civs {
|
||||
&mut rng,
|
||||
wpos,
|
||||
)),
|
||||
SiteKind::Sahagin => WorldSite::sahagin(site2::Site::generate_sahagin(
|
||||
&Land::from_sim(ctx.sim),
|
||||
index_ref,
|
||||
&mut rng,
|
||||
wpos,
|
||||
)),
|
||||
}
|
||||
});
|
||||
sim_site.site_tmp = Some(site);
|
||||
@ -1625,6 +1642,13 @@ impl Civs {
|
||||
})
|
||||
}
|
||||
|
||||
fn sahagin_enemies(&self) -> impl Iterator<Item = Vec2<i32>> + '_ {
|
||||
self.sites().filter_map(|s| match s.kind {
|
||||
SiteKind::Tree | SiteKind::GiantTree => None,
|
||||
_ => Some(s.center),
|
||||
})
|
||||
}
|
||||
|
||||
fn rock_circle_enemies(&self) -> impl Iterator<Item = Vec2<i32>> + '_ {
|
||||
self.sites().filter_map(|s| match s.kind {
|
||||
SiteKind::Tree | SiteKind::GiantTree => None,
|
||||
@ -1988,6 +2012,7 @@ pub enum SiteKind {
|
||||
DwarvenMine,
|
||||
JungleRuin,
|
||||
Cultist,
|
||||
Sahagin,
|
||||
}
|
||||
|
||||
impl SiteKind {
|
||||
@ -2069,6 +2094,10 @@ impl SiteKind {
|
||||
SiteKind::PirateHideout => {
|
||||
(0.5..3.5).contains(&(chunk.water_alt - CONFIG.sea_level))
|
||||
},
|
||||
SiteKind::Sahagin => {
|
||||
matches!(chunk.get_biome(), BiomeKind::Ocean)
|
||||
&& (40.0..45.0).contains(&(CONFIG.sea_level - chunk.alt))
|
||||
},
|
||||
SiteKind::JungleRuin => {
|
||||
matches!(chunk.get_biome(), BiomeKind::Jungle)
|
||||
},
|
||||
|
@ -218,6 +218,7 @@ impl World {
|
||||
civ::SiteKind::Citadel => world_msg::SiteKind::Castle,
|
||||
civ::SiteKind::Bridge(_, _) => world_msg::SiteKind::Bridge,
|
||||
civ::SiteKind::Cultist => world_msg::SiteKind::Cultist,
|
||||
civ::SiteKind::Sahagin => world_msg::SiteKind::Sahagin,
|
||||
civ::SiteKind::Adlet => world_msg::SiteKind::Adlet,
|
||||
civ::SiteKind::Haniwa => world_msg::SiteKind::Haniwa,
|
||||
},
|
||||
|
@ -132,6 +132,7 @@ impl Environment {
|
||||
SiteKind::Gnarling(_) => {},
|
||||
SiteKind::Adlet(_) => {},
|
||||
SiteKind::Cultist(_) => {},
|
||||
SiteKind::Sahagin(_) => {},
|
||||
SiteKind::Haniwa(_) => {},
|
||||
SiteKind::JungleRuin(_) => {},
|
||||
SiteKind::ChapelSite(_) => {},
|
||||
|
@ -85,6 +85,7 @@ pub enum SiteKind {
|
||||
TrollCave(site2::Site),
|
||||
Camp(site2::Site),
|
||||
Cultist(site2::Site),
|
||||
Sahagin(site2::Site),
|
||||
}
|
||||
|
||||
impl Site {
|
||||
@ -214,6 +215,13 @@ impl Site {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sahagin(sg: site2::Site) -> Self {
|
||||
Self {
|
||||
kind: SiteKind::Sahagin(sg),
|
||||
economy: Economy::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dwarven_mine(dm: site2::Site) -> Self {
|
||||
Self {
|
||||
kind: SiteKind::DwarvenMine(dm),
|
||||
@ -274,6 +282,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.radius(),
|
||||
SiteKind::Haniwa(ha) => ha.radius(),
|
||||
SiteKind::Cultist(cl) => cl.radius(),
|
||||
SiteKind::Sahagin(sg) => sg.radius(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,6 +311,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.origin,
|
||||
SiteKind::Haniwa(ha) => ha.origin,
|
||||
SiteKind::Cultist(cl) => cl.origin,
|
||||
SiteKind::Sahagin(sg) => sg.origin,
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,6 +340,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.spawn_rules(wpos),
|
||||
SiteKind::Haniwa(ha) => ha.spawn_rules(wpos),
|
||||
SiteKind::Cultist(cl) => cl.spawn_rules(wpos),
|
||||
SiteKind::Sahagin(sg) => sg.spawn_rules(wpos),
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,6 +369,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.name(),
|
||||
SiteKind::Haniwa(ha) => ha.name(),
|
||||
SiteKind::Cultist(cl) => cl.name(),
|
||||
SiteKind::Sahagin(sg) => sg.name(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,6 +418,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.render(canvas, dynamic_rng),
|
||||
SiteKind::Haniwa(ha) => ha.render(canvas, dynamic_rng),
|
||||
SiteKind::Cultist(cl) => cl.render(canvas, dynamic_rng),
|
||||
SiteKind::Sahagin(sg) => sg.render(canvas, dynamic_rng),
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,6 +461,7 @@ impl Site {
|
||||
SiteKind::Adlet(ad) => ad.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||
SiteKind::Haniwa(ha) => ha.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||
SiteKind::Cultist(cl) => cl.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||
SiteKind::Sahagin(sg) => sg.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,6 +504,7 @@ impl Site {
|
||||
SiteKind::Adlet(site2) => Some(site2),
|
||||
SiteKind::Haniwa(site2) => Some(site2),
|
||||
SiteKind::Cultist(site2) => Some(site2),
|
||||
SiteKind::Sahagin(site2) => Some(site2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ impl Site {
|
||||
PlotKind::TerracottaHouse(th) => Some(th.spawn_rules(wpos)),
|
||||
PlotKind::TerracottaYard(ty) => Some(ty.spawn_rules(wpos)),
|
||||
PlotKind::Cultist(cl) => Some(cl.spawn_rules(wpos)),
|
||||
PlotKind::Sahagin(sg) => Some(sg.spawn_rules(wpos)),
|
||||
PlotKind::DwarvenMine(dm) => Some(dm.spawn_rules(wpos)),
|
||||
_ => None,
|
||||
})
|
||||
@ -1731,7 +1732,6 @@ impl Site {
|
||||
let mut rng = reseed(rng);
|
||||
let mut site = Site {
|
||||
origin,
|
||||
|
||||
name: {
|
||||
let name = NameGen::location(&mut rng).generate();
|
||||
match rng.gen_range(0..5) {
|
||||
@ -1742,8 +1742,6 @@ impl Site {
|
||||
_ => format!("{} Pit", name),
|
||||
}
|
||||
},
|
||||
|
||||
//name: NameGen::location(&mut rng).generate_adlet(),
|
||||
..Site::default()
|
||||
};
|
||||
let size = 22.0 as i32;
|
||||
@ -1770,6 +1768,51 @@ impl Site {
|
||||
site
|
||||
}
|
||||
|
||||
pub fn generate_sahagin(
|
||||
land: &Land,
|
||||
index: IndexRef,
|
||||
rng: &mut impl Rng,
|
||||
origin: Vec2<i32>,
|
||||
) -> Self {
|
||||
let mut rng = reseed(rng);
|
||||
let mut site = Site {
|
||||
origin,
|
||||
name: {
|
||||
let name = NameGen::location(&mut rng).generate();
|
||||
match rng.gen_range(0..4) {
|
||||
0 => format!("{} Isle", name),
|
||||
1 => format!("{} Islet", name),
|
||||
2 => format!("{} Key", name),
|
||||
3 => format!("{} Cay", name),
|
||||
_ => format!("{} Rock", name),
|
||||
}
|
||||
},
|
||||
..Site::default()
|
||||
};
|
||||
let size = 16.0 as i32;
|
||||
let aabr = Aabr {
|
||||
min: Vec2::broadcast(-size),
|
||||
max: Vec2::broadcast(size),
|
||||
};
|
||||
{
|
||||
let sahagin = plot::Sahagin::generate(land, index, &mut reseed(&mut rng), &site, aabr);
|
||||
let sahagin_alt = sahagin.alt;
|
||||
let plot = site.create_plot(Plot {
|
||||
kind: PlotKind::Sahagin(sahagin),
|
||||
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(sahagin_alt),
|
||||
});
|
||||
}
|
||||
site
|
||||
}
|
||||
|
||||
pub fn generate_bridge(
|
||||
land: &Land,
|
||||
index: IndexRef,
|
||||
@ -2112,6 +2155,7 @@ 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::Sahagin(sahagin) => sahagin.render_collect(self, canvas),
|
||||
PlotKind::SavannahPit(savannah_pit) => savannah_pit.render_collect(self, canvas),
|
||||
PlotKind::SavannahHut(savannah_hut) => savannah_hut.render_collect(self, canvas),
|
||||
PlotKind::SavannahWorkshop(savannah_workshop) => {
|
||||
|
@ -20,6 +20,7 @@ mod house;
|
||||
mod jungle_ruin;
|
||||
mod pirate_hideout;
|
||||
mod rock_circle;
|
||||
mod sahagin;
|
||||
mod savannah_hut;
|
||||
mod savannah_pit;
|
||||
mod savannah_workshop;
|
||||
@ -38,10 +39,11 @@ pub use self::{
|
||||
desert_city_multiplot::DesertCityMultiPlot, desert_city_temple::DesertCityTemple,
|
||||
dungeon::Dungeon, dwarven_mine::DwarvenMine, giant_tree::GiantTree,
|
||||
gnarling::GnarlingFortification, haniwa::Haniwa, house::House, jungle_ruin::JungleRuin,
|
||||
pirate_hideout::PirateHideout, rock_circle::RockCircle, savannah_hut::SavannahHut,
|
||||
savannah_pit::SavannahPit, savannah_workshop::SavannahWorkshop, sea_chapel::SeaChapel,
|
||||
tavern::Tavern, terracotta_house::TerracottaHouse, terracotta_palace::TerracottaPalace,
|
||||
terracotta_yard::TerracottaYard, troll_cave::TrollCave, workshop::Workshop,
|
||||
pirate_hideout::PirateHideout, rock_circle::RockCircle, sahagin::Sahagin,
|
||||
savannah_hut::SavannahHut, savannah_pit::SavannahPit, savannah_workshop::SavannahWorkshop,
|
||||
sea_chapel::SeaChapel, tavern::Tavern, terracotta_house::TerracottaHouse,
|
||||
terracotta_palace::TerracottaPalace, terracotta_yard::TerracottaYard, troll_cave::TrollCave,
|
||||
workshop::Workshop,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -103,6 +105,7 @@ pub enum PlotKind {
|
||||
Haniwa(Haniwa),
|
||||
GiantTree(GiantTree),
|
||||
CliffTower(CliffTower),
|
||||
Sahagin(Sahagin),
|
||||
Citadel(Citadel),
|
||||
SavannahPit(SavannahPit),
|
||||
SavannahHut(SavannahHut),
|
||||
|
@ -229,7 +229,6 @@ impl Room {
|
||||
// Toss mobs in the center of the room
|
||||
if tile_pos == enemy_spawn_tile && wpos2d == tile_wcenter.xy() {
|
||||
let entities = match self.difficulty {
|
||||
2 => enemy_2(dynamic_rng, tile_wcenter),
|
||||
4 => enemy_4(dynamic_rng, tile_wcenter),
|
||||
_ => enemy_fallback(dynamic_rng, tile_wcenter),
|
||||
};
|
||||
@ -259,7 +258,6 @@ impl Room {
|
||||
|
||||
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let entities = match self.difficulty {
|
||||
2 => mini_boss_2(dynamic_rng, tile_wcenter),
|
||||
4 => mini_boss_4(dynamic_rng, tile_wcenter),
|
||||
_ => mini_boss_fallback(dynamic_rng, tile_wcenter),
|
||||
};
|
||||
@ -289,7 +287,6 @@ impl Room {
|
||||
|
||||
if tile_pos == boss_spawn_tile && wpos2d == tile_wcenter.xy() {
|
||||
let entities = match self.difficulty {
|
||||
2 => boss_2(dynamic_rng, tile_wcenter),
|
||||
4 => boss_4(dynamic_rng, tile_wcenter),
|
||||
_ => boss_fallback(dynamic_rng, tile_wcenter),
|
||||
};
|
||||
@ -669,32 +666,6 @@ impl Floor {
|
||||
}
|
||||
}
|
||||
|
||||
fn enemy_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let number = dynamic_rng.gen_range(2..=4);
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(number, || {
|
||||
// TODO: give enemies health skills?
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
match dynamic_rng.gen_range(0..=4) {
|
||||
0 => {
|
||||
entity.with_asset_expect("common.entity.dungeon.sahagin.sniper", dynamic_rng, None)
|
||||
},
|
||||
1 => entity.with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.sorcerer",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
_ => entity.with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.spearman",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let number = dynamic_rng.gen_range(2..=4);
|
||||
let mut entities = Vec::new();
|
||||
@ -734,16 +705,6 @@ fn enemy_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<En
|
||||
entities
|
||||
}
|
||||
|
||||
fn boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.tidalwarrior",
|
||||
dynamic_rng,
|
||||
None,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
fn boss_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
@ -764,18 +725,6 @@ fn boss_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<Ent
|
||||
]
|
||||
}
|
||||
|
||||
fn mini_boss_2(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(dynamic_rng.gen_range(1..=2), || {
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.hakulaq",
|
||||
dynamic_rng,
|
||||
None,
|
||||
)
|
||||
});
|
||||
entities
|
||||
}
|
||||
|
||||
fn mini_boss_4(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
vec![
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32)).with_asset_expect(
|
||||
@ -1376,7 +1325,6 @@ mod tests {
|
||||
fn test_creating_bosses() {
|
||||
let mut dynamic_rng = thread_rng();
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
boss_2(&mut dynamic_rng, tile_wcenter);
|
||||
boss_4(&mut dynamic_rng, tile_wcenter);
|
||||
boss_fallback(&mut dynamic_rng, tile_wcenter);
|
||||
}
|
||||
@ -1386,7 +1334,6 @@ mod tests {
|
||||
fn test_creating_enemies() {
|
||||
let mut dynamic_rng = thread_rng();
|
||||
let random_position = Vec3::new(0, 0, 0);
|
||||
enemy_2(&mut dynamic_rng, random_position);
|
||||
enemy_4(&mut dynamic_rng, random_position);
|
||||
enemy_fallback(&mut dynamic_rng, random_position);
|
||||
}
|
||||
@ -1396,7 +1343,6 @@ mod tests {
|
||||
fn test_creating_minibosses() {
|
||||
let mut dynamic_rng = thread_rng();
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
mini_boss_2(&mut dynamic_rng, tile_wcenter);
|
||||
mini_boss_4(&mut dynamic_rng, tile_wcenter);
|
||||
mini_boss_fallback(&mut dynamic_rng, tile_wcenter);
|
||||
}
|
||||
|
758
world/src/site2/plot/sahagin.rs
Normal file
758
world/src/site2/plot/sahagin.rs
Normal file
@ -0,0 +1,758 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
site2::{plot::dungeon::spiral_staircase, util::gradient::WrapMode},
|
||||
util::{sampler::Sampler, RandomField},
|
||||
Land,
|
||||
};
|
||||
use common::generation::EntityInfo;
|
||||
use rand::prelude::*;
|
||||
use std::{f32::consts::TAU, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
pub struct Sahagin {
|
||||
bounds: Aabr<i32>,
|
||||
pub(crate) alt: i32,
|
||||
surface_color: Rgb<f32>,
|
||||
sub_surface_color: Rgb<f32>,
|
||||
pub(crate) center: Vec2<i32>,
|
||||
pub(crate) rooms: Vec<Vec2<i32>>,
|
||||
pub(crate) room_size: i32,
|
||||
}
|
||||
impl Sahagin {
|
||||
pub fn generate(
|
||||
land: &Land,
|
||||
index: IndexRef,
|
||||
_rng: &mut impl Rng,
|
||||
site: &Site,
|
||||
tile_aabr: Aabr<i32>,
|
||||
) -> Self {
|
||||
let bounds = Aabr {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
};
|
||||
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))
|
||||
};
|
||||
let room_size = 30;
|
||||
let center = bounds.center();
|
||||
let outer_room_radius = (room_size * 2) + (room_size / 3);
|
||||
|
||||
let outer_rooms = place_circular(center, outer_room_radius as f32, 5);
|
||||
let mut rooms = vec![center];
|
||||
rooms.extend(outer_rooms);
|
||||
|
||||
Self {
|
||||
bounds,
|
||||
alt: CONFIG.sea_level as i32,
|
||||
surface_color,
|
||||
sub_surface_color,
|
||||
center,
|
||||
rooms,
|
||||
room_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
||||
SpawnRules {
|
||||
waypoints: false,
|
||||
trees: wpos.distance_squared(self.bounds.center()) > (75_i32).pow(2),
|
||||
..SpawnRules::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for Sahagin {
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
const UPDATE_FN: &'static [u8] = b"render_sahagin\0";
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_sahagin")]
|
||||
fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||
let room_size = self.room_size;
|
||||
let center = self.center;
|
||||
let base = self.alt - room_size + 1;
|
||||
let rooms = &self.rooms;
|
||||
let mut thread_rng = thread_rng();
|
||||
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(center.x as f32, center.y as f32, (base + 1) as f32);
|
||||
let gradient_var_1 = RandomField::new(0).get(center.with_z(base)) as i32 % 8;
|
||||
let gradient_var_2 = RandomField::new(0).get(center.with_z(base + 1)) as i32 % 10;
|
||||
let mut random_npcs = vec![];
|
||||
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 jellyfish = Fill::Gradient(
|
||||
util::gradient::Gradient::new(
|
||||
gradient_center,
|
||||
8.0 + gradient_var_1 as f32,
|
||||
util::gradient::Shape::Point,
|
||||
(Rgb::new(180, 181, 227), Rgb::new(120, 160, 255)),
|
||||
)
|
||||
.with_repeat(if gradient_var_2 > 5 {
|
||||
WrapMode::Repeat
|
||||
} else {
|
||||
WrapMode::PingPong
|
||||
}),
|
||||
BlockKind::GlowingRock,
|
||||
);
|
||||
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::GlowingRock, Rgb::new(255, 244, 193)),
|
||||
})
|
||||
}));
|
||||
let wood = Fill::Brick(BlockKind::Wood, Rgb::new(71, 33, 11), 12);
|
||||
let key_door = Fill::Block(Block::air(SpriteKind::SahaginKeyDoor));
|
||||
let key_hole = Fill::Block(Block::air(SpriteKind::SahaginKeyhole));
|
||||
let rope = Fill::Block(Block::air(SpriteKind::Rope));
|
||||
let room_size = 30;
|
||||
let cell_size_raw = room_size / 6;
|
||||
let ground_floor = base - (room_size * 2);
|
||||
let outer_room_radius = (room_size * 2) + (room_size / 3);
|
||||
let tunnel_radius = (room_size * 3) + 6;
|
||||
let tunnel_points = place_circular(center, tunnel_radius as f32, 25);
|
||||
let scaler = -10;
|
||||
let height_handle = -room_size;
|
||||
let shell_radius = 3 * (room_size / 2) + scaler;
|
||||
let shell_carve_radius = 6 * (room_size / 2) + scaler;
|
||||
let shell_base = base + (room_size * 1) + height_handle;
|
||||
let high_carve_base = base + (room_size * 7) + height_handle;
|
||||
let low_carve_base = base + height_handle;
|
||||
let shell_carve_limiter_1 = painter.aabb(Aabb {
|
||||
min: (center - shell_radius - 6).with_z(shell_base),
|
||||
max: (center + shell_radius + 6).with_z(shell_base + (5 * shell_radius)),
|
||||
});
|
||||
|
||||
let shell_carve_limiter_2 = painter.aabb(Aabb {
|
||||
min: (center - shell_radius).with_z(base + (room_size + 2) - 2),
|
||||
max: (center + shell_radius).with_z(shell_base + (5 * shell_radius)),
|
||||
});
|
||||
painter
|
||||
.cylinder_with_radius(
|
||||
center.with_z(shell_base),
|
||||
shell_radius as f32,
|
||||
5.0 * shell_radius as f32,
|
||||
)
|
||||
.intersect(shell_carve_limiter_2)
|
||||
.fill(white.clone());
|
||||
// decor bubbles
|
||||
let decor_radius = room_size / 3;
|
||||
for b in 3..=7 {
|
||||
let shell_decor = place_circular(center, (shell_radius - 2) as f32, 3 * b);
|
||||
|
||||
for pos in shell_decor {
|
||||
let decor_var = 3 + RandomField::new(0).get(pos.with_z(base)) as i32 % 3;
|
||||
|
||||
painter
|
||||
.sphere_with_radius(
|
||||
pos.with_z(shell_base + (b * (shell_radius / 2))),
|
||||
(decor_radius - decor_var) as f32,
|
||||
)
|
||||
.fill(white.clone());
|
||||
}
|
||||
}
|
||||
// shell carves
|
||||
painter
|
||||
.sphere_with_radius(
|
||||
(center - room_size).with_z(high_carve_base),
|
||||
shell_carve_radius as f32,
|
||||
)
|
||||
.intersect(shell_carve_limiter_1)
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.sphere_with_radius(
|
||||
(center + (room_size / 2)).with_z(low_carve_base),
|
||||
shell_carve_radius as f32,
|
||||
)
|
||||
.intersect(shell_carve_limiter_2)
|
||||
.clear();
|
||||
// clear room
|
||||
painter
|
||||
.cylinder_with_radius(
|
||||
center.with_z(shell_base + (3 * (shell_radius / 2))),
|
||||
(shell_radius - 8) as f32,
|
||||
shell_radius as f32,
|
||||
)
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.sphere_with_radius(
|
||||
center.with_z(shell_base + (5 * (shell_radius / 2)) - 5),
|
||||
(shell_radius - 8) as f32,
|
||||
)
|
||||
.clear();
|
||||
let boss_pos = center.with_z(shell_base + (3 * (shell_radius / 2)));
|
||||
painter.spawn(EntityInfo::at(boss_pos.as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.tidalwarrior",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
));
|
||||
// overground towers
|
||||
let var_towers = 32 + RandomField::new(0).get(center.with_z(base)) as i32 % 6;
|
||||
let tower_positions = place_circular(center, (5 * (room_size / 2)) as f32, var_towers);
|
||||
|
||||
for tower_center_pos in tower_positions {
|
||||
for dir in CARDINALS {
|
||||
let tower_center = tower_center_pos + dir * 5;
|
||||
let var_height =
|
||||
RandomField::new(0).get(tower_center.with_z(base)) as i32 % (room_size / 2);
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (tower_center - 10).with_z(base - room_size),
|
||||
max: (tower_center + 10).with_z(base + (3 * (room_size / 2)) + var_height),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
}
|
||||
}
|
||||
let bldg_base = base + room_size;
|
||||
let bldgs = var_towers / 3;
|
||||
let beam_th = 2.5;
|
||||
let bldg_positions = place_circular(center, (5 * (room_size / 2)) as f32, bldgs);
|
||||
// buildings
|
||||
for bldg_center in &bldg_positions {
|
||||
let bldg_size = ((room_size / 4) + 1)
|
||||
+ RandomField::new(0).get(bldg_center.with_z(bldg_base)) as i32 % 3;
|
||||
let points = 21;
|
||||
let ring_0 = place_circular(*bldg_center, (4 * (bldg_size / 2)) as f32, points);
|
||||
let ring_1 = place_circular(*bldg_center, (9 * (bldg_size / 2)) as f32, points);
|
||||
let ring_2 = place_circular(*bldg_center, (4 * (bldg_size / 2)) as f32, points);
|
||||
let ring_3 = place_circular(*bldg_center, (2 * (bldg_size / 2)) as f32, points);
|
||||
|
||||
let ring_4 = place_circular(*bldg_center, (6 * (bldg_size / 2)) as f32, points);
|
||||
let ring_5 = place_circular(*bldg_center, (4 * (bldg_size / 2)) as f32, points);
|
||||
let ring_6 = place_circular(*bldg_center, (2 * (bldg_size / 2)) as f32, points);
|
||||
|
||||
for b in 0..=(ring_0.len() - 1) {
|
||||
painter
|
||||
.cubic_bezier(
|
||||
ring_0[b].with_z(bldg_base + (3 * (bldg_size / 2))),
|
||||
ring_1[b].with_z(bldg_base + (5 * (bldg_size / 2))),
|
||||
ring_2[b].with_z(bldg_base + (10 * (bldg_size / 2))),
|
||||
ring_3[b].with_z(bldg_base + (14 * (bldg_size / 2))),
|
||||
beam_th,
|
||||
)
|
||||
.fill(jellyfish.clone());
|
||||
if b == (ring_0.len() - 2) {
|
||||
painter
|
||||
.cubic_bezier(
|
||||
ring_4[b].with_z(bldg_base + (12 * (bldg_size / 2))),
|
||||
ring_5[b + 1].with_z(bldg_base + (14 * (bldg_size / 2))),
|
||||
ring_6[0].with_z(bldg_base + (16 * (bldg_size / 2))),
|
||||
bldg_center.with_z(bldg_base + (18 * (bldg_size / 2))),
|
||||
beam_th,
|
||||
)
|
||||
.fill(jellyfish.clone());
|
||||
} else if b == (ring_0.len() - 1) {
|
||||
painter
|
||||
.cubic_bezier(
|
||||
ring_4[b].with_z(bldg_base + (12 * (bldg_size / 2))),
|
||||
ring_5[0].with_z(bldg_base + (14 * (bldg_size / 2))),
|
||||
ring_6[1].with_z(bldg_base + (16 * (bldg_size / 2))),
|
||||
bldg_center.with_z(bldg_base + (18 * (bldg_size / 2))),
|
||||
beam_th,
|
||||
)
|
||||
.fill(jellyfish.clone());
|
||||
} else {
|
||||
painter
|
||||
.cubic_bezier(
|
||||
ring_4[b].with_z(bldg_base + (12 * (bldg_size / 2))),
|
||||
ring_5[b + 1].with_z(bldg_base + (14 * (bldg_size / 2))),
|
||||
ring_6[b + 2].with_z(bldg_base + (16 * (bldg_size / 2))),
|
||||
bldg_center.with_z(bldg_base + (18 * (bldg_size / 2))),
|
||||
beam_th,
|
||||
)
|
||||
.fill(jellyfish.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
let key_chest_index_1 =
|
||||
RandomField::new(0).get(center.with_z(base)) as usize % bldgs as usize;
|
||||
for (p, bldg_center) in bldg_positions.iter().enumerate() {
|
||||
let bldg_size = ((room_size / 4) + 1)
|
||||
+ RandomField::new(0).get(bldg_center.with_z(bldg_base)) as i32 % 3;
|
||||
|
||||
// passage
|
||||
|
||||
if p == (bldg_positions.len() - 1) {
|
||||
painter
|
||||
.line(
|
||||
bldg_positions[p].with_z(bldg_base + (5 * (bldg_size / 2))),
|
||||
bldg_positions[0].with_z(bldg_base + (5 * (bldg_size / 2))),
|
||||
beam_th * 2.0,
|
||||
)
|
||||
.clear();
|
||||
} else {
|
||||
painter
|
||||
.line(
|
||||
bldg_positions[p].with_z(bldg_base + (5 * (bldg_size / 2))),
|
||||
bldg_positions[p + 1].with_z(bldg_base + (5 * (bldg_size / 2))),
|
||||
beam_th * 2.0,
|
||||
)
|
||||
.clear();
|
||||
}
|
||||
// floor
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (bldg_center - (2 * bldg_size) - 2).with_z(base),
|
||||
max: (bldg_center + (2 * bldg_size) + 2)
|
||||
.with_z(bldg_base + (5 * (bldg_size / 2)) - 4),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
let chest_pos = bldg_center - 4;
|
||||
if p == key_chest_index_1 {
|
||||
painter.sprite(
|
||||
chest_pos.with_z(bldg_base + (9 * (bldg_size / 2))),
|
||||
SpriteKind::SahaginChest,
|
||||
);
|
||||
}
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (chest_pos - 2).with_z(bldg_base + (9 * (bldg_size / 2)) - 1),
|
||||
max: (chest_pos + 3).with_z(bldg_base + (9 * (bldg_size / 2))),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
|
||||
random_npcs.push(chest_pos.with_z(bldg_base + (9 * (bldg_size / 2)) + 1));
|
||||
}
|
||||
for bldg_center in bldg_positions {
|
||||
let bldg_size = ((room_size / 4) + 1)
|
||||
+ RandomField::new(0).get(bldg_center.with_z(bldg_base)) as i32 % 3;
|
||||
|
||||
// center spear
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (bldg_center - 3).with_z(bldg_base),
|
||||
max: (bldg_center + 3).with_z(bldg_base + (20 * (bldg_size / 2))),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cone(Aabb {
|
||||
min: (bldg_center - 4).with_z(bldg_base + (20 * (bldg_size / 2))),
|
||||
max: (bldg_center + 4).with_z(bldg_base + (30 * (bldg_size / 2))),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
}
|
||||
|
||||
// underground
|
||||
// rooms
|
||||
for room_center in rooms {
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (room_center - room_size - (room_size / 2)).with_z(ground_floor),
|
||||
max: (room_center + room_size + (room_size / 2)).with_z(base + 5),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
}
|
||||
let key_chest_index_2 = RandomField::new(0).get(center.with_z(base)) as usize % rooms.len();
|
||||
for (r, room_center) in rooms.iter().enumerate() {
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (room_center - room_size).with_z(ground_floor + 1),
|
||||
max: (room_center + room_size).with_z(base - 2),
|
||||
})
|
||||
.clear();
|
||||
let cells = place_circular(*room_center, room_size as f32, room_size / 2);
|
||||
let spawns = place_circular(*room_center, (room_size + 2) as f32, room_size / 2);
|
||||
let cell_floors = (room_size / 6) - 1;
|
||||
for f in 0..cell_floors {
|
||||
let cell_floor = ground_floor + (room_size / 2) + ((cell_size_raw * 2) * f);
|
||||
for cell_pos in &cells {
|
||||
let cell_var = RandomField::new(0).get(cell_pos.with_z(cell_floor)) as i32 % 2;
|
||||
let cell_size = cell_size_raw + cell_var;
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (cell_pos - cell_size).with_z(cell_floor - cell_size),
|
||||
max: (cell_pos + cell_size).with_z(cell_floor + cell_size),
|
||||
})
|
||||
.clear();
|
||||
}
|
||||
for spawn_pos in &spawns {
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (spawn_pos - 3).with_z(cell_floor - cell_size_raw - 1),
|
||||
max: (spawn_pos + 4).with_z(cell_floor - cell_size_raw),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (spawn_pos - 2).with_z(cell_floor - cell_size_raw),
|
||||
max: (spawn_pos + 3).with_z(cell_floor - cell_size_raw + 1),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (spawn_pos - 1).with_z(cell_floor - cell_size_raw + 1),
|
||||
max: (spawn_pos + 2).with_z(cell_floor - cell_size_raw + 2),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
painter.sprite(
|
||||
spawn_pos.with_z(cell_floor - cell_size_raw + 2),
|
||||
match (RandomField::new(0)
|
||||
.get(spawn_pos.with_z(cell_floor - cell_size_raw)))
|
||||
% 75
|
||||
{
|
||||
0 => SpriteKind::DungeonChest2,
|
||||
_ => SpriteKind::FireBowlGround,
|
||||
},
|
||||
);
|
||||
|
||||
let npc_pos = spawn_pos.with_z(cell_floor - cell_size_raw + 3);
|
||||
if RandomField::new(0).get(npc_pos) as i32 % 5 == 1 {
|
||||
random_npcs.push(npc_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// solid floor
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: (room_center - room_size).with_z(ground_floor),
|
||||
max: (room_center + room_size).with_z(ground_floor + (room_size / 3)),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
|
||||
for m in 0..2 {
|
||||
let mini_boss_pos = room_center.with_z(ground_floor + (room_size / 3));
|
||||
painter.spawn(
|
||||
EntityInfo::at((mini_boss_pos + (1 * m)).as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.hakulaq",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
if r == key_chest_index_2 {
|
||||
painter.sprite(
|
||||
(room_center - 1).with_z(ground_floor + (room_size / 3)),
|
||||
SpriteKind::SahaginChest,
|
||||
);
|
||||
}
|
||||
|
||||
let center_entry = RandomField::new(0).get(center.with_z(base)) % 4;
|
||||
|
||||
if r > 0 {
|
||||
// overground - keep center clear
|
||||
let rooms_center =
|
||||
place_circular(center, (outer_room_radius - 15) as f32, room_size / 2);
|
||||
let room_base = base - (room_size / 2) + (room_size / 2);
|
||||
for room_center in &rooms_center {
|
||||
let room_var =
|
||||
RandomField::new(0).get(room_center.with_z(room_base)) as i32 % 10;
|
||||
let room_var_size = room_size - room_var;
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (room_center - room_var_size).with_z(room_base),
|
||||
max: (room_center + room_var_size).with_z(room_base + room_var_size),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
}
|
||||
if r == (center_entry + 1) as usize {
|
||||
painter
|
||||
.line(
|
||||
room_center.with_z(ground_floor + room_size),
|
||||
center.with_z(ground_floor + room_size),
|
||||
15.0,
|
||||
)
|
||||
.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
// tunnels
|
||||
for p in 0..tunnel_points.len() {
|
||||
if p == tunnel_points.len() - 1 {
|
||||
painter
|
||||
.line(
|
||||
tunnel_points[p].with_z(ground_floor + (room_size / 2)),
|
||||
tunnel_points[0].with_z(ground_floor + (room_size / 2)),
|
||||
5.0,
|
||||
)
|
||||
.clear();
|
||||
} else {
|
||||
painter
|
||||
.line(
|
||||
tunnel_points[p].with_z(ground_floor + (room_size / 2)),
|
||||
tunnel_points[p + 1].with_z(ground_floor + (room_size / 2)),
|
||||
5.0,
|
||||
)
|
||||
.clear();
|
||||
}
|
||||
}
|
||||
// boss room
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (center - room_size - 10).with_z(base - 2),
|
||||
max: (center + room_size + 10).with_z(base + room_size),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
let clear_limiter = painter.aabb(Aabb {
|
||||
min: (center - room_size - 8).with_z(base + (room_size / 5)),
|
||||
max: (center + room_size + 8).with_z(base + room_size - 1),
|
||||
});
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (center - room_size - 8).with_z(base),
|
||||
max: (center + room_size + 8).with_z(base + room_size - 1),
|
||||
})
|
||||
.intersect(clear_limiter)
|
||||
.clear();
|
||||
|
||||
// lamps
|
||||
let var_lamps = 25 + RandomField::new(0).get(center.with_z(base)) as i32 % 5;
|
||||
let lamp_positions = place_circular(center, (room_size + 5) as f32, var_lamps);
|
||||
|
||||
for lamp_pos in lamp_positions {
|
||||
painter.sprite(
|
||||
lamp_pos.with_z(base + (room_size / 5)),
|
||||
SpriteKind::FireBowlGround,
|
||||
);
|
||||
}
|
||||
|
||||
// top entry and stairs
|
||||
let stair_radius = room_size / 3;
|
||||
for e in 0..=1 {
|
||||
let stairs_pos = center - (room_size / 2) + ((room_size * 2) * e);
|
||||
// top entry foundation and door
|
||||
if e > 0 {
|
||||
painter
|
||||
.rounded_aabb(Aabb {
|
||||
min: (stairs_pos - stair_radius - 5).with_z(base - (room_size / 2)),
|
||||
max: (stairs_pos + stair_radius + 5)
|
||||
.with_z(base + (room_size / 5) + (3 * (room_size / 2))),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
// door clear
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 8, stairs_pos.y - 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2))),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 7),
|
||||
})
|
||||
.clear();
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 8, stairs_pos.y - 1)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 7),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 8),
|
||||
})
|
||||
.clear();
|
||||
// door
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 1, stairs_pos.y - 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2))),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 7),
|
||||
})
|
||||
.fill(key_door.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 1, stairs_pos.y - 1)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 7),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 8),
|
||||
})
|
||||
.fill(key_door.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 1, stairs_pos.y)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 2),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 3),
|
||||
})
|
||||
.fill(key_hole.clone());
|
||||
// steps
|
||||
for s in 0..4 {
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 2 - s, stairs_pos.y - 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) - 1 - s),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius - 1 - s, stairs_pos.y + 2)
|
||||
.with_z(base + (room_size / 5) + (2 * (room_size / 2)) + 7),
|
||||
})
|
||||
.clear();
|
||||
}
|
||||
} else {
|
||||
// boss entry 1
|
||||
// tube
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (stairs_pos - stair_radius - 4).with_z(base + (room_size / 5)),
|
||||
max: (stairs_pos + stair_radius + 4).with_z(base + room_size - 2),
|
||||
})
|
||||
.fill(brick.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (stairs_pos - stair_radius).with_z(base + (room_size / 5)),
|
||||
max: (stairs_pos + stair_radius).with_z(base + room_size - 3),
|
||||
})
|
||||
.clear();
|
||||
// door clear
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 3, stairs_pos.y - 2)
|
||||
.with_z(base + (room_size / 5) + 2),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 2)
|
||||
.with_z(base + (room_size / 5) + 9),
|
||||
})
|
||||
.clear();
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 3, stairs_pos.y - 1)
|
||||
.with_z(base + (room_size / 5) + 9),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + 10),
|
||||
})
|
||||
.clear();
|
||||
// door
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 4, stairs_pos.y - 2)
|
||||
.with_z(base + (room_size / 5) + 2),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius - 3, stairs_pos.y + 2)
|
||||
.with_z(base + (room_size / 5) + 9),
|
||||
})
|
||||
.fill(key_door.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 4, stairs_pos.y - 1)
|
||||
.with_z(base + (room_size / 5) + 9),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius - 3, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + 10),
|
||||
})
|
||||
.fill(key_door.clone());
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: Vec2::new(stairs_pos.x - stair_radius - 4, stairs_pos.y)
|
||||
.with_z(base + (room_size / 5) + 3),
|
||||
max: Vec2::new(stairs_pos.x - stair_radius - 3, stairs_pos.y + 1)
|
||||
.with_z(base + (room_size / 5) + 4),
|
||||
})
|
||||
.fill(key_hole.clone());
|
||||
}
|
||||
|
||||
let stairs_clear = painter.cylinder(Aabb {
|
||||
min: (stairs_pos - stair_radius).with_z(ground_floor + (room_size / 3)),
|
||||
max: (stairs_pos + stair_radius)
|
||||
.with_z(base + (room_size / 5) + (((3 * (room_size / 2)) - 6) * e)),
|
||||
});
|
||||
stairs_clear.clear();
|
||||
stairs_clear
|
||||
.sample(spiral_staircase(
|
||||
stairs_pos.with_z(ground_floor + (room_size / 3)),
|
||||
(stair_radius + 1) as f32,
|
||||
2.5,
|
||||
(room_size - 5) as f32,
|
||||
))
|
||||
.fill(wood.clone());
|
||||
}
|
||||
|
||||
// boss entry 2
|
||||
let boss_entry_pos = center + (room_size / 3);
|
||||
let rope_pos = center + (room_size / 3) - 2;
|
||||
let spike_pos = center + (room_size / 3) - 1;
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (boss_entry_pos - stair_radius).with_z(base + room_size - 5),
|
||||
max: (boss_entry_pos + stair_radius).with_z(base + (room_size * 2) - 10),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (boss_entry_pos - 3).with_z(base + (room_size * 2) - 10),
|
||||
max: (boss_entry_pos + 4).with_z(base + (room_size * 2) - 7),
|
||||
})
|
||||
.fill(wood.clone());
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (boss_entry_pos - 2).with_z(base + room_size - 5),
|
||||
max: (boss_entry_pos + 3).with_z(base + (room_size * 2) - 7),
|
||||
})
|
||||
.clear();
|
||||
|
||||
painter
|
||||
.aabb(Aabb {
|
||||
min: rope_pos.with_z(base + (room_size / 4) + 2),
|
||||
max: (rope_pos + 1).with_z(base + room_size - 5),
|
||||
})
|
||||
.fill(rope.clone());
|
||||
|
||||
painter
|
||||
.cylinder(Aabb {
|
||||
min: (spike_pos - 3).with_z(base + (room_size * 2) - 7),
|
||||
max: (spike_pos + 4).with_z(base + (room_size * 2) - 5),
|
||||
})
|
||||
.fill(Fill::Block(Block::air(SpriteKind::IronSpike)));
|
||||
// top room npcs
|
||||
let npc_pos = boss_entry_pos;
|
||||
let amount = 4 + RandomField::new(0).get(npc_pos.with_z(base)) as i32 % 4;
|
||||
for a in 0..amount {
|
||||
random_npcs.push((npc_pos + a).with_z(base + (room_size / 4)))
|
||||
}
|
||||
for m in 0..2 {
|
||||
painter.spawn(
|
||||
EntityInfo::at(((npc_pos - m).with_z(base + (room_size / 4))).as_())
|
||||
.with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.hakulaq",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
// room npcs
|
||||
for m in 0..2 {
|
||||
let mini_boss_pos = center.with_z(base + room_size + 5);
|
||||
painter.spawn(
|
||||
EntityInfo::at((mini_boss_pos + (1 * m)).as_()).with_asset_expect(
|
||||
"common.entity.dungeon.sahagin.hakulaq",
|
||||
&mut thread_rng,
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for pos in random_npcs {
|
||||
let entities = [
|
||||
"common.entity.dungeon.sahagin.sniper",
|
||||
"common.entity.dungeon.sahagin.sniper",
|
||||
"common.entity.dungeon.sahagin.sniper",
|
||||
"common.entity.dungeon.sahagin.sorcerer",
|
||||
"common.entity.dungeon.sahagin.spearman",
|
||||
];
|
||||
let npc = entities[(RandomField::new(0).get(pos) % entities.len() as u32) as usize];
|
||||
painter.spawn(EntityInfo::at(pos.as_()).with_asset_expect(npc, &mut thread_rng, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn place_circular(center: Vec2<i32>, radius: f32, amount: i32) -> Vec<Vec2<i32>> {
|
||||
let phi = TAU / amount as f32;
|
||||
let mut positions = vec![];
|
||||
for n in 1..=amount {
|
||||
let pos = Vec2::new(
|
||||
center.x + (radius * ((n as f32 * phi).cos())) as i32,
|
||||
center.y + (radius * ((n as f32 * phi).sin())) as i32,
|
||||
);
|
||||
positions.push(pos);
|
||||
}
|
||||
positions
|
||||
}
|
Loading…
Reference in New Issue
Block a user