underworld_core 0.6.3

Small library to either play a game or assist in generating rooms
Documentation
use rand::Rng;

use crate::{
    actions::MovePlayerItem,
    components::{
        items::{packed_tags_for_item_type, ready_tag_for_item_type},
        PlayerCharacter,
    },
    errors::Error,
    events::{Event, PlayerItemMoved},
    utils::ids::parse_id,
};

const MAX_WEAPONS_AT_READY: usize = 2;
const MAX_WEARABLES_AT_READY: usize = 8;

pub fn handle(
    move_player_item: &MovePlayerItem,
    player: &PlayerCharacter,
) -> Result<Vec<Event>, Error> {
    let item_id = parse_id(&move_player_item.item_id)?;
    let character_item = match player.character.find_item(&item_id) {
        Some(it) => it,
        None => return Err(Error::ItemNotFoundError(item_id.to_string())),
    };

    if character_item.is_at_the_ready() && move_player_item.put_at_the_ready {
        return Ok(Vec::new());
    }

    if character_item.is_packed() && !move_player_item.put_at_the_ready {
        return Ok(Vec::new());
    }

    if character_item.is_weapon()
        && player.character.count_weapons_at_ready() >= MAX_WEAPONS_AT_READY
        && move_player_item.put_at_the_ready
    {
        return Err(Error::TooManyWeaponsEquippedError);
    }

    if character_item.is_wearable()
        && player.character.count_wearables_at_ready() >= MAX_WEARABLES_AT_READY
        && move_player_item.put_at_the_ready
    {
        return Err(Error::TooManyWearablesEquippedError);
    }

    let location = match &move_player_item.location_tag {
        Some(it) => *it,
        None => {
            if move_player_item.put_at_the_ready {
                ready_tag_for_item_type(&character_item.item.item_type)
            } else {
                let mut rng = rand::thread_rng();
                let possibilities = packed_tags_for_item_type(&character_item.item.item_type);
                let index = rng.gen_range(0..possibilities.len());
                possibilities.get(index).cloned().unwrap()
            }
        }
    };

    Ok(vec![Event::PlayerItemMoved(PlayerItemMoved {
        item_id,
        at_the_ready: move_player_item.put_at_the_ready,
        location,
    })])
}