Add events and achievement items for killing players and npcs.

This commit is contained in:
Shane Handley 2020-07-05 13:46:40 +10:00
parent fb8590fac7
commit e607ec498d
3 changed files with 81 additions and 15 deletions

View File

@ -1,4 +1,7 @@
use crate::comp::item::{Consumable, Item, ItemKind};
use crate::comp::{
self,
item::{Consumable, Item, ItemKind},
};
use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage;
@ -7,25 +10,23 @@ pub enum AchievementEvent {
None,
CollectedItem(Item),
LevelUp(u32),
KilledPlayer,
KilledNpc,
}
/// The types of achievements available in game
///
/// Some potential additions in the future:
/// - ReachCoordinate
/// - CollectCurrency
/// - KillPlayers
/// - OpenChests
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AchievementAction {
None,
CollectConsumable(Consumable),
ReachLevel,
KillPlayers,
KillNpcs,
}
/// Information about an achievement. This differs from a complete
/// [`Achievement`](struct.Achievement.html) in that it describes the
/// achievement without any information about progress
/// achievement without any information about progress or completion status
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AchievementItem {
pub title: String,
@ -36,6 +37,8 @@ pub struct AchievementItem {
impl AchievementItem {
pub fn matches_event(&self, event: AchievementEvent) -> bool {
match event {
AchievementEvent::KilledNpc => self.action == AchievementAction::KillNpcs,
AchievementEvent::KilledPlayer => self.action == AchievementAction::KillPlayers,
AchievementEvent::LevelUp(_) => self.action == AchievementAction::ReachLevel,
AchievementEvent::CollectedItem(item) => match self.action {
AchievementAction::CollectConsumable(consumable) => {
@ -47,6 +50,7 @@ impl AchievementItem {
},
_ => false,
},
AchievementEvent::None => false,
_ => {
tracing::warn!(
?event,
@ -158,7 +162,7 @@ impl AchievementUpdate {
}
impl Component for AchievementUpdate {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
type Storage = IDVStorage<Self>;
}
#[cfg(test)]

View File

@ -1,12 +1,52 @@
[
(
title: "Collect 5 Apples",
title: "Collect 10 apples",
action: CollectConsumable(Apple),
target: 5
target: 10
),
(
title: "Collect 7 Apples",
title: "Collect 50 apples",
action: CollectConsumable(Apple),
target: 7
target: 50
),
(
title: "Pick a mushroom",
action: CollectConsumable(Mushroom),
target: 1
),
(
title: "Kill an NPC",
action: KillNpcs,
target: 1
),
(
title: "Kill 10 NPCs",
action: KillNpcs,
target: 10
),
(
title: "Kill 100 NPCs",
action: KillNpcs,
target: 100
),
(
title: "Kill another player",
action: KillPlayers,
target: 1
),
(
title: "Kill 10 players",
action: KillPlayers,
target: 10
),
(
title: "Find a Velorite fragment",
action: CollectConsumable(VeloriteFrag),
target: 1
),
(
title: "Find Velorite",
action: CollectConsumable(Velorite),
target: 1
)
]

View File

@ -2,8 +2,8 @@ use crate::{client::Client, Server, SpawnPoint, StateExt};
use common::{
assets,
comp::{
self, item::lottery::Lottery, object, AchievementEvent, Body, HealthChange, HealthSource,
Player, Stats,
self, item::lottery::Lottery, object, AchievementEvent, Alignment, Body, HealthChange,
HealthSource, Player, Stats,
},
msg::{PlayerListUpdate, ServerMsg},
state::BlockChange,
@ -58,6 +58,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
{
// Give EXP to the killer if entity had stats
let mut stats = state.ecs().write_storage::<Stats>();
if let Some(entity_stats) = stats.get(entity).cloned() {
if let HealthSource::Attack { by } | HealthSource::Projectile { owner: Some(by) } =
cause
@ -73,6 +74,27 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
as i64,
);
}
// Write an associated AchievementEvent for this kill
if let Some(event) = match (
state.ecs().read_storage::<Player>().get(entity),
state.ecs().read_storage::<Alignment>().get(entity),
) {
(Some(_), _) => Some(AchievementEvent::KilledPlayer),
(None, Some(alignment)) => {
if alignment == &comp::Alignment::Npc {
Some(AchievementEvent::KilledNpc)
} else {
None
}
},
_ => None,
} {
let _ = state
.ecs()
.write_storage()
.insert(entity, comp::AchievementUpdate::new(event));
}
});
}
}