oxygengine-overworld 0.46.1

RPG overworld module for Oxygengine
Documentation
use crate::resources::market::{Currency, MarketItemId};
use oxygengine_core::id::ID;
use std::collections::{HashMap, HashSet};

pub type ObjectiveId = ID<Objective<()>>;
pub type QuestId = ID<Quest<(), ()>>;

#[derive(Debug, Clone)]
pub struct Objective<T>
where
    T: std::fmt::Debug + Clone + Send + Sync,
{
    pub data: T,
}

impl<T> Default for Objective<T>
where
    T: std::fmt::Debug + Default + Clone + Send + Sync,
{
    fn default() -> Self {
        Self {
            data: Default::default(),
        }
    }
}

#[derive(Debug, Clone)]
pub enum QuestReward<V>
where
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    MarketItem(MarketItemId),
    Currency(V),
}

#[derive(Debug, Clone)]
pub struct Quest<T, V>
where
    T: std::fmt::Debug + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    pub data: T,
    pub objectives: HashSet<ObjectiveId>,
    pub rewards: Vec<QuestReward<V>>,
}

impl<T, V> Default for Quest<T, V>
where
    T: std::fmt::Debug + Default + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    fn default() -> Self {
        Self {
            data: Default::default(),
            objectives: Default::default(),
            rewards: Default::default(),
        }
    }
}

impl<T, V> Quest<T, V>
where
    T: std::fmt::Debug + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    pub fn new(data: T) -> Self {
        Self {
            data,
            objectives: Default::default(),
            rewards: Default::default(),
        }
    }

    pub fn with_objective(mut self, id: ObjectiveId) -> Self {
        self.objectives.insert(id);
        self
    }

    pub fn with_reward(mut self, reward: QuestReward<V>) -> Self {
        self.rewards.push(reward);
        self
    }
}

#[derive(Debug, Clone)]
pub struct QuestsDatabase<Q, B, V>
where
    Q: std::fmt::Debug + Clone + Send + Sync,
    B: std::fmt::Debug + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    objectives: HashMap<ObjectiveId, Objective<B>>,
    quests: HashMap<QuestId, Quest<Q, V>>,
}

impl<Q, B, V> Default for QuestsDatabase<Q, B, V>
where
    Q: std::fmt::Debug + Clone + Send + Sync,
    B: std::fmt::Debug + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    fn default() -> Self {
        Self {
            objectives: Default::default(),
            quests: Default::default(),
        }
    }
}

impl<Q, B, V> QuestsDatabase<Q, B, V>
where
    Q: std::fmt::Debug + Clone + Send + Sync,
    B: std::fmt::Debug + Clone + Send + Sync,
    V: Currency + std::fmt::Debug + Clone + Send + Sync,
{
    pub fn register_objective(&mut self, item: Objective<B>) -> ObjectiveId {
        let id = ObjectiveId::new();
        self.objectives.insert(id, item);
        id
    }

    pub fn register_many_objectives<'a>(
        &'a mut self,
        iter: impl Iterator<Item = Objective<B>> + 'a,
    ) -> impl Iterator<Item = ObjectiveId> + 'a {
        let reserve = iter.size_hint();
        let reserve = reserve.1.unwrap_or(reserve.0);
        self.objectives.reserve(reserve);
        iter.map(|item| self.register_objective(item))
    }

    pub fn unregister_objective(&mut self, id: ObjectiveId) -> Option<Objective<B>> {
        if let Some(objective) = self.objectives.remove(&id) {
            for quest in self.quests.values_mut() {
                quest.objectives.remove(&id);
            }
            return Some(objective);
        }
        None
    }

    pub fn unregister_many_objectives<'a>(
        &'a mut self,
        iter: impl Iterator<Item = ObjectiveId> + 'a,
    ) -> impl Iterator<Item = Objective<B>> + 'a {
        iter.filter_map(|id| self.unregister_objective(id))
    }

    pub fn objectives(&self) -> impl Iterator<Item = (ObjectiveId, &Objective<B>)> {
        self.objectives
            .iter()
            .map(|(id, objective)| (*id, objective))
    }

    pub fn objective(&self, id: ObjectiveId) -> Option<&Objective<B>> {
        self.objectives.get(&id)
    }

    pub fn objective_mut(&mut self, id: ObjectiveId) -> Option<&mut Objective<B>> {
        self.objectives.get_mut(&id)
    }

    pub fn find_objectives(
        &self,
        iter: impl Iterator<Item = ObjectiveId>,
    ) -> impl Iterator<Item = (ObjectiveId, &Objective<B>)> {
        iter.filter_map(|id| self.objective(id).map(|objective| (id, objective)))
    }

    pub fn contains_objective(&self, id: ObjectiveId) -> bool {
        self.objectives.contains_key(&id)
    }

    pub fn objective_id(&self, data: &B) -> Option<ObjectiveId>
    where
        B: PartialEq,
    {
        self.objectives
            .iter()
            .find(|(_, objective)| &objective.data == data)
            .map(|(id, _)| *id)
    }

    pub fn register_quest(&mut self, item: Quest<Q, V>) -> QuestId {
        let id = QuestId::new();
        self.quests.insert(id, item);
        id
    }

    pub fn register_many_quests<'a>(
        &'a mut self,
        iter: impl Iterator<Item = Quest<Q, V>> + 'a,
    ) -> impl Iterator<Item = QuestId> + 'a {
        let reserve = iter.size_hint();
        let reserve = reserve.1.unwrap_or(reserve.0);
        self.quests.reserve(reserve);
        iter.map(|item| self.register_quest(item))
    }

    pub fn unregister_quest(&mut self, id: QuestId) -> Option<Quest<Q, V>> {
        self.quests.remove(&id)
    }

    pub fn unregister_many_quests<'a>(
        &'a mut self,
        iter: impl Iterator<Item = QuestId> + 'a,
    ) -> impl Iterator<Item = Quest<Q, V>> + 'a {
        iter.filter_map(|id| self.unregister_quest(id))
    }

    pub fn quests(&self) -> impl Iterator<Item = (QuestId, &Quest<Q, V>)> {
        self.quests.iter().map(|(id, quest)| (*id, quest))
    }

    pub fn quest(&self, id: QuestId) -> Option<&Quest<Q, V>> {
        self.quests.get(&id)
    }

    pub fn quest_mut(&mut self, id: QuestId) -> Option<&mut Quest<Q, V>> {
        self.quests.get_mut(&id)
    }

    pub fn find_quests(
        &self,
        iter: impl Iterator<Item = QuestId>,
    ) -> impl Iterator<Item = (QuestId, &Quest<Q, V>)> {
        iter.filter_map(|id| self.quest(id).map(|quest| (id, quest)))
    }

    pub fn contains_quest(&self, id: QuestId) -> bool {
        self.quests.contains_key(&id)
    }

    pub fn quest_id(&self, data: &Q) -> Option<QuestId>
    where
        Q: PartialEq,
    {
        self.quests
            .iter()
            .find(|(_, quest)| &quest.data == data)
            .map(|(id, _)| *id)
    }
}