diff --git a/CHANGELOG.md b/CHANGELOG.md index fd13acce..9058a973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +### Added +* Quest to beat your own shadow #86 + +### Fixed +* Reach level 50 and 100 unlock and reward 4128f75 + ## [0.6.0](https://github.com/facundoolano/rpg-cli/releases/tag/0.6.0) - 2021-08-04 ### Added * Customizable classes file #76 diff --git a/src/character/enemy.rs b/src/character/enemy.rs index 6feea6fe..bff51950 100644 --- a/src/character/enemy.rs +++ b/src/character/enemy.rs @@ -2,12 +2,21 @@ use super::{class::Category, class::Class, Character}; use crate::location; use crate::randomizer::{random, Randomizer}; use rand::prelude::SliceRandom; +use rand::Rng; pub fn at(location: &location::Location, player: &Character) -> Character { - let distance = location.distance_from_home(); - let level = level(player.level, distance.len()); - let category = weighted_choice(distance); - Character::new(Class::random(category).clone(), level) + let (class, level) = if should_find_shadow(location) { + let mut class = player.class.clone(); + class.name = String::from("shadow"); + (class, player.level + 3) + } else { + let distance = location.distance_from_home(); + let level = level(player.level, distance.len()); + let category = weighted_choice(distance); + (Class::random(category).clone(), level) + }; + + Character::new(class, level) } fn level(player_level: i32, distance_from_home: i32) -> i32 { @@ -15,6 +24,11 @@ fn level(player_level: i32, distance_from_home: i32) -> i32 { random().enemy_level(level) } +fn should_find_shadow(location: &location::Location) -> bool { + let mut rng = rand::thread_rng(); + location.is_home() && rng.gen_ratio(1, 10) +} + /// Choose an enemy randomly, with higher chance to difficult enemies the further from home. fn weighted_choice(distance: location::Distance) -> Category { // the weights for each group of enemies are different depending on the distance diff --git a/src/log.rs b/src/log.rs index 91f8a293..d6a58556 100644 --- a/src/log.rs +++ b/src/log.rs @@ -402,7 +402,9 @@ fn battle_log(character: &Character, suffix: &str) { fn format_character(character: &Character) -> String { let name = format!("{:>8}", character.name()); - let name = if character.is_player() { + let name = if character.name() == "shadow" { + name.dimmed() + } else if character.is_player() { name.bold() } else { name.yellow().bold() diff --git a/src/quest/beat_enemy.rs b/src/quest/beat_enemy.rs index 38e4bed6..5d2a10a6 100644 --- a/src/quest/beat_enemy.rs +++ b/src/quest/beat_enemy.rs @@ -16,6 +16,17 @@ pub fn of_class(category: class::Category, description: &str) -> Box }) } +pub fn shadow() -> Box { + let mut to_beat = HashSet::new(); + to_beat.insert(String::from("shadow")); + + Box::new(BeatEnemyClass { + to_beat, + total: 1, + description: String::from("Beat your own shadow."), + }) +} + pub fn at_distance(distance: i32) -> Box { Box::new(BeatEnemyDistance { distance }) } diff --git a/src/quest/mod.rs b/src/quest/mod.rs index a35c33c7..4a4b8063 100644 --- a/src/quest/mod.rs +++ b/src/quest/mod.rs @@ -67,16 +67,18 @@ impl QuestList { beat_enemy::of_class(class::Category::Legendary, "beat all legendary creatures"), )); + self.todo + .push((10, 10000, Box::new(level::ReachLevel::new(50)))); + for name in class::Class::names(class::Category::Player) { self.todo .push((10, 5000, Box::new(level::RaiseClassLevels::new(&name)))); } - self.todo - .push((2, 500, Box::new(level::ReachLevel::new(50)))); + self.todo.push((15, 20000, beat_enemy::shadow())); self.todo - .push((2, 500, Box::new(level::ReachLevel::new(100)))); + .push((50, 100000, Box::new(level::ReachLevel::new(100)))); } /// Pass the event to each of the quests, moving the completed ones to DONE.