feat: difficulty scaling by depth + new items (bow, shield, mana potion)
Difficulty scaling: - Spawn rates increase with depth (goblins every 30-10 ticks, slimes every 45-15) - Enemy count caps increase with depth (goblins 3-8, slimes 2-5) - Enemy health scales with depth (+5 hp/goblin, +3 hp/slime per depth) - Goblin strength stat scales with depth New items: - Bow: ranged weapon, +4 damage bonus - Shield: armor, +3 armor bonus - Mana Potion: consumable, heals 20 hp - Items spawn in world gen: sword, bow, shield, health potion, mana potion, leather armor All 171 tests pass.
This commit is contained in:
+27
-4
@@ -2,11 +2,14 @@
|
||||
pub enum ItemType {
|
||||
Dagger,
|
||||
Sword,
|
||||
Bow,
|
||||
LeatherArmor,
|
||||
PlateArmor,
|
||||
HealthPotion,
|
||||
ManaPotion,
|
||||
Food,
|
||||
Scroll,
|
||||
Shield,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -25,9 +28,12 @@ impl Item {
|
||||
match self.typ {
|
||||
ItemType::Dagger => "Dagger",
|
||||
ItemType::Sword => "Sword",
|
||||
ItemType::Bow => "Bow",
|
||||
ItemType::LeatherArmor => "Leather Armor",
|
||||
ItemType::PlateArmor => "Plate Armor",
|
||||
ItemType::Shield => "Shield",
|
||||
ItemType::HealthPotion => "Health Potion",
|
||||
ItemType::ManaPotion => "Mana Potion",
|
||||
ItemType::Food => "Food",
|
||||
ItemType::Scroll => "Scroll",
|
||||
}
|
||||
@@ -37,9 +43,12 @@ impl Item {
|
||||
match self.typ {
|
||||
ItemType::Dagger => '/',
|
||||
ItemType::Sword => '|',
|
||||
ItemType::Bow => ')',
|
||||
ItemType::LeatherArmor => '[',
|
||||
ItemType::PlateArmor => '{',
|
||||
ItemType::Shield => 'O',
|
||||
ItemType::HealthPotion => '!',
|
||||
ItemType::ManaPotion => '!',
|
||||
ItemType::Food => '%',
|
||||
ItemType::Scroll => '?',
|
||||
}
|
||||
@@ -49,9 +58,12 @@ impl Item {
|
||||
match self.typ {
|
||||
ItemType::Dagger => [200, 200, 200],
|
||||
ItemType::Sword => [240, 240, 240],
|
||||
ItemType::Bow => [180, 140, 80],
|
||||
ItemType::LeatherArmor => [140, 90, 50],
|
||||
ItemType::PlateArmor => [180, 180, 190],
|
||||
ItemType::Shield => [160, 140, 60],
|
||||
ItemType::HealthPotion => [255, 40, 40],
|
||||
ItemType::ManaPotion => [60, 60, 255],
|
||||
ItemType::Food => [80, 200, 60],
|
||||
ItemType::Scroll => [255, 220, 120],
|
||||
}
|
||||
@@ -60,22 +72,30 @@ impl Item {
|
||||
pub fn is_equipment(&self) -> bool {
|
||||
matches!(
|
||||
self.typ,
|
||||
ItemType::Dagger | ItemType::Sword | ItemType::LeatherArmor | ItemType::PlateArmor
|
||||
ItemType::Dagger
|
||||
| ItemType::Sword
|
||||
| ItemType::Bow
|
||||
| ItemType::LeatherArmor
|
||||
| ItemType::PlateArmor
|
||||
| ItemType::Shield
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_weapon(&self) -> bool {
|
||||
matches!(self.typ, ItemType::Dagger | ItemType::Sword)
|
||||
matches!(self.typ, ItemType::Dagger | ItemType::Sword | ItemType::Bow)
|
||||
}
|
||||
|
||||
pub fn is_armor(&self) -> bool {
|
||||
matches!(self.typ, ItemType::LeatherArmor | ItemType::PlateArmor)
|
||||
matches!(
|
||||
self.typ,
|
||||
ItemType::LeatherArmor | ItemType::PlateArmor | ItemType::Shield
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_consumable(&self) -> bool {
|
||||
matches!(
|
||||
self.typ,
|
||||
ItemType::HealthPotion | ItemType::Food | ItemType::Scroll
|
||||
ItemType::HealthPotion | ItemType::ManaPotion | ItemType::Food | ItemType::Scroll
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,6 +103,7 @@ impl Item {
|
||||
match self.typ {
|
||||
ItemType::Dagger => 3.0,
|
||||
ItemType::Sword => 6.0,
|
||||
ItemType::Bow => 4.0,
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
@@ -91,6 +112,7 @@ impl Item {
|
||||
match self.typ {
|
||||
ItemType::LeatherArmor => 2.0,
|
||||
ItemType::PlateArmor => 5.0,
|
||||
ItemType::Shield => 3.0,
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
@@ -98,6 +120,7 @@ impl Item {
|
||||
pub fn heal_amount(&self) -> f32 {
|
||||
match self.typ {
|
||||
ItemType::HealthPotion => 40.0,
|
||||
ItemType::ManaPotion => 20.0,
|
||||
ItemType::Food => 15.0,
|
||||
_ => 0.0,
|
||||
}
|
||||
|
||||
+17
-4
@@ -245,6 +245,12 @@ impl Game {
|
||||
.spawn(ItemType::HealthPotion, px as i32 + 6, py as i32 + 1);
|
||||
self.items
|
||||
.spawn(ItemType::LeatherArmor, px as i32 - 3, py as i32 - 8);
|
||||
self.items
|
||||
.spawn(ItemType::Bow, px as i32 + 10, py as i32 + 1);
|
||||
self.items
|
||||
.spawn(ItemType::Shield, px as i32 - 10, py as i32 + 1);
|
||||
self.items
|
||||
.spawn(ItemType::ManaPotion, px as i32 + 3, py as i32 - 6);
|
||||
}
|
||||
|
||||
pub fn center_camera_on(&mut self, px: f32, py: f32) {
|
||||
@@ -516,10 +522,10 @@ impl Game {
|
||||
self.update_score();
|
||||
self.update_item_pickup();
|
||||
|
||||
if self.tick % 30 == 0 {
|
||||
if self.tick % (30u64 - (self.depth as u64 * 3).min(20)) == 0 {
|
||||
self.try_spawn_goblin();
|
||||
}
|
||||
if self.tick % 45 == 0 {
|
||||
if self.tick % (45u64 - (self.depth as u64 * 4).min(30)) == 0 {
|
||||
self.try_spawn_slime();
|
||||
}
|
||||
|
||||
@@ -1364,13 +1370,14 @@ impl Game {
|
||||
}
|
||||
|
||||
fn try_spawn_goblin(&mut self) {
|
||||
let max_goblins = 3usize + self.depth.min(5) as usize;
|
||||
let alive_goblins = self
|
||||
.entities
|
||||
.all()
|
||||
.iter()
|
||||
.filter(|e| e.alive && e.kind == EntityKind::Goblin)
|
||||
.count();
|
||||
if alive_goblins >= 3 {
|
||||
if alive_goblins >= max_goblins {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1397,17 +1404,21 @@ impl Game {
|
||||
let id = self.entities.spawn(EntityKind::Goblin);
|
||||
if let Some(g) = self.entities.get_mut(id) {
|
||||
g.build_humanoid(spawn_x as f32, spawn_y as f32);
|
||||
g.health += self.depth as f32 * 5.0;
|
||||
g.max_health += self.depth as f32 * 5.0;
|
||||
g.strength += self.depth;
|
||||
}
|
||||
}
|
||||
|
||||
fn try_spawn_slime(&mut self) {
|
||||
let max_slimes = 2usize + self.depth.min(3) as usize;
|
||||
let alive_slimes = self
|
||||
.entities
|
||||
.all()
|
||||
.iter()
|
||||
.filter(|e| e.alive && e.kind == EntityKind::Slime)
|
||||
.count();
|
||||
if alive_slimes >= 2 {
|
||||
if alive_slimes >= max_slimes {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1434,6 +1445,8 @@ impl Game {
|
||||
let id = self.entities.spawn(EntityKind::Slime);
|
||||
if let Some(s) = self.entities.get_mut(id) {
|
||||
s.build_humanoid(spawn_x as f32, spawn_y as f32);
|
||||
s.health += self.depth as f32 * 3.0;
|
||||
s.max_health += self.depth as f32 * 3.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user