From: Ian Jackson Date: Sun, 22 May 2022 11:02:57 +0000 (+0100) Subject: angles: Make not be insane X-Git-Tag: otter-1.1.0~26 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=40d15824279c307e6613acd7c442747da566783f;p=otter.git angles: Make not be insane Signed-off-by: Ian Jackson --- diff --git a/daemon/cmdlistener.rs b/daemon/cmdlistener.rs index fd853d1a..c30840ac 100644 --- a/daemon/cmdlistener.rs +++ b/daemon/cmdlistener.rs @@ -1049,6 +1049,7 @@ fn execute_game_insn<'cs, 'igr, 'ig: 'igr>( .try_into().map_err( |_| SpE::InternalError(format!("implicit item count out of range")) )?; + let angle = angle.resolve()?; let count: Box> = match count { Some(explicit) if implicit == 1 => { Box::new((0..explicit).map(|_| 0)) diff --git a/docs/bundles.rst b/docs/bundles.rst index dafe41aa..396ceb27 100644 --- a/docs/bundles.rst +++ b/docs/bundles.rst @@ -179,6 +179,8 @@ follow the link to the latest published documentation for that format. of library pieces overhauled. ``size`` is now the in-game size, and the SVG size is obtained from the SVG. Library catalogues must be overhauled. + - Handling of the ``angle`` parameter in game specs is now + much more sensible, and also accurately documented. * - ``1`` - 0.x - `1.0.0 `_ diff --git a/docs/gamespec.rst b/docs/gamespec.rst index 34f047da..d1f13bdc 100644 --- a/docs/gamespec.rst +++ b/docs/gamespec.rst @@ -109,10 +109,9 @@ These apply regardless of the value of ``type``. pin and unpin pieces during the game; this is the initial state. [boolean] - * ``angle``: Initial orientation of the piece. The - specified value is multiplied by 45 degrees, increasing values - rotating anticlockwise. So for example ``6`` would mean to rotate - 90 degrees clockwise. [integer 0..7] + * ``angle``: Initial orientation of the piece. Only 45-degree + angles are supported. + [number, degrees, clockwise; or string, "N", "NE" etc.] Common parameters diff --git a/specs/demo.game.toml b/specs/demo.game.toml index 739497e1..8956302d 100644 --- a/specs/demo.game.toml +++ b/specs/demo.game.toml @@ -16,7 +16,7 @@ edges = ["black","white"] pos = [90, 20] type = "Rect" size = [10] -angle.Compass = 1 +angle = "SW" faces = ["blue", "grey"] [[pieces]] @@ -28,7 +28,7 @@ item = "chess-w-B" [[pieces]] pos = [160,40] type = "Lib" -angle.Compass = 1 +angle = "NE" lib = "wikimedia" item = "chess-b-N" @@ -36,7 +36,7 @@ item = "chess-b-N" pos = [120, 30] type = "Rect" size = [10] -angle.Compass = 1 +angle = 45 faces = [ ] edges = ["yellow", "orange"] edge_width = 0.5 diff --git a/src/imports.rs b/src/imports.rs index 0a3dfc0b..10baa440 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -103,7 +103,7 @@ pub use crate::shapelib; pub use crate::shapelib::{ItemEnquiryData, LibraryEnquiryData}; pub use crate::shapelib::{LibraryLoadError}; pub use crate::spec::*; -pub use crate::spec::imp::ColourSpecExt as _; +pub use crate::spec::imp::{ColourSpecExt as _, OptionPieceAngleSpecExt as _}; pub use crate::spec::piece_specs::{FaceColourSpecs, SimpleCommon}; pub use crate::updates::*; pub use crate::utils::*; diff --git a/src/spec.rs b/src/spec.rs index 7634c5cd..7ba438cc 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -225,11 +225,18 @@ pub struct PiecesSpec { pub count: Option, pub face: Option, pub pinned: Option, - #[serde(default)] pub angle: PieceAngle, + #[serde(default)] pub angle: Option, #[serde(flatten)] pub info: Box, } +#[derive(Debug,Clone,Serialize,Deserialize)] +#[serde(untagged)] +pub enum PieceAngleSpec { + Compass(String), + Degrees(i32), +} + #[derive(Debug,Copy,Clone,Serialize,Deserialize)] pub enum PieceAngle { Compass(CompassAngle), @@ -653,6 +660,30 @@ pub mod imp { } } + #[ext(pub)] + impl Option { + #[throws(SpecError)] + fn resolve(&self) -> PieceAngle { + use PieceAngleSpec as PAS; + let i = match self { + None => return default(), + Some(PAS::Compass(s)) => { + let (i,_) = [ + "N" , "NE", "E" , "SE", "S" , "SW", "W" , "NW", + ].iter().enumerate().find(|(_i,&exp)| s == exp) + .ok_or_else(|| SpE::CompassAngleInvalid)?; + i as u8 + }, + Some(PAS::Degrees(deg)) => { + let deg = deg.rem_euclid(360); + if deg % 45 != 0 { throw!(SpE::CompassAngleInvalid) } + (deg / 45) as u8 + }, + }; + PieceAngle::Compass(i.try_into()?) + } + } + impl UrlSpec { const MAX_LEN: usize = 200; }