diff --git a/MarathonData.md b/MarathonData.md index d43cafa..22a1c4d 100644 --- a/MarathonData.md +++ b/MarathonData.md @@ -2170,8 +2170,6 @@ If `DataVersion` is `DataM1`, then `ItemOpt` must be set by the client. | `TermPause` | `8` | | `M1Monster` | `9` | | `M1Weps` | `10` | -| `NetPlay` | `13` | -| `Solo` | `14` | - `Vacuum` makes most weapons not work and oxygen deplete. - `Magnetic` fucks up the motion sensor. @@ -2185,8 +2183,6 @@ If `DataVersion` is `DataM1`, then `ItemOpt` must be set by the client. - `M1Monster` sets monster activation limits to Marathon 1's. - `M1Weps` changes weapon pickups on Total Carnage and makes grenades low gravity. -- `NetPlay` marks the map as net-play compatible. -- `Solo` marks the map as solo compatible. ### Light Flags ### diff --git a/source/durandal/text.rs b/source/durandal/text.rs index 173b0b2..c97f15e 100644 --- a/source/durandal/text.rs +++ b/source/durandal/text.rs @@ -1,5 +1,7 @@ //! Text conversion utilities. +use crate::durandal::err::*; + /// Dumps a slice of memory as text to stderr. pub fn dump_mem(b: &[u8]) { @@ -81,16 +83,25 @@ pub fn mac_roman_conv(s: &[u8]) -> String for &c in s.iter() { v.push(match c { - 0 => break, - b'\r' => '\n', - c if c & 0x80 != 0 => TR[usize::from(c) & 0x7F], - c => char::from(c), - }); + c if c & 0x80 != 0 => TR[usize::from(c) & 0x7F], + b'\r' => '\n', + c => char::from(c), + }); } v } +/// Converts a C-style string from Mac Roman to Unicode. +pub fn mac_roman_cstr(s: &[u8]) -> ResultS +{ + if let Some(s) = s.split(|&n| n == 0).nth(0) { + Ok(mac_roman_conv(s)) + } else { + bail!("no null in C string"); + } +} + const TR: [char; 128] = ['\u{00c4}', '\u{00c5}', '\u{00c7}', '\u{00c9}', '\u{00d1}', '\u{00d6}', '\u{00dc}', '\u{00e1}', '\u{00e0}', '\u{00e2}', '\u{00e4}', '\u{00e3}', @@ -139,4 +150,10 @@ fn mac_roman_conv_basic_marathon_stuff() assert_eq!(mac_roman_conv(b"I\xd5ve"), "I’ve"); } +#[test] +fn mac_roman_cstr_tests() +{ + assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0e").unwrap(), "I’ve awaken"); +} + // EOF diff --git a/source/marathon/map.rs b/source/marathon/map.rs index e05cade..13235a1 100644 --- a/source/marathon/map.rs +++ b/source/marathon/map.rs @@ -1,6 +1,6 @@ //! Structures used by Marathon's Map format. -use crate::{durandal::{bin::*, err::*, fixed::*, text::mac_roman_conv}, +use crate::{durandal::{bin::*, err::*, fixed::*, text::*}, marathon::xfer::TransferMode}; use bitflags::bitflags; @@ -55,13 +55,14 @@ pub fn read_minf(b: &[u8]) -> ResultS music_id = u16[4]; missi_flags = u16[6]; envir_flags = u16[8]; - level_name = mac_roman_conv[18..84] no_try; + level_name = mac_roman_cstr[18..84]; entry_flags = u32[84]; } let missi_flags = flag_ok!(MsnFlags, missi_flags)?; let envir_flags = flag_ok!(EnvFlags, envir_flags)?; let entry_flags = flag_ok!(EntFlags, entry_flags)?; + Ok(Minf{env_code, physi_id, music_id, missi_flags, envir_flags, entry_flags, level_name}) } @@ -397,7 +398,7 @@ pub fn read_note(b: &[u8]) -> ResultS<(Note, usize)> 72, BE in b => pos = read_point[2..6]; poly = u16[6]; - text = mac_roman_conv[8..72] no_try; + text = mac_roman_cstr[8..72]; } Ok((Note{pos, poly, text}, 72)) @@ -650,8 +651,6 @@ bitflags! { const TermPause = 1 << 8; const M1Monster = 1 << 9; const M1Weps = 1 << 10; - const NetPlay = 1 << 13; - const Solo = 1 << 14; } } diff --git a/source/marathon/trm.rs b/source/marathon/trm.rs index 795a97d..79e1a64 100644 --- a/source/marathon/trm.rs +++ b/source/marathon/trm.rs @@ -2,7 +2,6 @@ use crate::durandal::{err::*, text::*}; use bitflags::bitflags; -use std::fmt; /// Reads a `Group`. pub fn read_group(b: &[u8], text: &[u8]) -> ResultS @@ -17,7 +16,7 @@ pub fn read_group(b: &[u8], text: &[u8]) -> ResultS lines = u16[10]; } - let text = mac_roman_conv(&text[start..start + size]); + let text = mac_roman_cstr(&text[start..start + size])?; let flags = flag_ok!(GroupFlags, flags)?; let ttype = GroupType::from_repr(ttype)?; @@ -81,32 +80,32 @@ pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)> } /// A terminal definition, with collections of groups and faces. -#[derive(Debug, serde::Serialize)] +#[derive(Debug, PartialEq, serde::Serialize)] pub struct Terminal { - lines: u16, - groups: Vec, - faces: Vec, + pub lines: u16, + pub groups: Vec, + pub faces: Vec, } /// A text face. -#[derive(Debug, serde::Serialize)] +#[derive(Debug, PartialEq, serde::Serialize)] pub struct Face { - start: usize, - face: u16, - color: u16, + pub start: usize, + pub face: u16, + pub color: u16, } /// A terminal command grouping. -#[derive(serde::Serialize)] +#[derive(Debug, PartialEq, serde::Serialize)] pub struct Group { - flags: GroupFlags, - ttype: GroupType, - pdata: i16, - lines: u16, - text: String, + pub flags: GroupFlags, + pub ttype: GroupType, + pub pdata: i16, + pub lines: u16, + pub text: String, } bitflags! { @@ -121,7 +120,7 @@ bitflags! { c_enum! { /// The command of a `Group`. - #[derive(Debug, serde::Serialize)] + #[derive(Debug, PartialEq, serde::Serialize)] pub enum GroupType: u16 { 0 => Logon, @@ -144,18 +143,4 @@ c_enum! { } } -impl fmt::Debug for Group -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - write!(f, "Group{{{:?} {} {}", self.ttype, self.pdata, self.lines)?; - - if !self.text.is_empty() { - write!(f, ";\n{}", self.text)?; - } - - write!(f, "}}") - } -} - // EOF diff --git a/source/marathon/wad.rs b/source/marathon/wad.rs index 5745cfa..b9c4206 100644 --- a/source/marathon/wad.rs +++ b/source/marathon/wad.rs @@ -1,6 +1,6 @@ //! Marathon Wad format handling. -use crate::{durandal::{bin::*, err::*, image, text::mac_roman_conv}, +use crate::{durandal::{bin::*, err::*, image, text::mac_roman_cstr}, marathon::{map, phy, pict, trm}}; use std::collections::BTreeMap; @@ -27,30 +27,30 @@ pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize) let data = &b[beg..end]; chunks.push(match &iden.0 { - b"PICT" => Chunk::Pict(pict::load_pict(data)?), - b"Minf" => Chunk::Minf(map::read_minf(data)?), - b"iidx" => Chunk::Iidx(rd_array(data, map::read_iidx)?), - b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?), - b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?), - b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?), - b"SIDS" => Chunk::Sids(rd_array(data, map_read_sides)?), - b"POLY" => Chunk::Poly(rd_array(data, map_read_polys)?), - b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?), - b"LITE" => Chunk::Lite(rd_array(data, map_read_light)?), - b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?), - b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?), - b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?), - b"medi" => Chunk::Medi(rd_array(data, map::read_medi)?), - b"plat" => Chunk::Plat(rd_array(data, map::read_plat)?), - b"NOTE" => Chunk::Note(rd_array(data, map::read_note)?), - b"term" => Chunk::Term(rd_array(data, trm::read_term)?), - b"FXpx" => Chunk::Fxpx(rd_array(data, phy::read_fxpx)?), - b"MNpx" => Chunk::Mnpx(rd_array(data, phy::read_mnpx)?), - b"PRpx" => Chunk::Prpx(rd_array(data, phy::read_prpx)?), - b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?), - b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?), - _ => Chunk::Data{iden, data: data.to_vec()}, - }); + b"PICT" => Chunk::Pict(pict::load_pict(data)?), + b"Minf" => Chunk::Minf(map::read_minf(data)?), + b"iidx" => Chunk::Iidx(rd_array(data, map::read_iidx)?), + b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?), + b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?), + b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?), + b"SIDS" => Chunk::Sids(rd_array(data, map_read_sides)?), + b"POLY" => Chunk::Poly(rd_array(data, map_read_polys)?), + b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?), + b"LITE" => Chunk::Lite(rd_array(data, map_read_light)?), + b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?), + b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?), + b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?), + b"medi" => Chunk::Medi(rd_array(data, map::read_medi)?), + b"plat" => Chunk::Plat(rd_array(data, map::read_plat)?), + b"NOTE" => Chunk::Note(rd_array(data, map::read_note)?), + b"term" => Chunk::Term(rd_array(data, trm::read_term)?), + b"FXpx" => Chunk::Fxpx(rd_array(data, phy::read_fxpx)?), + b"MNpx" => Chunk::Mnpx(rd_array(data, phy::read_mnpx)?), + b"PRpx" => Chunk::Prpx(rd_array(data, phy::read_prpx)?), + b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?), + b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?), + _ => Chunk::Data{iden, data: data.to_vec()}, + }); p = end; } @@ -104,7 +104,7 @@ pub fn read_wad(b: &[u8]) -> ResultS 128, BE in b => ver_wad = u16[0]; ver_dat = u16[2]; - name = mac_roman_conv[4..68] no_try; + name = mac_roman_cstr[4..68]; siz_app = u16[78] usize; siz_wcnk = u16[80] usize; siz_went = u16[82] usize; diff --git a/source/tycho/main.rs b/source/tycho/main.rs index 07995e3..47e8951 100644 --- a/source/tycho/main.rs +++ b/source/tycho/main.rs @@ -22,21 +22,21 @@ fn mk_draw_area(b: >k::Builder) let im = CairoPixbuf(load_img("/net/greyserv/maraiah/tycho/tycho1")); area.connect_draw(move |area, cr| { - let w = f64::from(area.get_allocated_width()); - let h = f64::from(area.get_allocated_height()); + let w = f64::from(area.get_allocated_width()); + let h = f64::from(area.get_allocated_height()); - ax.set_lower(0.0); - ax.set_upper(w); + ax.set_lower(0.0); + ax.set_upper(w); - ay.set_lower(0.0); - ay.set_upper(h); + ay.set_lower(0.0); + ay.set_upper(h); - let d = CairoDrawArea::new(cr.clone(), w, h); + let d = CairoDrawArea::new(cr.clone(), w, h); - draw_map_none(&d, &im); + draw_map_none(&d, &im); - Inhibit(true) - }); + Inhibit(true) + }); } fn run_app(app: >k::Application)