mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'juliancoffee/dungeon_rebalance' into 'master'
Make cultist great again See merge request veloren/veloren!2513
This commit is contained in:
commit
099ddea165
@ -7,7 +7,7 @@ RepeaterRanged(
|
||||
half_speed_at: 1,
|
||||
projectile: Arrow(
|
||||
damage: 30.0,
|
||||
knockback: 5.0,
|
||||
knockback: 2.0,
|
||||
energy_regen: 0,
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
|
@ -2,17 +2,17 @@ ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 160,
|
||||
base_damage: 200,
|
||||
damage_increase: 0,
|
||||
base_poise_damage: 12,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 5.0,
|
||||
range: 3.5,
|
||||
angle: 60.0,
|
||||
base_buildup_duration: 0.25,
|
||||
base_swing_duration: 0.07,
|
||||
base_buildup_duration: 0.5,
|
||||
base_swing_duration: 0.2,
|
||||
hit_timing: 0.5,
|
||||
base_recover_duration: 0.25,
|
||||
base_recover_duration: 0.5,
|
||||
forward_movement: 0.5,
|
||||
damage_kind: Crushing,
|
||||
),
|
||||
|
@ -2,8 +2,8 @@ BasicBeam(
|
||||
buildup_duration: 0.40,
|
||||
recover_duration: 0.50,
|
||||
beam_duration: 1.0,
|
||||
damage: 400,
|
||||
tick_rate: 0.9,
|
||||
damage: 150,
|
||||
tick_rate: 5.0,
|
||||
range: 22.0,
|
||||
max_angle: 15.0,
|
||||
damage_effect: Some(Buff((
|
||||
@ -14,7 +14,7 @@ BasicBeam(
|
||||
))),
|
||||
energy_regen: 0,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Normal,
|
||||
ori_rate: 0.6,
|
||||
orientation_behavior: FromOri,
|
||||
ori_rate: 0.2,
|
||||
specifier: Cultist,
|
||||
)
|
||||
|
@ -3,10 +3,10 @@ ChargedMelee(
|
||||
energy_drain: 300,
|
||||
initial_damage: 10,
|
||||
scaled_damage: 160,
|
||||
initial_poise_damage: 60,
|
||||
scaled_poise_damage: 130,
|
||||
initial_knockback: 10.0,
|
||||
scaled_knockback: 50.0,
|
||||
initial_poise_damage: 20,
|
||||
scaled_poise_damage: 60,
|
||||
initial_knockback: 5.0,
|
||||
scaled_knockback: 20.0,
|
||||
range: 3.5,
|
||||
max_angle: 30.0,
|
||||
speed: 1.0,
|
||||
|
@ -14,7 +14,7 @@ BasicBeam(
|
||||
))),
|
||||
energy_regen: 0,
|
||||
energy_drain: 350,
|
||||
orientation_behavior: Normal,
|
||||
ori_rate: 0.6,
|
||||
orientation_behavior: FromOri,
|
||||
ori_rate: 0.3,
|
||||
specifier: Flamethrower,
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Belt("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(6.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(8.0),
|
||||
poise_resilience: Normal(1.0),
|
||||
energy_max: 20,
|
||||
energy_reward: 0.025,
|
||||
crit_power: 0.02,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Chest("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(30.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(48.0),
|
||||
poise_resilience: Normal(6.0),
|
||||
energy_max: 135,
|
||||
energy_reward: 0.135,
|
||||
crit_power: 0.125,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Foot("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(6.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(16.0),
|
||||
poise_resilience: Normal(2.0),
|
||||
energy_max: 45,
|
||||
energy_reward: 0.045,
|
||||
crit_power: 0.04,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Hand("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(12.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(16.0),
|
||||
poise_resilience: Normal(2.0),
|
||||
energy_max: 45,
|
||||
energy_reward: 0.045,
|
||||
crit_power: 0.04,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Pants("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(24.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(32.0),
|
||||
poise_resilience: Normal(4.0),
|
||||
energy_max: 90,
|
||||
energy_reward: 0.1,
|
||||
crit_power: 0.08,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,11 +4,11 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Shoulder("Cultist"),
|
||||
stats: (
|
||||
protection: Normal(18.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(32.0),
|
||||
poise_resilience: Normal(5.0),
|
||||
energy_max: 90,
|
||||
energy_reward: 0.1,
|
||||
crit_power: 0.08,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
@ -16,4 +16,4 @@ ItemDef(
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
)
|
||||
|
@ -4,14 +4,16 @@ ItemDef(
|
||||
kind: Armor((
|
||||
kind: Back("DungeonPurple"),
|
||||
stats: (
|
||||
protection: Normal(3.0),
|
||||
poise_resilience: Normal(0.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
protection: Normal(8.0),
|
||||
poise_resilience: Normal(1.0),
|
||||
energy_max: 20,
|
||||
energy_reward: 0.025,
|
||||
crit_power: 0.02,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
quality: Epic,
|
||||
tags: [],
|
||||
)
|
||||
tags: [
|
||||
Cultist,
|
||||
],
|
||||
)
|
||||
|
17
assets/common/items/npc_armor/biped_large/warlock.ron
Normal file
17
assets/common/items/npc_armor/biped_large/warlock.ron
Normal file
@ -0,0 +1,17 @@
|
||||
ItemDef(
|
||||
name: "Giant Warlock Chest",
|
||||
description: "Made of darkest silk.",
|
||||
kind: Armor((
|
||||
kind: Chest("GiantWarlock"),
|
||||
stats: (
|
||||
protection: Normal(250.0),
|
||||
poise_resilience: Normal(1.0),
|
||||
energy_max: 1000,
|
||||
energy_reward: 1.0,
|
||||
crit_power: 0.0,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
quality: Moderate,
|
||||
tags: [],
|
||||
)
|
17
assets/common/items/npc_armor/biped_large/warlord.ron
Normal file
17
assets/common/items/npc_armor/biped_large/warlord.ron
Normal file
@ -0,0 +1,17 @@
|
||||
ItemDef(
|
||||
name: "Giant Warlord Chest",
|
||||
description: "Made of darkest steel.",
|
||||
kind: Armor((
|
||||
kind: Chest("GiantWarlord"),
|
||||
stats: (
|
||||
protection: Normal(300.0),
|
||||
poise_resilience: Normal(1.0),
|
||||
energy_max: 0,
|
||||
energy_reward: 0.0,
|
||||
crit_power: 0.0,
|
||||
stealth: 0.0,
|
||||
),
|
||||
)),
|
||||
quality: Moderate,
|
||||
tags: [],
|
||||
)
|
@ -15,4 +15,4 @@ ItemDef(
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Husk Brute")),
|
||||
)
|
||||
)
|
||||
|
@ -4,5 +4,4 @@
|
||||
Tree("common.skillset.dungeon.tier-5.axe"),
|
||||
Tree("common.skillset.dungeon.tier-5.hammer"),
|
||||
Tree("common.skillset.dungeon.tier-5.bow"),
|
||||
Tree("common.skillset.dungeon.tier-5.staff"),
|
||||
])
|
||||
|
@ -1,21 +0,0 @@
|
||||
([
|
||||
Group(Weapon(Staff)),
|
||||
|
||||
// Fireball
|
||||
Skill((Staff(BDamage), Some(1))),
|
||||
Skill((Staff(BRegen), Some(1))),
|
||||
Skill((Staff(BRadius), Some(1))),
|
||||
|
||||
// Flamethrower
|
||||
Skill((Staff(FRange), Some(1))),
|
||||
Skill((Staff(FDrain), Some(1))),
|
||||
Skill((Staff(FDamage), Some(1))),
|
||||
Skill((Staff(FVelocity), Some(1))),
|
||||
|
||||
// Shockwave
|
||||
Skill((Staff(UnlockShockwave), None)),
|
||||
Skill((Staff(SDamage), Some(1))),
|
||||
Skill((Staff(SKnockback), Some(1))),
|
||||
Skill((Staff(SRange), Some(1))),
|
||||
Skill((Staff(SCost), Some(1))),
|
||||
])
|
@ -13,7 +13,6 @@
|
||||
|
||||
// Spin of death
|
||||
Skill((Sword(UnlockSpin), None)),
|
||||
Skill((Sword(SDamage), Some(1))),
|
||||
Skill((Sword(SSpins), Some(2))),
|
||||
Skill((Sword(SCost), Some(1))),
|
||||
Skill((Sword(SDamage), Some(2))),
|
||||
Skill((Sword(SCost), Some(2))),
|
||||
])
|
||||
|
23
assets/common/skillset/preset/max/axe.ron
Normal file
23
assets/common/skillset/preset/max/axe.ron
Normal file
@ -0,0 +1,23 @@
|
||||
([
|
||||
Group(Weapon(Axe)),
|
||||
|
||||
// DoubleStrike
|
||||
Skill((Axe(DsCombo), None)),
|
||||
Skill((Axe(DsDamage), Some(3))),
|
||||
Skill((Axe(DsRegen), Some(2))),
|
||||
Skill((Axe(DsSpeed), Some(3))),
|
||||
|
||||
// Spin
|
||||
Skill((Axe(SInfinite), None)),
|
||||
Skill((Axe(SHelicopter), None)),
|
||||
Skill((Axe(SDamage), Some(3))),
|
||||
Skill((Axe(SSpeed), Some(2))),
|
||||
Skill((Axe(SCost), Some(2))),
|
||||
|
||||
// Leap
|
||||
Skill((Axe(UnlockLeap), None)),
|
||||
Skill((Axe(LDamage), Some(2))),
|
||||
Skill((Axe(LKnockback), Some(2))),
|
||||
Skill((Axe(LCost), Some(2))),
|
||||
Skill((Axe(LDistance), Some(2))),
|
||||
])
|
25
assets/common/skillset/preset/max/bow.ron
Normal file
25
assets/common/skillset/preset/max/bow.ron
Normal file
@ -0,0 +1,25 @@
|
||||
([
|
||||
Group(Weapon(Bow)),
|
||||
|
||||
// Projectile Speed
|
||||
Skill((Bow(ProjSpeed), Some(2))),
|
||||
|
||||
// Charged
|
||||
Skill((Bow(CDamage), Some(3))),
|
||||
Skill((Bow(CKnockback), Some(2))),
|
||||
Skill((Bow(CSpeed), Some(2))),
|
||||
Skill((Bow(CRegen), Some(2))),
|
||||
Skill((Bow(CMove), Some(2))),
|
||||
|
||||
// Repeater
|
||||
Skill((Bow(RDamage), Some(3))),
|
||||
Skill((Bow(RCost), Some(2))),
|
||||
Skill((Bow(RSpeed), Some(2))),
|
||||
|
||||
// Shotgun
|
||||
Skill((Bow(UnlockShotgun), None)),
|
||||
Skill((Bow(SDamage), Some(2))),
|
||||
Skill((Bow(SCost), Some(2))),
|
||||
Skill((Bow(SArrows), Some(2))),
|
||||
Skill((Bow(SSpread), Some(2))),
|
||||
])
|
23
assets/common/skillset/preset/max/hammer.ron
Normal file
23
assets/common/skillset/preset/max/hammer.ron
Normal file
@ -0,0 +1,23 @@
|
||||
([
|
||||
Group(Weapon(Hammer)),
|
||||
|
||||
// Single Strike, as single as you are
|
||||
Skill((Hammer(SsKnockback), Some(2))),
|
||||
Skill((Hammer(SsDamage), Some(3))),
|
||||
Skill((Hammer(SsRegen), Some(2))),
|
||||
Skill((Hammer(SsSpeed), Some(3))),
|
||||
|
||||
// Charged
|
||||
Skill((Hammer(CDamage), Some(3))),
|
||||
Skill((Hammer(CKnockback), Some(3))),
|
||||
Skill((Hammer(CDrain), Some(2))),
|
||||
Skill((Hammer(CSpeed), Some(2))),
|
||||
|
||||
// Leap
|
||||
Skill((Hammer(UnlockLeap), None)),
|
||||
Skill((Hammer(LDamage), Some(2))),
|
||||
Skill((Hammer(LCost), Some(2))),
|
||||
Skill((Hammer(LDistance), Some(2))),
|
||||
Skill((Hammer(LKnockback), Some(2))),
|
||||
Skill((Hammer(LRange), Some(2))),
|
||||
])
|
21
assets/common/skillset/preset/max/staff.ron
Normal file
21
assets/common/skillset/preset/max/staff.ron
Normal file
@ -0,0 +1,21 @@
|
||||
([
|
||||
Group(Weapon(Staff)),
|
||||
|
||||
// Fireball
|
||||
Skill((Staff(BDamage), Some(3))),
|
||||
Skill((Staff(BRegen), Some(2))),
|
||||
Skill((Staff(BRadius), Some(3))),
|
||||
|
||||
// Flamethrower
|
||||
Skill((Staff(FRange), Some(2))),
|
||||
Skill((Staff(FDamage), Some(3))),
|
||||
Skill((Staff(FDrain), Some(2))),
|
||||
Skill((Staff(FVelocity), Some(2))),
|
||||
|
||||
// Shockwave
|
||||
Skill((Staff(UnlockShockwave), None)),
|
||||
Skill((Staff(SDamage), Some(2))),
|
||||
Skill((Staff(SKnockback), Some(2))),
|
||||
Skill((Staff(SRange), Some(2))),
|
||||
Skill((Staff(SCost), Some(2))),
|
||||
])
|
26
assets/common/skillset/preset/max/sword.ron
Normal file
26
assets/common/skillset/preset/max/sword.ron
Normal file
@ -0,0 +1,26 @@
|
||||
([
|
||||
Group(Weapon(Sword)),
|
||||
|
||||
Skill((Sword(InterruptingAttacks), None)),
|
||||
|
||||
// TripleStrike
|
||||
Skill((Sword(TsCombo), None)),
|
||||
Skill((Sword(TsDamage), Some(3))),
|
||||
Skill((Sword(TsRegen), Some(2))),
|
||||
Skill((Sword(TsSpeed), Some(3))),
|
||||
|
||||
// Dash
|
||||
Skill((Sword(DCost), Some(2))),
|
||||
Skill((Sword(DDrain), Some(2))),
|
||||
Skill((Sword(DDamage), Some(2))),
|
||||
Skill((Sword(DScaling), Some(3))),
|
||||
Skill((Sword(DSpeed), None)),
|
||||
Skill((Sword(DInfinite), None)),
|
||||
|
||||
// Spin of death
|
||||
Skill((Sword(UnlockSpin), None)),
|
||||
Skill((Sword(SDamage), Some(2))),
|
||||
Skill((Sword(SSpeed), Some(2))),
|
||||
Skill((Sword(SSpins), Some(2))),
|
||||
Skill((Sword(SCost), Some(2))),
|
||||
])
|
@ -314,6 +314,15 @@
|
||||
("common.items.armor.ferocious.back",1),
|
||||
("common.items.weapons.sword.bloodsteel-1",1),
|
||||
],
|
||||
"cultist": [
|
||||
("common.items.armor.cultist.chest",1),
|
||||
("common.items.armor.cultist.pants",1),
|
||||
("common.items.armor.cultist.hand",1),
|
||||
("common.items.armor.cultist.foot",1),
|
||||
("common.items.armor.cultist.shoulder",1),
|
||||
("common.items.armor.cultist.belt",1),
|
||||
("common.items.armor.misc.back.dungeon_purple",1),
|
||||
],
|
||||
"admin_cosmetics": [
|
||||
("common.items.debug.cultist_belt",1),
|
||||
("common.items.debug.cultist_boots",1),
|
||||
|
@ -625,6 +625,7 @@ impl Body {
|
||||
biped_large::Species::Dullahan => 120,
|
||||
biped_large::Species::Huskbrute => 100,
|
||||
// Boss enemies have their health set, not adjusted by level.
|
||||
biped_large::Species::Huskbrute => 0,
|
||||
biped_large::Species::Mindflayer => 0,
|
||||
biped_large::Species::Minotaur => 0,
|
||||
biped_large::Species::Tidalwarrior => 0,
|
||||
|
@ -161,14 +161,9 @@ fn default_main_tool(body: &Body) -> Item {
|
||||
_ => None,
|
||||
},
|
||||
Body::QuadrupedMedium(quadruped_medium) => match quadruped_medium.species {
|
||||
quadruped_medium::Species::Wolf
|
||||
| quadruped_medium::Species::Grolgar
|
||||
| quadruped_medium::Species::Lion
|
||||
| quadruped_medium::Species::Bonerattler
|
||||
| quadruped_medium::Species::Darkhound
|
||||
| quadruped_medium::Species::Snowleopard => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.quadmedquick",
|
||||
)),
|
||||
quadruped_medium::Species::Wolf | quadruped_medium::Species::Grolgar => Some(
|
||||
Item::new_from_asset_expect("common.items.npc_weapons.unique.quadmedquick"),
|
||||
),
|
||||
quadruped_medium::Species::Donkey
|
||||
| quadruped_medium::Species::Horse
|
||||
| quadruped_medium::Species::Zebra
|
||||
@ -180,7 +175,11 @@ fn default_main_tool(body: &Body) -> Item {
|
||||
| quadruped_medium::Species::Alpaca => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.quadmedhoof",
|
||||
)),
|
||||
quadruped_medium::Species::Saber => Some(Item::new_from_asset_expect(
|
||||
quadruped_medium::Species::Saber
|
||||
| quadruped_medium::Species::Bonerattler
|
||||
| quadruped_medium::Species::Darkhound
|
||||
| quadruped_medium::Species::Lion
|
||||
| quadruped_medium::Species::Snowleopard => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.quadmedjump",
|
||||
)),
|
||||
quadruped_medium::Species::Tuskram
|
||||
@ -398,88 +397,73 @@ impl LoadoutBuilder {
|
||||
|
||||
#[must_use]
|
||||
/// Set default equipement based on `body`
|
||||
pub fn with_default_equipment(mut self, body: &Body) -> Self {
|
||||
self = match body {
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species: biped_large::Species::Mindflayer,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.mindflayer",
|
||||
))),
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species: biped_large::Species::Minotaur,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.minotaur",
|
||||
))),
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species: biped_large::Species::Tidalwarrior,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.tidal_warrior",
|
||||
))),
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species: biped_large::Species::Yeti,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.yeti",
|
||||
))),
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species: biped_large::Species::Harvester,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.harvester",
|
||||
))),
|
||||
Body::BipedLarge(biped_large::Body {
|
||||
species:
|
||||
biped_large::Species::Ogre
|
||||
| biped_large::Species::Cyclops
|
||||
| biped_large::Species::Blueoni
|
||||
| biped_large::Species::Redoni
|
||||
| biped_large::Species::Cavetroll
|
||||
| biped_large::Species::Wendigo,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.biped_large.generic",
|
||||
))),
|
||||
Body::Golem(golem::Body {
|
||||
species: golem::Species::ClayGolem,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.golem.claygolem",
|
||||
))),
|
||||
Body::QuadrupedLow(quadruped_low::Body {
|
||||
species:
|
||||
quadruped_low::Species::Basilisk
|
||||
| quadruped_low::Species::Asp
|
||||
| quadruped_low::Species::Lavadrake
|
||||
| quadruped_low::Species::Maneater
|
||||
| quadruped_low::Species::Rocksnapper
|
||||
| quadruped_low::Species::Sandshark,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.quadruped_low.generic",
|
||||
))),
|
||||
Body::QuadrupedLow(quadruped_low::Body {
|
||||
species: quadruped_low::Species::Tortoise,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.quadruped_low.shell",
|
||||
))),
|
||||
Body::Theropod(theropod::Body {
|
||||
species:
|
||||
theropod::Species::Archaeos
|
||||
| theropod::Species::Yale
|
||||
| theropod::Species::Ntouka
|
||||
| theropod::Species::Odonto,
|
||||
..
|
||||
}) => self.chest(Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_armor.theropod.rugged",
|
||||
))),
|
||||
_ => self,
|
||||
pub fn with_default_equipment(self, body: &Body) -> Self {
|
||||
let chest = match body {
|
||||
Body::BipedLarge(body) => match body.species {
|
||||
biped_large::Species::Mindflayer => {
|
||||
Some("common.items.npc_armor.biped_large.mindflayer")
|
||||
},
|
||||
biped_large::Species::Minotaur => {
|
||||
Some("common.items.npc_armor.biped_large.minotaur")
|
||||
},
|
||||
biped_large::Species::Tidalwarrior => {
|
||||
Some("common.items.npc_armor.biped_large.tidal_warrior")
|
||||
},
|
||||
biped_large::Species::Yeti => Some("common.items.npc_armor.biped_large.yeti"),
|
||||
biped_large::Species::Harvester => {
|
||||
Some("common.items.npc_armor.biped_large.harvester")
|
||||
},
|
||||
biped_large::Species::Ogre
|
||||
| biped_large::Species::Cyclops
|
||||
| biped_large::Species::Blueoni
|
||||
| biped_large::Species::Redoni
|
||||
| biped_large::Species::Cavetroll
|
||||
| biped_large::Species::Wendigo => {
|
||||
Some("common.items.npc_armor.biped_large.generic")
|
||||
},
|
||||
biped_large::Species::Cultistwarlord => {
|
||||
Some("common.items.npc_armor.biped_large.warlord")
|
||||
},
|
||||
biped_large::Species::Cultistwarlock => {
|
||||
Some("common.items.npc_armor.biped_large.warlock")
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Body::Golem(body) => match body.species {
|
||||
golem::Species::ClayGolem => Some("common.items.npc_armor.golem.claygolem"),
|
||||
_ => None,
|
||||
},
|
||||
Body::QuadrupedLow(body) => match body.species {
|
||||
quadruped_low::Species::Basilisk
|
||||
| quadruped_low::Species::Asp
|
||||
| quadruped_low::Species::Lavadrake
|
||||
| quadruped_low::Species::Maneater
|
||||
| quadruped_low::Species::Rocksnapper
|
||||
| quadruped_low::Species::Sandshark => {
|
||||
Some("common.items.npc_armor.quadruped_low.generic")
|
||||
},
|
||||
quadruped_low::Species::Tortoise => {
|
||||
Some("common.items.npc_armor.quadruped_low.shell")
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Body::Theropod(body) => match body.species {
|
||||
theropod::Species::Archaeos
|
||||
| theropod::Species::Yale
|
||||
| theropod::Species::Ntouka
|
||||
| theropod::Species::Odonto => Some("common.items.npc_armor.theropod.rugged"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self
|
||||
// closures can't be used here, because it moves value
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
if let Some(chest) = chest {
|
||||
self.chest(Some(Item::new_from_asset_expect(chest)))
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -184,18 +184,195 @@ impl Tile {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum RoomKind {
|
||||
Peaceful,
|
||||
Fight,
|
||||
Boss,
|
||||
Miniboss,
|
||||
}
|
||||
|
||||
pub struct Room {
|
||||
seed: u32,
|
||||
loot_density: f32,
|
||||
enemy_density: Option<f32>,
|
||||
miniboss: bool,
|
||||
boss: bool,
|
||||
kind: RoomKind,
|
||||
area: Rect<i32, i32>,
|
||||
height: i32,
|
||||
pillars: Option<i32>, // Pillars with the given separation
|
||||
difficulty: u32,
|
||||
}
|
||||
|
||||
impl Room {
|
||||
fn fill_fight_cell(
|
||||
&self,
|
||||
supplement: &mut ChunkSupplement,
|
||||
dynamic_rng: &mut impl Rng,
|
||||
tile_wcenter: Vec3<i32>,
|
||||
wpos2d: Vec2<i32>,
|
||||
tile_pos: Vec2<i32>,
|
||||
) {
|
||||
let enemy_spawn_tile = self.area.center();
|
||||
// Don't spawn enemies in a pillar
|
||||
let enemy_tile_is_pillar = self.pillars.map_or(false, |pillar_space| {
|
||||
enemy_spawn_tile
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
});
|
||||
let enemy_spawn_tile = enemy_spawn_tile + if enemy_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
// Toss mobs in the center of the room
|
||||
if tile_pos == enemy_spawn_tile && wpos2d == tile_wcenter.xy() {
|
||||
let entities = match self.difficulty {
|
||||
0 => enemy_0(dynamic_rng, tile_wcenter),
|
||||
1 => enemy_1(dynamic_rng, tile_wcenter),
|
||||
2 => enemy_2(dynamic_rng, tile_wcenter),
|
||||
3 => enemy_3(dynamic_rng, tile_wcenter),
|
||||
4 => enemy_4(dynamic_rng, tile_wcenter),
|
||||
5 => enemy_5(dynamic_rng, tile_wcenter),
|
||||
_ => enemy_fallback(dynamic_rng, tile_wcenter),
|
||||
};
|
||||
|
||||
for entity in entities {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(self.difficulty as f32).powf(1.25) + 3.0
|
||||
..(self.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round() as u16,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Turrets
|
||||
// Turret has 1/5000 chance to spawn per voxel in fight room
|
||||
if dynamic_rng.gen_range(0..5000) == 0 {
|
||||
let pos = tile_wcenter.map(|e| e as f32)
|
||||
+ Vec3::<u32>::iota()
|
||||
.map(|e| {
|
||||
(RandomField::new(self.seed.wrapping_add(10 + e))
|
||||
.get(Vec3::from(tile_pos))
|
||||
% 32) as i32
|
||||
- 16
|
||||
})
|
||||
.map(|e| e as f32 / 16.0);
|
||||
let turret =
|
||||
EntityInfo::at(pos.map(|e| e as f32)).with_alignment(comp::Alignment::Enemy);
|
||||
match self.difficulty {
|
||||
3 => {
|
||||
let turret = turret
|
||||
.with_body(comp::Body::Object(comp::object::Body::Crossbow))
|
||||
.with_asset_expect("common.entity.dungeon.tier-3.sentry");
|
||||
supplement.add_entity(turret);
|
||||
},
|
||||
5 => {
|
||||
let turret = turret
|
||||
.with_body(comp::Body::Object(comp::object::Body::Crossbow))
|
||||
.with_asset_expect("common.entity.dungeon.tier-5.turret");
|
||||
supplement.add_entity(turret);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_miniboss_cell(
|
||||
&self,
|
||||
supplement: &mut ChunkSupplement,
|
||||
dynamic_rng: &mut impl Rng,
|
||||
tile_wcenter: Vec3<i32>,
|
||||
wpos2d: Vec2<i32>,
|
||||
tile_pos: Vec2<i32>,
|
||||
) {
|
||||
let miniboss_spawn_tile = self.area.center();
|
||||
// Don't spawn the miniboss in a pillar
|
||||
let miniboss_tile_is_pillar = self.pillars.map_or(false, |pillar_space| {
|
||||
miniboss_spawn_tile
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
});
|
||||
let miniboss_spawn_tile = miniboss_spawn_tile + if miniboss_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let entities = match self.difficulty {
|
||||
0 => mini_boss_0(tile_wcenter),
|
||||
1 => mini_boss_1(tile_wcenter),
|
||||
2 => mini_boss_2(tile_wcenter),
|
||||
3 => mini_boss_3(tile_wcenter),
|
||||
4 => mini_boss_4(tile_wcenter),
|
||||
5 => mini_boss_5(dynamic_rng, tile_wcenter),
|
||||
_ => mini_boss_fallback(tile_wcenter),
|
||||
};
|
||||
|
||||
for entity in entities {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(self.difficulty as f32).powf(1.25) + 3.0
|
||||
..(self.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round() as u16
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_boss_cell(
|
||||
&self,
|
||||
supplement: &mut ChunkSupplement,
|
||||
dynamic_rng: &mut impl Rng,
|
||||
tile_wcenter: Vec3<i32>,
|
||||
wpos2d: Vec2<i32>,
|
||||
tile_pos: Vec2<i32>,
|
||||
) {
|
||||
let boss_spawn_tile = self.area.center();
|
||||
// Don't spawn the boss in a pillar
|
||||
let boss_tile_is_pillar = self.pillars.map_or(false, |pillar_space| {
|
||||
boss_spawn_tile
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
});
|
||||
let boss_spawn_tile = boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
if tile_pos == boss_spawn_tile && wpos2d == tile_wcenter.xy() {
|
||||
let entities = match self.difficulty {
|
||||
0 => boss_0(tile_wcenter),
|
||||
1 => boss_1(tile_wcenter),
|
||||
2 => boss_2(tile_wcenter),
|
||||
3 => boss_3(tile_wcenter),
|
||||
4 => boss_4(tile_wcenter),
|
||||
5 => boss_5(tile_wcenter),
|
||||
_ => boss_fallback(tile_wcenter),
|
||||
};
|
||||
|
||||
for entity in entities {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(self.difficulty as f32).powf(1.25) + 3.0
|
||||
..(self.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round() as u16
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Floor {
|
||||
tile_offset: Vec2<i32>,
|
||||
tiles: Grid<Tile>,
|
||||
@ -252,9 +429,7 @@ impl Floor {
|
||||
let upstair_room = this.create_room(Room {
|
||||
seed: ctx.rng.gen(),
|
||||
loot_density: 0.0,
|
||||
enemy_density: None,
|
||||
miniboss: false,
|
||||
boss: false,
|
||||
kind: RoomKind::Peaceful,
|
||||
area: Rect::from((stair_tile - tile_offset - 1, Extent2::broadcast(3))),
|
||||
height: STAIR_ROOM_HEIGHT,
|
||||
pillars: None,
|
||||
@ -265,9 +440,7 @@ impl Floor {
|
||||
this.create_room(Room {
|
||||
seed: ctx.rng.gen(),
|
||||
loot_density: 0.0,
|
||||
enemy_density: Some((0.0002 * difficulty as f32).min(0.001)), // Minions!
|
||||
miniboss: false,
|
||||
boss: true,
|
||||
kind: RoomKind::Boss,
|
||||
area: Rect::from((
|
||||
new_stair_tile - tile_offset - MAX_WIDTH as i32 - 1,
|
||||
Extent2::broadcast(width as i32 * 2 + 1),
|
||||
@ -281,9 +454,7 @@ impl Floor {
|
||||
let downstair_room = this.create_room(Room {
|
||||
seed: ctx.rng.gen(),
|
||||
loot_density: 0.0,
|
||||
enemy_density: None,
|
||||
miniboss: false,
|
||||
boss: false,
|
||||
kind: RoomKind::Peaceful,
|
||||
area: Rect::from((new_stair_tile - tile_offset - 1, Extent2::broadcast(3))),
|
||||
height: STAIR_ROOM_HEIGHT,
|
||||
pillars: None,
|
||||
@ -358,23 +529,21 @@ impl Floor {
|
||||
let mut dynamic_rng = rand::thread_rng();
|
||||
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
// Miniboss room
|
||||
0 => self.create_room(Room {
|
||||
seed: ctx.rng.gen(),
|
||||
loot_density: 0.000025 + level as f32 * 0.00015,
|
||||
enemy_density: None,
|
||||
miniboss: true,
|
||||
boss: false,
|
||||
kind: RoomKind::Miniboss,
|
||||
area,
|
||||
height: ctx.rng.gen_range(15..20),
|
||||
pillars: Some(ctx.rng.gen_range(2..=4)),
|
||||
difficulty: self.difficulty,
|
||||
}),
|
||||
// Fight room with enemies in it
|
||||
_ => self.create_room(Room {
|
||||
seed: ctx.rng.gen(),
|
||||
loot_density: 0.000025 + level as f32 * 0.00015,
|
||||
enemy_density: Some(0.001 + level as f32 * 0.00006),
|
||||
miniboss: false,
|
||||
boss: false,
|
||||
kind: RoomKind::Fight,
|
||||
area,
|
||||
height: ctx.rng.gen_range(10..15),
|
||||
pillars: if ctx.rng.gen_range(0..4) == 0 {
|
||||
@ -433,7 +602,6 @@ impl Floor {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::match_single_binding)] // TODO: Pending review in #587
|
||||
fn apply_supplement(
|
||||
&self,
|
||||
// NOTE: Used only for dynamic elements like chests and entities!
|
||||
@ -477,141 +645,29 @@ impl Floor {
|
||||
.map(|e| e.div_euclid(TILE_SIZE) * TILE_SIZE + TILE_SIZE / 2),
|
||||
);
|
||||
|
||||
let tile_is_pillar = room
|
||||
.pillars
|
||||
.map(|pillar_space| {
|
||||
tile_pos
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
})
|
||||
.unwrap_or(false);
|
||||
|
||||
if room
|
||||
.enemy_density
|
||||
.map(|density| dynamic_rng.gen_range(0..density.recip() as usize) == 0)
|
||||
.unwrap_or(false)
|
||||
&& !tile_is_pillar
|
||||
&& !room.boss
|
||||
{
|
||||
// Randomly displace them a little
|
||||
let raw_entity = EntityInfo::at(
|
||||
tile_wcenter.map(|e| e as f32)
|
||||
+ Vec3::<u32>::iota()
|
||||
.map(|e| {
|
||||
(RandomField::new(room.seed.wrapping_add(10 + e))
|
||||
.get(Vec3::from(tile_pos))
|
||||
% 32) as i32
|
||||
- 16
|
||||
})
|
||||
.map(|e| e as f32 / 16.0),
|
||||
);
|
||||
|
||||
let entity = match room.difficulty {
|
||||
0 => enemy_0(dynamic_rng, raw_entity),
|
||||
1 => enemy_1(dynamic_rng, raw_entity),
|
||||
2 => enemy_2(dynamic_rng, raw_entity),
|
||||
3 => enemy_3(dynamic_rng, raw_entity),
|
||||
4 => enemy_4(dynamic_rng, raw_entity),
|
||||
5 => enemy_5(dynamic_rng, raw_entity),
|
||||
_ => enemy_fallback(raw_entity),
|
||||
};
|
||||
supplement.add_entity(
|
||||
entity.with_alignment(comp::Alignment::Enemy).with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0
|
||||
..(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round() as u16,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if room.boss {
|
||||
let boss_spawn_tile = room.area.center();
|
||||
// Don't spawn the boss in a pillar
|
||||
let boss_tile_is_pillar = room
|
||||
.pillars
|
||||
.map(|pillar_space| {
|
||||
boss_spawn_tile
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
})
|
||||
.unwrap_or(false);
|
||||
let boss_spawn_tile =
|
||||
boss_spawn_tile + if boss_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
if tile_pos == boss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let entities = match room.difficulty {
|
||||
0 => boss_0(tile_wcenter),
|
||||
1 => boss_1(tile_wcenter),
|
||||
2 => boss_2(tile_wcenter),
|
||||
3 => boss_3(tile_wcenter),
|
||||
4 => boss_4(tile_wcenter),
|
||||
5 => boss_5(tile_wcenter),
|
||||
_ => boss_fallback(tile_wcenter),
|
||||
};
|
||||
|
||||
for entity in entities {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0
|
||||
..(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round()
|
||||
as u16
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if room.miniboss {
|
||||
let miniboss_spawn_tile = room.area.center();
|
||||
// Don't spawn the miniboss in a pillar
|
||||
let miniboss_tile_is_pillar = room
|
||||
.pillars
|
||||
.map(|pillar_space| {
|
||||
miniboss_spawn_tile
|
||||
.map(|e| e.rem_euclid(pillar_space) == 0)
|
||||
.reduce_and()
|
||||
})
|
||||
.unwrap_or(false);
|
||||
let miniboss_spawn_tile =
|
||||
miniboss_spawn_tile + if miniboss_tile_is_pillar { 1 } else { 0 };
|
||||
|
||||
if tile_pos == miniboss_spawn_tile && tile_wcenter.xy() == wpos2d {
|
||||
let entities = match room.difficulty {
|
||||
0 => mini_boss_0(tile_wcenter),
|
||||
1 => mini_boss_1(tile_wcenter),
|
||||
2 => mini_boss_2(tile_wcenter),
|
||||
3 => mini_boss_3(tile_wcenter),
|
||||
4 => mini_boss_4(tile_wcenter),
|
||||
5 => mini_boss_5(dynamic_rng, tile_wcenter),
|
||||
_ => mini_boss_fallback(tile_wcenter),
|
||||
};
|
||||
|
||||
for entity in entities {
|
||||
supplement.add_entity(
|
||||
entity
|
||||
.with_level(
|
||||
dynamic_rng
|
||||
.gen_range(
|
||||
(room.difficulty as f32).powf(1.25) + 3.0
|
||||
..(room.difficulty as f32).powf(1.5) + 4.0,
|
||||
)
|
||||
.round()
|
||||
as u16
|
||||
* 5,
|
||||
)
|
||||
.with_alignment(comp::Alignment::Enemy),
|
||||
);
|
||||
}
|
||||
}
|
||||
match room.kind {
|
||||
RoomKind::Fight => room.fill_fight_cell(
|
||||
supplement,
|
||||
dynamic_rng,
|
||||
tile_wcenter,
|
||||
wpos2d,
|
||||
tile_pos,
|
||||
),
|
||||
RoomKind::Miniboss => room.fill_miniboss_cell(
|
||||
supplement,
|
||||
dynamic_rng,
|
||||
tile_wcenter,
|
||||
wpos2d,
|
||||
tile_pos,
|
||||
),
|
||||
RoomKind::Boss => room.fill_boss_cell(
|
||||
supplement,
|
||||
dynamic_rng,
|
||||
tile_wcenter,
|
||||
wpos2d,
|
||||
tile_pos,
|
||||
),
|
||||
RoomKind::Peaceful => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -631,61 +687,105 @@ impl Floor {
|
||||
}
|
||||
}
|
||||
|
||||
fn enemy_0(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.tier-0.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-0.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-0.spear"),
|
||||
}
|
||||
fn enemy_0(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, || {
|
||||
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.tier-0.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-0.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-0.spear"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_1(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.tier-1.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-1.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-1.spear"),
|
||||
}
|
||||
fn enemy_1(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, || {
|
||||
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.tier-1.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-1.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-1.spear"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_2(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.tier-2.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-2.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-2.spear"),
|
||||
}
|
||||
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, || {
|
||||
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.tier-2.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-2.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-2.spear"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_3(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => entity
|
||||
.with_body(comp::Body::Object(comp::object::Body::HaniwaSentry))
|
||||
.with_asset_expect("common.entity.dungeon.tier-3.sentry"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-3.bow"),
|
||||
2 => entity.with_asset_expect("common.entity.dungeon.tier-3.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-3.spear"),
|
||||
}
|
||||
}
|
||||
fn enemy_4(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..5) {
|
||||
0 => entity.with_asset_expect("common.entity.dungeon.tier-4.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-4.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-4.spear"),
|
||||
}
|
||||
fn enemy_3(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, || {
|
||||
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.tier-3.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-3.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-3.spear"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_5(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
|
||||
match dynamic_rng.gen_range(0..6) {
|
||||
0 => entity
|
||||
.with_body(comp::Body::Object(comp::object::Body::Crossbow))
|
||||
.with_asset_expect("common.entity.dungeon.tier-5.turret"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-5.warlock"),
|
||||
2 => entity.with_asset_expect("common.entity.dungeon.tier-5.warlord"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-5.cultist"),
|
||||
}
|
||||
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();
|
||||
entities.resize_with(number, || {
|
||||
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.tier-4.bow"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-4.staff"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-4.spear"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_fallback(entity: EntityInfo) -> EntityInfo {
|
||||
entity.with_asset_expect("common.entity.dungeon.fallback.enemy")
|
||||
fn enemy_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let number = dynamic_rng.gen_range(1..=3);
|
||||
let mut entities = Vec::new();
|
||||
entities.resize_with(number, || {
|
||||
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.tier-5.warlock"),
|
||||
1 => entity.with_asset_expect("common.entity.dungeon.tier-5.warlord"),
|
||||
_ => entity.with_asset_expect("common.entity.dungeon.tier-5.cultist"),
|
||||
}
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn enemy_fallback(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, || {
|
||||
let entity = EntityInfo::at(tile_wcenter.map(|e| e as f32));
|
||||
entity.with_asset_expect("common.entity.dungeon.fallback.enemy")
|
||||
});
|
||||
|
||||
entities
|
||||
}
|
||||
|
||||
fn boss_0(tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
@ -782,7 +882,7 @@ fn mini_boss_4(tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
|
||||
fn mini_boss_5(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
let mut entities = Vec::new();
|
||||
match dynamic_rng.gen_range(0..3) {
|
||||
match dynamic_rng.gen_range(0..=2) {
|
||||
0 => {
|
||||
entities.push(
|
||||
EntityInfo::at(tile_wcenter.map(|e| e as f32))
|
||||
@ -816,51 +916,6 @@ fn mini_boss_fallback(tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_creating_bosses() {
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
boss_0(tile_wcenter);
|
||||
boss_1(tile_wcenter);
|
||||
boss_2(tile_wcenter);
|
||||
boss_3(tile_wcenter);
|
||||
boss_4(tile_wcenter);
|
||||
boss_5(tile_wcenter);
|
||||
boss_fallback(tile_wcenter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Uses random, test may be not great
|
||||
fn test_creating_enemies() {
|
||||
let mut dynamic_rng = rand::thread_rng();
|
||||
let raw_entity = EntityInfo::at(Vec3::new(0.0, 0.0, 0.0));
|
||||
enemy_0(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_1(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_2(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_3(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_4(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_5(&mut dynamic_rng, raw_entity.clone());
|
||||
enemy_fallback(raw_entity);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Uses random, test may be not great
|
||||
fn test_creating_minibosses() {
|
||||
let mut dynamic_rng = rand::thread_rng();
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
mini_boss_0(tile_wcenter);
|
||||
mini_boss_1(tile_wcenter);
|
||||
mini_boss_2(tile_wcenter);
|
||||
mini_boss_3(tile_wcenter);
|
||||
mini_boss_4(tile_wcenter);
|
||||
mini_boss_5(&mut dynamic_rng, tile_wcenter);
|
||||
mini_boss_fallback(tile_wcenter);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tilegrid_nearest_wall(tiles: &Grid<Tile>, rpos: Vec2<i32>) -> Option<Vec2<i32>> {
|
||||
let tile_pos = rpos.map(|e| e.div_euclid(TILE_SIZE));
|
||||
|
||||
@ -1222,7 +1277,7 @@ impl Floor {
|
||||
prim(Primitive::Scale(pillar, Vec2::broadcast(scale).with_z(1.0)));
|
||||
lights = prim(Primitive::And(lighting_plane, lights));
|
||||
// Only add the base (and shift the lights up) for boss-room pillars
|
||||
if room.boss {
|
||||
if room.kind == RoomKind::Boss {
|
||||
lights = prim(Primitive::Translate(lights, 3 * Vec3::unit_z()));
|
||||
pillar = prim(Primitive::Or(pillar, base));
|
||||
}
|
||||
@ -1231,7 +1286,7 @@ impl Floor {
|
||||
}
|
||||
|
||||
// Keep track of the boss room to be able to add decorations later
|
||||
if room.boss {
|
||||
if room.kind == RoomKind::Boss {
|
||||
boss_room_center =
|
||||
Some(floor_corner + TILE_SIZE * room.area.center() + TILE_SIZE / 2);
|
||||
}
|
||||
@ -1334,3 +1389,48 @@ impl SiteStructure for Dungeon {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_creating_bosses() {
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
boss_0(tile_wcenter);
|
||||
boss_1(tile_wcenter);
|
||||
boss_2(tile_wcenter);
|
||||
boss_3(tile_wcenter);
|
||||
boss_4(tile_wcenter);
|
||||
boss_5(tile_wcenter);
|
||||
boss_fallback(tile_wcenter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Uses random, test may be not great
|
||||
fn test_creating_enemies() {
|
||||
let mut dynamic_rng = rand::thread_rng();
|
||||
let random_position = Vec3::new(0, 0, 0);
|
||||
enemy_0(&mut dynamic_rng, random_position);
|
||||
enemy_1(&mut dynamic_rng, random_position);
|
||||
enemy_2(&mut dynamic_rng, random_position);
|
||||
enemy_3(&mut dynamic_rng, random_position);
|
||||
enemy_4(&mut dynamic_rng, random_position);
|
||||
enemy_5(&mut dynamic_rng, random_position);
|
||||
enemy_fallback(&mut dynamic_rng, random_position);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Uses random, test may be not great
|
||||
fn test_creating_minibosses() {
|
||||
let mut dynamic_rng = rand::thread_rng();
|
||||
let tile_wcenter = Vec3::new(0, 0, 0);
|
||||
mini_boss_0(tile_wcenter);
|
||||
mini_boss_1(tile_wcenter);
|
||||
mini_boss_2(tile_wcenter);
|
||||
mini_boss_3(tile_wcenter);
|
||||
mini_boss_4(tile_wcenter);
|
||||
mini_boss_5(&mut dynamic_rng, tile_wcenter);
|
||||
mini_boss_fallback(tile_wcenter);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user