chiark / gitweb /
hidden: Provide create_occultation
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 17 Feb 2021 21:38:12 +0000 (21:38 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 17 Feb 2021 21:38:12 +0000 (21:38 +0000)
No caller yet.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/api.rs
src/error.rs
src/hidden.rs
src/spec.rs

index f06ccfc958b9d86c40172e31c144ff19da3d198c..ac031feb6cb758b464490f0098e1b5015e5efda9 100644 (file)
@@ -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,
index 336a8cbb35b9cff47d6832b492d71585c9685225..3244cde12a0b29488774dbd9ddc552ef86d40a6c 100644 (file)
@@ -24,6 +24,8 @@ pub enum OnlineError {
   PieceHeld,
   #[error("improper UI operation")]
   BadOperation,
+  #[error("overlapping occultation")]
+  OverlappingOccultation,
 }
 from_instance_lock_error!{OnlineError}
 
index 5dfd82c6badf8423a8a82339960fe988a4aab766..2336f522e48c944ea1504d8493203c0034b647e2 100644 (file)
@@ -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<OccultationViews, IE>;
+}
+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<V: OccultationViewDef>(
+  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(&region) { 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
+}
index ced7564ef4adc9c56e48af7e15ee1e565cb803fc..9164b18e660bb55b4990f4aa4b72e6e994af7151 100644 (file)
@@ -323,6 +323,13 @@ pub mod implementation {
         p.0[i] > self.0[1].0[i]
       })
     }
+
+    pub fn overlaps(&self, other: &AreaC<T>) -> 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 {