use crate::bits::{BitReader, BitWriter};
use crate::data::ExternalData;
use crate::error::{Error, Result};
use crate::model::item::Item;
macro_rules! list_newtype {
($name:ident, $item:ty) => {
impl ::std::ops::Deref for $name {
type Target = Vec<$item>;
fn deref(&self) -> &Vec<$item> {
&self.0
}
}
impl ::std::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Vec<$item> {
&mut self.0
}
}
impl<'a> IntoIterator for &'a $name {
type Item = &'a $item;
type IntoIter = std::slice::Iter<'a, $item>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut $name {
type Item = &'a mut $item;
type IntoIter = std::slice::IterMut<'a, $item>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl IntoIterator for $name {
type Item = $item;
type IntoIter = std::vec::IntoIter<$item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl FromIterator<$item> for $name {
fn from_iter<T: IntoIterator<Item = $item>>(iter: T) -> Self {
$name(iter.into_iter().collect())
}
}
impl From<Vec<$item>> for $name {
fn from(v: Vec<$item>) -> Self {
$name(v)
}
}
};
}
pub(crate) use list_newtype;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct ItemsSection(pub Vec<Item>);
list_newtype!(ItemsSection, Item);
impl ItemsSection {
pub const MAGIC: u16 = 0x4D4A;
pub fn read(r: &mut BitReader<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<Self> {
let magic = r.read_u16()?;
if magic != Self::MAGIC {
return Err(Error::InvalidMagic { section: "items section", found: magic as u32 });
}
let count = r.read_u16()?;
let mut items = Vec::with_capacity((count as usize).min(r.bits_remaining() / 32));
for _ in 0..count {
items.push(Item::read(r, data, save_version)?);
}
Ok(ItemsSection(items))
}
pub fn write(&self, w: &mut BitWriter<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<()> {
w.write_u16(Self::MAGIC)?;
w.write_u16(self.0.len() as u16)?;
for item in &self.0 {
item.write(w, data, save_version)?;
}
Ok(())
}
pub fn estimate_size(&self) -> usize {
4 + self.0.iter().map(Item::count_recursive).sum::<usize>() * 200
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Corpse {
pub unused: u32,
pub x: u32,
pub y: u32,
pub items: ItemsSection,
}
impl Corpse {
pub fn read(r: &mut BitReader<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<Self> {
Ok(Corpse {
unused: r.read_u32()?,
x: r.read_u32()?,
y: r.read_u32()?,
items: ItemsSection::read(r, data, save_version)?,
})
}
pub fn write(&self, w: &mut BitWriter<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<()> {
w.write_u32(self.unused)?;
w.write_u32(self.x)?;
w.write_u32(self.y)?;
self.items.write(w, data, save_version)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct CorpseSection(pub Vec<Corpse>);
list_newtype!(CorpseSection, Corpse);
impl CorpseSection {
pub const MAGIC: u16 = 0x4D4A;
pub fn read(r: &mut BitReader<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<Self> {
let magic = r.read_u16()?;
if magic != Self::MAGIC {
return Err(Error::InvalidMagic { section: "corpse section", found: magic as u32 });
}
let count = r.read_u16()?;
let mut corpses = Vec::with_capacity(count.min(16) as usize);
for _ in 0..count {
corpses.push(Corpse::read(r, data, save_version)?);
}
Ok(CorpseSection(corpses))
}
pub fn write(&self, w: &mut BitWriter<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<()> {
w.write_u16(Self::MAGIC)?;
w.write_u16(self.0.len() as u16)?;
for corpse in &self.0 {
corpse.write(w, data, save_version)?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MercItemsSection {
pub items: ItemsSection,
}
impl MercItemsSection {
pub const MAGIC: u16 = 0x666A;
pub fn read(
r: &mut BitReader<'_>,
data: &(impl ExternalData + ?Sized),
has_merc: bool,
save_version: u32,
) -> Result<Self> {
let magic = r.read_u16()?;
if magic != Self::MAGIC {
return Err(Error::InvalidMagic { section: "merc items section", found: magic as u32 });
}
let items = if has_merc { ItemsSection::read(r, data, save_version)? } else { ItemsSection::default() };
Ok(MercItemsSection { items })
}
pub fn write(
&self,
w: &mut BitWriter<'_>,
data: &(impl ExternalData + ?Sized),
has_merc: bool,
save_version: u32,
) -> Result<()> {
w.write_u16(Self::MAGIC)?;
if has_merc {
self.items.write(w, data, save_version)?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IronGolemSection {
pub golem_item: Option<Item>,
}
impl IronGolemSection {
pub const MAGIC: u16 = 0x666B;
pub fn read(r: &mut BitReader<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<Self> {
let magic = r.read_u16()?;
if magic != Self::MAGIC {
return Err(Error::InvalidMagic { section: "iron golem section", found: magic as u32 });
}
let golem_item = if r.read_u8()? != 0 { Some(Item::read(r, data, save_version)?) } else { None };
Ok(IronGolemSection { golem_item })
}
pub fn write(&self, w: &mut BitWriter<'_>, data: &(impl ExternalData + ?Sized), save_version: u32) -> Result<()> {
w.write_u16(Self::MAGIC)?;
w.write_u8(self.golem_item.is_some() as u8)?;
if let Some(item) = &self.golem_item {
item.write(w, data, save_version)?;
}
Ok(())
}
}