doukutsu-rs/src/mod_list.rs

201 lines
6.9 KiB
Rust
Raw Permalink Normal View History

2022-02-13 19:39:28 +00:00
use std::collections::HashMap;
2022-02-10 09:21:28 +00:00
use std::io::{BufRead, BufReader};
use std::iter::Peekable;
use std::str::Chars;
2022-11-19 17:20:03 +00:00
use crate::framework::context::Context;
use crate::framework::error::GameResult;
2022-02-10 09:21:28 +00:00
use crate::framework::filesystem;
2022-03-15 22:18:25 +00:00
use crate::mod_requirements::ModRequirements;
2022-02-10 09:21:28 +00:00
#[derive(Debug)]
pub struct ModInfo {
pub id: String,
pub requirement: Requirement,
pub priority: u32,
2022-02-18 00:54:22 +00:00
pub save_slot: i32,
2022-02-10 09:21:28 +00:00
pub path: String,
2022-02-13 19:39:28 +00:00
pub name: String,
pub description: String,
2022-05-22 13:17:55 +00:00
pub valid: bool,
2022-02-10 09:21:28 +00:00
}
2022-03-15 22:18:25 +00:00
impl ModInfo {
pub fn satisfies_requirement(&self, mod_requirements: &ModRequirements) -> bool {
match self.requirement {
Requirement::Unlocked => true,
Requirement::Locked => false,
Requirement::RequireHell => mod_requirements.beat_hell,
Requirement::RequireItem(item_id) => mod_requirements.has_item(item_id),
Requirement::RequireWeapon(weapon_id) => mod_requirements.has_weapon(weapon_id),
}
}
}
2022-02-10 09:21:28 +00:00
#[derive(Debug, Copy, Clone)]
pub enum Requirement {
/// R+
Unlocked,
/// R-
Locked,
/// RI##
RequireItem(u16),
/// RA##
RequireWeapon(u16),
/// RG
RequireHell,
}
pub struct ModList {
pub mods: Vec<ModInfo>,
}
impl ModList {
2022-02-13 19:39:28 +00:00
pub fn load(ctx: &mut Context, string_table: &HashMap<String, String>) -> GameResult<ModList> {
2022-02-10 09:21:28 +00:00
let mut mods = Vec::new();
if let Ok(file) = filesystem::open(ctx, "/mods.txt") {
let reader = BufReader::new(file);
let mut lines = reader.lines();
while let Some(Ok(line)) = lines.next() {
if line == "=MOD LIST START=" {
break;
}
}
while let Some(Ok(line)) = lines.next() {
let mut id = String::new();
let mut requirement = Requirement::Unlocked;
let mut priority = 1000u32;
let mut path = String::new();
let mut chars = line.chars().peekable();
fn consume_spaces(chars: &mut Peekable<Chars>) {
while let Some(&c) = chars.peek() {
if c != ' ' {
break;
}
chars.next();
}
}
consume_spaces(&mut chars);
id.push_str("csmod_");
for c in &mut chars {
if c == ' ' {
break;
}
id.push(c);
}
consume_spaces(&mut chars);
loop {
if let Some(c) = chars.next() {
if c == 'R' {
if let Some(c) = chars.next() {
if c == '+' {
requirement = Requirement::Unlocked;
} else if c == '-' {
requirement = Requirement::Locked;
} else if c == 'I' {
let mut item_id = String::new();
for c in &mut chars {
if c == ' ' {
break;
}
item_id.push(c);
}
requirement = Requirement::RequireItem(item_id.parse().unwrap_or(0));
} else if c == 'A' {
let mut weapon_id = String::new();
for c in &mut chars {
if c == ' ' {
break;
}
weapon_id.push(c);
}
requirement = Requirement::RequireWeapon(weapon_id.parse().unwrap_or(0));
} else if c == 'G' {
requirement = Requirement::RequireHell;
}
}
} else if c == 'P' {
priority = 0;
for c in &mut chars {
if c == ' ' {
break;
}
priority = priority.saturating_mul(10).saturating_add(c.to_digit(10).unwrap_or(0));
}
} else if c == '/' {
path.push(c);
while let Some(&c) = chars.peek() {
path.push(c);
chars.next();
}
break;
} else if c == ' ' {
continue;
}
} else {
break;
}
}
2022-05-22 13:17:55 +00:00
let mut valid = false;
2022-02-13 19:39:28 +00:00
let mut name = String::new();
let mut description = String::new();
2022-02-18 00:54:22 +00:00
let mut save_slot = -1;
2022-02-13 19:39:28 +00:00
if let Ok(file) = filesystem::open(ctx, [&path, "/mod.txt"].join("")) {
2022-05-22 13:17:55 +00:00
valid = true;
2022-02-13 19:39:28 +00:00
let reader = BufReader::new(file);
let mut lines = reader.lines();
2022-02-18 00:54:22 +00:00
if let Some(line) = lines.nth(1) {
save_slot = line.unwrap_or("-1".to_string()).parse::<i32>().unwrap_or(-1);
}
if let Some(line) = lines.next() {
2022-02-13 19:39:28 +00:00
let read_name = line.unwrap_or("No Mod Name".to_string()).to_string();
name = string_table.get(&read_name).unwrap_or(&read_name).to_string();
}
if let Some(line) = lines.next() {
description = line.unwrap_or("No Description".to_string()).to_string();
}
2022-05-22 13:17:55 +00:00
} else {
name = path.clone();
description = "mod.txt not found".to_string();
2022-02-13 19:39:28 +00:00
}
2022-05-22 13:17:55 +00:00
mods.push(ModInfo { id, requirement, priority, save_slot, path, name, description, valid })
2022-02-10 09:21:28 +00:00
}
}
mods.sort_by(|a, b| a.priority.cmp(&b.priority));
Ok(ModList { mods })
}
2022-02-23 00:46:49 +00:00
pub fn get_save_from_path(&self, mod_path: String) -> i32 {
if let Some(mod_sel) = self.mods.iter().find(|x| x.path == mod_path) {
mod_sel.save_slot
} else {
-1
}
}
pub fn get_name_from_path(&self, mod_path: String) -> &str {
if let Some(mod_sel) = self.mods.iter().find(|x| x.path == mod_path) {
&mod_sel.name
} else {
"NoName"
}
}
2022-02-10 09:21:28 +00:00
}