elseware/src/ship/items/floor.rs
jake a6e50555de
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
appease the clip
2021-12-28 01:37:24 -07:00

254 lines
7.4 KiB
Rust

use crate::ship::items::ClientItemId;
use crate::entity::item::{ItemEntityId, ItemDetail};
use crate::entity::item::Meseta;
use crate::entity::item::tool::Tool;
use crate::ship::map::MapArea;
use crate::ship::items::inventory::{IndividualInventoryItem, StackedInventoryItem, InventoryItemHandle};
#[derive(Debug, Clone)]
pub struct IndividualFloorItem {
pub entity_id: ItemEntityId,
pub item_id: ClientItemId,
pub item: ItemDetail,
pub map_area: MapArea,
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Debug, Clone)]
pub struct StackedFloorItem {
pub entity_ids: Vec<ItemEntityId>,
pub item_id: ClientItemId,
pub tool: Tool,
pub map_area: MapArea,
pub x: f32,
pub y: f32,
pub z: f32,
}
impl StackedFloorItem {
pub fn count(&self) -> usize {
self.entity_ids.len()
}
pub fn as_client_bytes(&self) -> [u8; 16] {
self.tool.as_stacked_bytes(self.count())
}
}
#[derive(Debug, Clone)]
pub struct MesetaFloorItem {
pub item_id: ClientItemId,
pub meseta: Meseta,
pub map_area: MapArea,
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Debug, Clone)]
pub enum FloorItem {
Individual(IndividualFloorItem),
Stacked(StackedFloorItem),
Meseta(MesetaFloorItem),
}
impl FloorItem {
pub fn item_id(&self) -> ClientItemId {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.item_id
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.item_id
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.item_id
}
}
}
pub fn x(&self) -> f32 {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.x
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.x
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.x
}
}
}
pub fn y(&self) -> f32 {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.y
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.y
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.y
}
}
}
pub fn z(&self) -> f32 {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.z
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.z
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.z
}
}
}
pub fn map_area(&self) -> MapArea {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.map_area
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.map_area
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.map_area
}
}
}
pub fn as_client_bytes(&self) -> [u8; 16] {
match self {
FloorItem::Individual(individual_floor_item) => {
individual_floor_item.item.as_client_bytes()
},
FloorItem::Stacked(stacked_floor_item) => {
stacked_floor_item.as_client_bytes()
},
FloorItem::Meseta(meseta_floor_item) => {
meseta_floor_item.meseta.as_bytes()
}
}
}
}
pub struct FloorItemHandle<'a> {
floor: &'a mut RoomFloorItems,
index: usize,
}
impl<'a> FloorItemHandle<'a> {
pub fn item(&'a self) -> Option<&'a FloorItem> {
self.floor.0.get(self.index)
}
pub fn remove_from_floor(self) {
self.floor.0.remove(self.index);
}
}
// TODO: floors should keep track of their own item_ids
#[derive(Debug, Default)]
pub struct RoomFloorItems(Vec<FloorItem>);
impl RoomFloorItems {
pub fn add_item(&mut self, item: FloorItem) {
self.0.push(item);
}
pub fn remove_item(&mut self, item_id: &ClientItemId) {
self.0.retain(|item| item.item_id() != *item_id);
}
// TODO: &ClientItemId
pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&FloorItem> {
self.0.iter().find(|item| item.item_id() == item_id)
}
// TODO: &ClientItemId
pub fn get_item_handle_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItemHandle> {
let index = self.0.iter().position(|item| item.item_id() == item_id)?;
Some(FloorItemHandle {
floor: self,
index,
})
}
pub fn take_item_by_id(&mut self, item_id: ClientItemId) -> Option<FloorItem> {
self.0
.drain_filter(|i| i.item_id() == item_id)
.next()
}
pub fn drop_individual_inventory_item(&mut self, individual_inventory_item: IndividualInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &IndividualFloorItem {
self.0.push(FloorItem::Individual(IndividualFloorItem {
entity_id: individual_inventory_item.entity_id,
item_id: individual_inventory_item.item_id,
item: individual_inventory_item.item,
map_area: item_drop_location.0,
x: item_drop_location.1,
y: item_drop_location.2,
z: item_drop_location.3,
}));
match self.0.last().unwrap() {
FloorItem::Individual(item) => item,
_ => unreachable!(),
}
}
pub fn drop_stacked_inventory_item(&mut self, stacked_inventory_item: StackedInventoryItem, item_drop_location: (MapArea, f32, f32, f32)) -> &StackedFloorItem {
self.0.push(FloorItem::Stacked(StackedFloorItem {
entity_ids: stacked_inventory_item.entity_ids,
item_id: stacked_inventory_item.item_id,
tool: stacked_inventory_item.tool,
map_area: item_drop_location.0,
x: item_drop_location.1,
y: item_drop_location.2,
z: item_drop_location.3,
}));
match self.0.last().unwrap() {
FloorItem::Stacked(item) => item,
_ => unreachable!(),
}
}
// TODO: Result
// TODO: if consumed_item is not a tool items do not get placed back into inventory (should I care?)
pub fn drop_partial_stacked_inventory_item(&mut self, inventory_item: InventoryItemHandle, amount: usize, new_item_id: ClientItemId, item_drop_location: (MapArea, f32, f32, f32)) -> Option<&StackedFloorItem> {
let consumed_item = inventory_item.consume(amount).ok()?;
if let ItemDetail::Tool(tool) = consumed_item.item() {
self.0.push(FloorItem::Stacked(StackedFloorItem {
entity_ids: consumed_item.entity_ids(),
item_id: new_item_id,
tool,
map_area: item_drop_location.0,
x: item_drop_location.1,
y: item_drop_location.2,
z: item_drop_location.3,
}))
}
else {
return None
}
match self.0.last().unwrap() {
FloorItem::Stacked(item) => Some(item),
_ => unreachable!(),
}
}
}