From: Ian Jackson Date: Wed, 17 Feb 2021 21:38:12 +0000 (+0000) Subject: hidden: Provide create_occultation X-Git-Tag: otter-0.4.0~425 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=30fb7bf0ab09df2a026564c4f1f6552b025b168c;p=otter.git hidden: Provide create_occultation No caller yet. Signed-off-by: Ian Jackson --- diff --git a/daemon/api.rs b/daemon/api.rs index f06ccfc9..ac031feb 100644 --- a/daemon/api.rs +++ b/daemon/api.rs @@ -72,7 +72,8 @@ impl From<&OnlineErrorResponse> for rocket::http::Status { ServerFailure(_) => Status::InternalServerError, NoClient | NoPlayer(_) | GameBeingDestroyed => Status::NotFound, - OnlineError::PieceHeld | OnlineError::PieceGone + OnlineError::PieceHeld | OnlineError::PieceGone | + OnlineError::OverlappingOccultation => Status::Conflict, InvalidZCoord | BadOperation | BadJSON(_) => Status::BadRequest, diff --git a/src/error.rs b/src/error.rs index 336a8cbb..3244cde1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,6 +24,8 @@ pub enum OnlineError { PieceHeld, #[error("improper UI operation")] BadOperation, + #[error("overlapping occultation")] + OverlappingOccultation, } from_instance_lock_error!{OnlineError} diff --git a/src/hidden.rs b/src/hidden.rs index 5dfd82c6..2336f522 100644 --- a/src/hidden.rs +++ b/src/hidden.rs @@ -414,3 +414,108 @@ pub fn recalculate_occultation_piece( } )? } + +#[must_use] +pub struct NascentOccultation(Occultation); + +#[derive(Debug,Copy,Clone)] +pub struct UniformOccultationView( + pub OccultationKind +); +#[derive(Debug,Copy,Clone)] +pub struct OwnerOccultationView { + defview: OccultationKind, + owner: PlayerId, + owner_view: OccultationKind, +} + +pub trait OccultationViewDef { + fn views(self) -> Result; +} +impl OccultationViewDef for UniformOccultationView { + #[throws(IE)] + fn views(self) -> OccultationViews { OccultationViews { + defview: self.0, + views: vec![] + } } +} +impl OccultationViewDef for OwnerOccultationView { + #[throws(IE)] + fn views(self) -> OccultationViews { OccultationViews { + defview: self.defview, + views: vec![OccultView { + players: vec![self.owner], + occult: self.owner_view, + }] + } } +} + +#[throws(OnlineError)] +pub fn create_occultation( + gs: &mut GameState, + ipieces: &PiecesLoaded, + region: Area, + occulter: PieceId, + views: OccultationViews, +) -> Vec<(PieceId, PieceUpdateOps)> { + { + let ogpc = gs.pieces.byid(occulter)?; + if ogpc.occult.active.is_some() { + throw!(internal_logic_error("re-occulting!")) + } + } + + for occ in gs.occults.occults.values() { + if occ.region.overlaps(®ion) { throw!(OE::OverlappingOccultation) } + } + + let mut recalc = vec![]; + for (ppiece, pgpc) in gs.pieces.iter() { + if ! region.contains(pgpc.pos) { continue } + if pgpc.occult.passive.is_some() { throw!(internal_logic_error( + format!("piece {:?} in region, no occulters, but occulted", &pgpc) + )) } + recalc.push(ppiece); + } + + let occultation = Occultation { + region, + occulter, + views, + pieces: default(), + }; + + // Everything from here on must be undone if we get an error + // but we hope not to get one... + + let occid = gs.occults.occults.insert(occultation); + let mut updates = vec![]; + (||{ + let ogpc = gs.pieces.get_mut(occulter).ok_or_else( + ||internal_logic_error("occulter vanished"))?; + ogpc.occult.active = Some(occid); + + for &ppiece in &recalc { + recalculate_occultation_general( + gs, ipieces, ppiece, + (), |_|(), + |_,_,_|(), |puo_pp, ()|{ + updates.push((ppiece, PUOs::PerPlayer(puo_pp))); + }, + )?; + } + + Ok::<_,IE>(()) + })().map_err(|e| { + for &ppiece in &recalc { + let pgpc = gs.pieces.get_mut(ppiece).expect("had ppiece earlier"); + pgpc.occult.passive = None; + } + let ogpc = gs.pieces.get_mut(occulter).expect("had occulter earlier"); + ogpc.occult.active = None; + gs.occults.occults.remove(occid).expect("inserted this earlier"); + e + })?; + + updates +} diff --git a/src/spec.rs b/src/spec.rs index ced7564e..9164b18e 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -323,6 +323,13 @@ pub mod implementation { p.0[i] > self.0[1].0[i] }) } + + pub fn overlaps(&self, other: &AreaC) -> bool where T: Ord { + (0..2).all(|i| !( + other.0[1].0[i] < self.0[0].0[i] || + other.0[0].0[i] > self.0[1].0[i] + )) + } } impl Default for PieceAngle {