Skip to content

Commit 89a313c

Browse files
authored
Merge pull request #73 from facundoolano/chest_merge
Merge tombstone contents
2 parents e52c60c + c07ce80 commit 89a313c

3 files changed

Lines changed: 72 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
### Changed
1313
* Tombstones are found with `rpg ls` instead of automatically #52
1414

15+
### Fixed
16+
* When hero dies twice in the same location, tombstone chest contents
17+
are merged instead of overridden #73
18+
1519
## [0.4.1](https://github.com/facundoolano/rpg-cli/releases/tag/0.4.1) - 2021-06-14
1620
### Changed
1721
* Game data is now serialized to JSON to allow extending it without breaking backwards compatibility.

src/game/chest.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::randomizer::Randomizer;
66
use serde::{Deserialize, Serialize};
77
use std::collections::HashMap;
88

9-
/// The tombstone is a bag of items left at the hero's dying location.
10-
/// When the next hero visits that location, it can pick up the items.
9+
/// A chest is a bag of items that can be picked up by the hero.
10+
/// It can randomly appear at a location upon inspection, or dropped
11+
/// by the hero when they die.
1112
#[derive(Serialize, Deserialize)]
1213
pub struct Chest {
1314
items: HashMap<String, Vec<Box<dyn Item>>>,
@@ -98,13 +99,37 @@ impl Chest {
9899
game.gold += self.gold;
99100
(to_log, self.gold)
100101
}
102+
103+
/// Add the elements of `other` to this chest
104+
pub fn extend(&mut self, mut other: Self) {
105+
// keep the best of each equipment
106+
if let Some(sword) = other.sword.take() {
107+
if sword.is_upgrade_from(&self.sword.as_ref()) {
108+
self.sword = Some(sword);
109+
}
110+
}
111+
112+
if let Some(shield) = other.shield.take() {
113+
if shield.is_upgrade_from(&self.shield.as_ref()) {
114+
self.shield = Some(shield);
115+
}
116+
}
117+
118+
// merge both item maps
119+
for (key, other_items) in other.items.drain() {
120+
let self_items = self.items.entry(key).or_default();
121+
self_items.extend(other_items);
122+
}
123+
124+
self.gold += other.gold;
125+
}
101126
}
102127

103128
#[cfg(test)]
104129
mod tests {
105130
use super::*;
106131
use crate::item::equipment::{Shield, Sword};
107-
use crate::item::Potion;
132+
use crate::item::{Escape, Potion};
108133

109134
#[test]
110135
fn test_empty_drop_pickup() {
@@ -180,4 +205,36 @@ mod tests {
180205

181206
assert_eq!(3, *game.inventory().get("potion").unwrap());
182207
}
208+
209+
#[test]
210+
fn test_merge() {
211+
let potions: Vec<Box<dyn Item>> = vec![Box::new(Potion::new(1)), Box::new(Potion::new(1))];
212+
let mut items = HashMap::new();
213+
items.insert("potion".to_string(), potions);
214+
let mut chest1 = Chest {
215+
items,
216+
sword: Some(Sword::new(1)),
217+
shield: Some(Shield::new(10)),
218+
gold: 100,
219+
};
220+
221+
let potions: Vec<Box<dyn Item>> = vec![Box::new(Potion::new(1))];
222+
let escapes: Vec<Box<dyn Item>> = vec![Box::new(Escape::new())];
223+
let mut items = HashMap::new();
224+
items.insert("potion".to_string(), potions);
225+
items.insert("escape".to_string(), escapes);
226+
let chest2 = Chest {
227+
items,
228+
sword: Some(Sword::new(10)),
229+
shield: Some(Shield::new(1)),
230+
gold: 100,
231+
};
232+
233+
chest1.extend(chest2);
234+
assert_eq!(200, chest1.gold);
235+
assert_eq!(10, chest1.sword.as_ref().unwrap().level());
236+
assert_eq!(10, chest1.shield.as_ref().unwrap().level());
237+
assert_eq!(3, chest1.items.get("potion").unwrap().len());
238+
assert_eq!(1, chest1.items.get("escape").unwrap().len());
239+
}
183240
}

src/game/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,14 @@ impl Game {
250250
Ok(())
251251
}
252252
Err(character::Dead) => {
253-
// leave hero items in the location
254-
let tombstone = Chest::drop(self);
255-
self.tombstones.insert(self.location.to_string(), tombstone);
253+
// Drop hero items in the location. If there was a previous tombstone
254+
// merge the contents of both chests
255+
let mut tombstone = Chest::drop(self);
256+
let location = self.location.to_string();
257+
if let Some(previous) = self.tombstones.remove(&location) {
258+
tombstone.extend(previous);
259+
}
260+
self.tombstones.insert(location, tombstone);
256261

257262
Event::emit(self, Event::BattleLost);
258263
Err(character::Dead)

0 commit comments

Comments
 (0)