Skip to main content

uorustlibs/
skill.rs

1//! Skill objects represent named skills that appear in UO's Skills menu.
2//! They also contain a flag denoting whether they are clicked to activate
3//!
4//! Skills are traditionally stored in skills.mul/skills.idx
5//!
6//! Skills are encoded as a list of
7//! |clickable:u8|name:c-string|
8
9use crate::error::{MulReaderError, MulReaderResult};
10use crate::mul::MulReader;
11use std::fs::File;
12use std::io::{Read, Seek};
13use std::path::Path;
14use std::str::from_utf8;
15
16/// A skill name, plus whether it requires clicking to activate
17#[derive(Debug, PartialEq, Eq, Clone)]
18pub struct Skill {
19    pub clickable: bool,
20    pub name: String,
21}
22
23impl Skill {
24    /// Create a new Skill object
25    pub fn new(clickable: bool, name: String) -> Skill {
26        Skill { clickable, name }
27    }
28
29    /// Convert a skill back into its canonical mul representation
30    pub fn serialize(&self) -> Vec<u8> {
31        let mut vec = vec![if self.clickable { 1 } else { 0 }];
32        vec.extend_from_slice(self.name.as_bytes());
33        vec.push(0);
34        vec
35    }
36}
37
38/// A struct to help read out Skill data
39pub struct SkillReader<T: Read + Seek> {
40    mul_reader: MulReader<T>,
41}
42
43impl SkillReader<File> {
44    /// Create a new SkillReader from an index and mul path
45    pub fn new(index_path: &Path, mul_path: &Path) -> MulReaderResult<SkillReader<File>> {
46        let mul_reader = MulReader::new(index_path, mul_path)?;
47        Ok(SkillReader { mul_reader })
48    }
49}
50
51impl<T: Read + Seek> SkillReader<T> {
52    pub fn from_mul(reader: MulReader<T>) -> SkillReader<T> {
53        SkillReader { mul_reader: reader }
54    }
55
56    pub fn read_skill(&mut self, id: u32) -> MulReaderResult<Skill> {
57        let record = self.mul_reader.read(id)?;
58        let slice = &record.data[1..record.data.len() - 1];
59        match from_utf8(slice) {
60            Ok(string) => Ok(Skill::new(record.data[0] == 1, String::from(string))),
61            Err(e) => Err(MulReaderError::FailedParse(format!(
62                "Failed to parse skill at index {} - {}",
63                id, e
64            ))),
65        }
66    }
67
68    pub fn read_all(&mut self) -> Vec<Skill> {
69        let mut result = vec![];
70        let mut id = 0;
71        while let Ok(skill) = self.read_skill(id) {
72            result.push(skill);
73            id += 1;
74        }
75        result
76    }
77}