use serde::Serialize;
use super::{Edition, Gen3, ItemId, text};
use crate::Result;
use crate::io::{ByteSource, Reader};
const RECORD_LEN: usize = 44;
const NAME_LEN: usize = 14;
const DESCRIPTION: u32 = 0x14;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Item {
pub id: ItemId,
pub name: String,
pub description: String,
pub price: u16,
pub pocket: Pocket,
pub hold_effect: u8,
pub hold_parameter: u8,
pub importance: u8,
pub registrable: bool,
pub usage: u8,
pub battle_usage: u8,
pub secondary_id: u32,
}
pub(super) fn parse<S: ByteSource>(game: &Gen3<S>) -> Result<Vec<Item>> {
let edition = game.edition;
let count = edition.item_count as usize;
let records = game.read(edition.items, count * RECORD_LEN)?;
(1..count)
.map(|index| {
let mut item =
parse_record(edition, index, &records[index * RECORD_LEN..][..RECORD_LEN])?;
let at = edition.items + (index * RECORD_LEN) as u32 + DESCRIPTION;
item.description = game.string_at(at)?;
Ok(item)
})
.collect()
}
fn parse_record(edition: &Edition, index: usize, bytes: &[u8]) -> Result<Item> {
let mut record = Reader::new("Gen 3 item", bytes);
let name = text::decode(record.take(NAME_LEN)?);
record.skip(2)?; let price = record.u16()?;
let hold_effect = record.u8()?;
let hold_parameter = record.u8()?;
record.skip(4)?; let importance = record.u8()?;
let registrable = record.u8()? != 0;
let pocket = match record.u8()? {
raw @ 1..=5 => edition.pockets[raw as usize - 1],
raw => Pocket::Unknown(raw),
};
let usage = record.u8()?;
record.skip(4)?; let battle_usage = record.u8()?;
record.skip(7)?; Ok(Item {
id: ItemId(index as u16),
name,
description: String::new(),
price,
pocket,
hold_effect,
hold_parameter,
importance,
registrable,
usage,
battle_usage,
secondary_id: record.u32()?,
})
}
raw_enum! {
pub enum Pocket: u8 {
Items = 1,
PokeBalls = 2,
Machines = 3,
Berries = 4,
KeyItems = 5,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::games::pokemon::gen3::{FIRERED, RUBY};
#[test]
fn parses_records_with_each_editions_pockets() {
let mut potion = [0u8; RECORD_LEN];
potion[..7].copy_from_slice(&[0xCA, 0xC9, 0xCE, 0xC3, 0xC9, 0xC8, 0xFF]);
potion[0x10..0x12].copy_from_slice(&300u16.to_le_bytes());
potion[0x1A] = 1;
potion[0x20] = 1;
let item = parse_record(&RUBY, 13, &potion).unwrap();
assert_eq!((item.name.as_str(), item.price), ("POTION", 300));
assert_eq!((item.pocket, item.battle_usage), (Pocket::Items, 1));
let mut key = potion;
key[0x1A] = 2;
assert_eq!(
parse_record(&RUBY, 1, &key).unwrap().pocket,
Pocket::PokeBalls
);
assert_eq!(
parse_record(&FIRERED, 1, &key).unwrap().pocket,
Pocket::KeyItems
);
key[0x1A] = 9;
assert_eq!(
parse_record(&RUBY, 1, &key).unwrap().pocket,
Pocket::Unknown(9)
);
assert!(parse_record(&RUBY, 1, &key[..40]).is_err());
}
}