From: Ian Jackson Date: Wed, 17 Feb 2021 00:36:58 +0000 (+0000) Subject: Move magic into own module, so it can inerit from hidden X-Git-Tag: otter-0.4.0~430 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=1b06e8763557d38d3dfcc7cf34fa8bba8c295a73;p=otter.git Move magic into own module, so it can inerit from hidden Signed-off-by: Ian Jackson --- diff --git a/src/hidden.rs b/src/hidden.rs index b2db9da7..3a1e9aab 100644 --- a/src/hidden.rs +++ b/src/hidden.rs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // There is NO WARRANTY. +#[path="magic.rs"] +mod magic; + use crate::prelude::*; use slotmap::secondary; diff --git a/src/magic.rs b/src/magic.rs new file mode 100644 index 00000000..cfeb8748 --- /dev/null +++ b/src/magic.rs @@ -0,0 +1,172 @@ +// Copyright 2020-2021 Ian Jackson and contributors to Otter +// SPDX-License-Identifier: AGPL-3.0-or-later +// There is NO WARRANTY. + +// This is otter::hidden::magic + +use crate::prelude::*; +//use super::*; + +#[derive(Debug,Clone,Serialize,Deserialize)] +struct MagicOwner { + player: PlayerId, + desc: Html, + dasharray: Html, +} + +#[derive(Debug,Serialize,Deserialize)] +struct Hand { + shape: SimpleShape, +} + +#[derive(Debug,Clone,Default,Serialize,Deserialize)] +struct HandState { + owner: Option, +} + +#[typetag::serde(name="Hand")] +impl PieceXData for HandState { } + +#[typetag::serde] +impl Outline for Hand { + delegate!{ + to self.shape { + fn surround_path(&self, _pri: &PieceRenderInstructions) + -> Result; + fn thresh_dragraise(&self, _pri: &PieceRenderInstructions) + -> Result,IE>; + fn bbox_approx(&self) -> [Pos;2]; + } + } +} + +#[typetag::serde] +impl PieceSpec for piece_specs::Hand { + #[throws(SpecError)] + fn load(&self, _: usize) -> Box { + let (mut shape, common) = self.shape.load_raw()?; + if common.itemname.is_some() { + throw!(SpecError::ItemnameSpecifiedWhereForbidden); + } + if shape.nfaces() != 1 { + throw!(SpecError::MultifacetedMagic); + } + shape.itemname = "magic-hand".to_string(); + Box::new(Hand { + shape, + }) as Box + } +} + +impl Hand { + fn describe_html_inner(&self, xdata: Option<&HandState>) -> Html { + if_chain! { + if let Some(xdata) = xdata; + if let Some(owner) = &xdata.owner; + then { owner.desc.clone() } + else { Html(format!("a hand repository")) } + } + } +} + +#[typetag::serde] +impl Piece for Hand { + fn nfaces(&self) -> RawFaceId { 1 } + #[throws(IE)] + fn svg_piece(&self, f: &mut Html, gpc: &PieceState, + pri: &PieceRenderInstructions) { + self.shape.svg_piece_raw(f, pri, &mut |f: &mut String| { + if_chain!{ + if let Some(xdata) = gpc.xdata.get::()?; + if let Some(owned) = &xdata.owner; + then { write!(f, r##" stroke-dasharray="{}" "##, + &owned.dasharray.0)?; } + } + Ok(()) + })?; + } + + #[throws(IE)] + fn describe_html(&self, _face: Option, gpc: &PieceState) -> Html { + let xdata = gpc.xdata.get()?; + self.describe_html_inner(xdata) + } + + delegate!{ + to self.shape { + fn itemname(&self) -> &str; + } + } + + #[throws(InternalError)] + fn add_ui_operations(&self, upd: &mut Vec, + gpc: &PieceState) { + upd.push(if_chain! { + if let Some(xdata) = gpc.xdata.get::()?; + if let Some(_owner) = &xdata.owner; + then { UoDescription { + kind: UoKind:: Piece, + def_key: 'C', + opname: "deactivate".to_owned(), + desc: Html::lit("Deactivate hand"), + wrc: WRC::Unpredictable, + }} + else { UoDescription { + kind: UoKind:: Piece, + def_key: 'C', + opname: "claim".to_owned(), + desc: Html::lit("Claim this as your hand"), + wrc: WRC::Unpredictable, + }} + }) + } + + fn ui_operation(&self, gs: &mut GameState, player: PlayerId, + piece: PieceId, opname: &str, wrc: WhatResponseToClientOp) + -> PieceUpdateResult { + let gplayers = &mut gs.players; + let gpc = gs.pieces.byid_mut(piece)?; + let xdata = gpc.xdata.get_mut::() + .map_err(|e| APOE::ReportViaResponse(e.into()))?; + let old_desc = self.describe_html_inner(Some(xdata)); + + let dasharray = player_dasharray(gplayers, player); + let gpl = gplayers.byid_mut(player)?; + let _occults = &mut gs.occults; + + let did; + match (opname, xdata.owner.is_some()) { + ("claim", false) => { + let nick = Html(htmlescape::encode_minimal(&gpl.nick)); + let new_desc = Html(format!("{}'s hand", &nick.0)); + xdata.owner = Some(MagicOwner { + player, + dasharray, + desc: new_desc, + }); + // xxx recalculate occultations + did = format!("claimed {}", &old_desc.0); + } + ("deactivate", true) => { + xdata.owner = None; + // xxx recalculate occultations + did = format!("deactivated {}", &old_desc.0); + } + ("claim", true) | + ("deactivate", false) => { + throw!(OE::PieceHeld); + } + _ => { + throw!(OE::BadOperation); + } + } + + let who_by = Html(htmlescape::encode_minimal(&gpl.nick)); + let log = vec![ LogEntry { html: Html(format!("{} {}", who_by.0, did)) }]; + Ok(PieceUpdate { + wrc, log, + ops: PUOs::Simple(PUO::Modify(())), // xxx + // xxx want PUU::RecalculateOccultations + }) + } +} diff --git a/src/pieces.rs b/src/pieces.rs index b5ccd816..e0d9bc6a 100644 --- a/src/pieces.rs +++ b/src/pieces.rs @@ -13,13 +13,13 @@ type ColourMap = IndexVec; #[derive(Debug,Serialize,Deserialize)] // todo: this serialisation is rather large pub struct SimpleShape { - desc: Html, - path: Html, + pub desc: Html, + pub path: Html, colours: ColourMap, - #[serde(default)] edges: ColourMap, - #[serde(default="default_edge_width")] edge_width: f64, - itemname: String, - outline: Box, + #[serde(default)] pub edges: ColourMap, + #[serde(default="default_edge_width")] pub edge_width: f64, + pub itemname: String, + pub outline: Box, } pub const SELECT_SCALE: f64 = 1.1; @@ -192,7 +192,7 @@ impl SimpleShape { } #[throws(IE)] - fn svg_piece_raw( + pub fn svg_piece_raw( &self, f: &mut Html, pri: &PieceRenderInstructions, stroke_attrs_hook: &mut dyn FnMut(&mut String) -> Result<(),IE>, ) { @@ -282,167 +282,3 @@ impl PieceSpec for piece_specs::Square { #[throws(SpecError)] fn load(&self, _: usize) -> Box { SimplePieceSpec::load(self)? } } - -#[derive(Debug,Clone,Serialize,Deserialize)] -struct MagicOwner { - player: PlayerId, - desc: Html, - dasharray: Html, -} - -#[derive(Debug,Serialize,Deserialize)] -struct Hand { - shape: SimpleShape, -} - -#[derive(Debug,Clone,Default,Serialize,Deserialize)] -struct HandState { - owner: Option, -} - -#[typetag::serde(name="Hand")] -impl PieceXData for HandState { } - -#[typetag::serde] -impl Outline for Hand { - delegate!{ - to self.shape { - fn surround_path(&self, _pri: &PieceRenderInstructions) - -> Result; - fn thresh_dragraise(&self, _pri: &PieceRenderInstructions) - -> Result,IE>; - fn bbox_approx(&self) -> [Pos;2]; - } - } -} - -#[typetag::serde] -impl PieceSpec for piece_specs::Hand { - #[throws(SpecError)] - fn load(&self, _: usize) -> Box { - let (mut shape, common) = self.shape.load_raw()?; - if common.itemname.is_some() { - throw!(SpecError::ItemnameSpecifiedWhereForbidden); - } - if shape.nfaces() != 1 { - throw!(SpecError::MultifacetedMagic); - } - shape.itemname = "magic-hand".to_string(); - Box::new(Hand { - shape, - }) as Box - } -} - -impl Hand { - fn describe_html_inner(&self, xdata: Option<&HandState>) -> Html { - if_chain! { - if let Some(xdata) = xdata; - if let Some(owner) = &xdata.owner; - then { owner.desc.clone() } - else { Html(format!("a hand repository")) } - } - } -} - -#[typetag::serde] -impl Piece for Hand { - fn nfaces(&self) -> RawFaceId { 1 } - #[throws(IE)] - fn svg_piece(&self, f: &mut Html, gpc: &PieceState, - pri: &PieceRenderInstructions) { - self.shape.svg_piece_raw(f, pri, &mut |f: &mut String| { - if_chain!{ - if let Some(xdata) = gpc.xdata.get::()?; - if let Some(owned) = &xdata.owner; - then { write!(f, r##" stroke-dasharray="{}" "##, - &owned.dasharray.0)?; } - } - Ok(()) - })?; - } - - #[throws(IE)] - fn describe_html(&self, _face: Option, gpc: &PieceState) -> Html { - let xdata = gpc.xdata.get()?; - self.describe_html_inner(xdata) - } - - delegate!{ - to self.shape { - fn itemname(&self) -> &str; - } - } - - #[throws(InternalError)] - fn add_ui_operations(&self, upd: &mut Vec, - gpc: &PieceState) { - upd.push(if_chain! { - if let Some(xdata) = gpc.xdata.get::()?; - if let Some(_owner) = &xdata.owner; - then { UoDescription { - kind: UoKind:: Piece, - def_key: 'C', - opname: "deactivate".to_owned(), - desc: Html::lit("Deactivate hand"), - wrc: WRC::Unpredictable, - }} - else { UoDescription { - kind: UoKind:: Piece, - def_key: 'C', - opname: "claim".to_owned(), - desc: Html::lit("Claim this as your hand"), - wrc: WRC::Unpredictable, - }} - }) - } - - fn ui_operation(&self, gs: &mut GameState, player: PlayerId, - piece: PieceId, opname: &str, wrc: WhatResponseToClientOp) - -> PieceUpdateResult { - let gplayers = &mut gs.players; - let gpc = gs.pieces.byid_mut(piece)?; - let xdata = gpc.xdata.get_mut::() - .map_err(|e| APOE::ReportViaResponse(e.into()))?; - let old_desc = self.describe_html_inner(Some(xdata)); - - let dasharray = player_dasharray(gplayers, player); - let gpl = gplayers.byid_mut(player)?; - let _occults = &mut gs.occults; - - let did; - match (opname, xdata.owner.is_some()) { - ("claim", false) => { - let nick = Html(htmlescape::encode_minimal(&gpl.nick)); - let new_desc = Html(format!("{}'s hand", &nick.0)); - xdata.owner = Some(MagicOwner { - player, - dasharray, - desc: new_desc, - }); - // xxx recalculate occultations - did = format!("claimed {}", &old_desc.0); - } - ("deactivate", true) => { - xdata.owner = None; - // xxx recalculate occultations - did = format!("deactivated {}", &old_desc.0); - } - ("claim", true) | - ("deactivate", false) => { - throw!(OE::PieceHeld); - } - _ => { - throw!(OE::BadOperation); - } - } - - let who_by = Html(htmlescape::encode_minimal(&gpl.nick)); - let log = vec![ LogEntry { html: Html(format!("{} {}", who_by.0, did)) }]; - Ok(PieceUpdate { - wrc, log, - ops: PUOs::Simple(PUO::Modify(())), // xxx - // xxx want PUU::RecalculateOccultations - }) - } -}