chiark / gitweb /
Prevent occultation by rotated pieces
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 7 Apr 2021 18:19:57 +0000 (19:19 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 7 Apr 2021 18:38:48 +0000 (19:38 +0100)
* Add a OcculterRotationChecked proof token to create_occultation
* Make a function to get the proof token from the GPiece
* In ui_operation (do the thing) functions, check it and plumb it through
* In the load functions, set rotateable to false

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

index 260207972a6b79b7d1d86e271a102a4831c66869..505bd5226eca328bc57ccd81788849715ffbe7bd 100644 (file)
@@ -59,6 +59,7 @@ impl PieceSpec for piece_specs::Deck {
       throw!(SpE::WrongNumberOfFaces);
     }
     gpc.moveable = PieceMoveable::IfWresting;
+    gpc.rotateable = false;
     let p = Box::new(Deck {
       shape,
       label: self.label.load()?,
@@ -161,7 +162,7 @@ impl PieceTrait for Deck {
   }
 
   #[throws(ApiPieceOpError)]
-  fn ui_operation(&self, _: ShowUnocculted,
+  fn ui_operation(&self, vis: ShowUnocculted,
                   a: ApiPieceOpArgs<'_>,
                   opname: &str, wrc: WhatResponseToClientOp)
                   -> UpdateFromOpComplex {
@@ -177,7 +178,8 @@ impl PieceTrait for Deck {
     let nick = gpl.nick.to_html();
 
     dbgc!("ui op k entry", &opname);
-    
+
+    let rot_checked = gpc.occulter_check_unrotated(vis)?;
     let old_state = self.state(gpc, &goccults)?;
   
     let (new_state, did) = match opname {
@@ -222,7 +224,7 @@ impl PieceTrait for Deck {
       xupdates.extend(
         create_occultation(&mut gen.unique_gen(), &mut gs.max_z,
                            gplayers, gpieces, goccults, ipieces, ioccults,
-                           to_recalculate,
+                           to_recalculate, rot_checked,
                            region, piece, views)?
       );
       dbgc!("creating occ done", &xupdates);
index 784465b868b6b12ddd612213b99148c77eaa26d3..c515b3708234e4a95aea9c12a7e8b8c2f429e99f 100644 (file)
@@ -181,6 +181,7 @@ pub enum PieceOpError {
   PieceGone,
   Occultation,
   PieceUnrotateable,
+  OcculterAlreadyRotated,
   OrganisedPlacementOverfull,
 }
 display_as_debug!{PieceOpError}
index e09b1173b3a084e24c612f95ffb14b2b3d94d57b..2b10686afa6d8057b4c9ad04689da179c830dec9 100644 (file)
@@ -123,6 +123,7 @@ impl PieceSpec for piece_specs::Hand {
           _pcaliases: &PieceAliases, _ir: &InstanceRef)
           -> PieceSpecLoaded {
     gpc.moveable = PieceMoveable::IfWresting;
+    gpc.rotateable = false;
     self.c.load(Behaviour::Hand)?
   }
 }
@@ -217,7 +218,7 @@ impl PieceTrait for Hand {
   }
 
   #[throws(ApiPieceOpError)]
-  fn ui_operation(&self, _: ShowUnocculted, mut a: ApiPieceOpArgs<'_>,
+  fn ui_operation(&self, vis: ShowUnocculted, mut a: ApiPieceOpArgs<'_>,
                   opname: &str, wrc: WhatResponseToClientOp)
                   -> UpdateFromOpComplex {
     if let Some(r) = {
@@ -237,6 +238,7 @@ impl PieceTrait for Hand {
 
     let goccults = &mut gs.occults;
     let gpc = gpieces.byid_mut(piece)?;
+    let rot_checked = gpc.occulter_check_unrotated(vis);
     let xdata = gpc.xdata.get_mut::<HandState,_>(default)?;
     let old_desc = self.behaviour.describe_html_inner(Some(xdata));
     let old_player = xdata.player();
@@ -261,6 +263,7 @@ impl PieceTrait for Hand {
         let xupdates = match self.behaviour.views() {
           None => default(),
           Some((mk_owner, mk_defview)) => {
+            let rot_checked = rot_checked?;
             let (region, views) = (||{
               dbgc!("claiming region");
               let rect   = self.shape.outline.rect  (gpc.pos)?;
@@ -281,7 +284,7 @@ impl PieceTrait for Hand {
               create_occultation(&mut gen.unique_gen(), &mut gs.max_z,
                                  gplayers, gpieces, goccults,
                                  ipieces, ioccults,
-                                 to_recalculate,
+                                 to_recalculate, rot_checked,
                                  region, piece, views)?;
             xupdates
           }
index 74397d3e2211e9218652315d370220fca88496ef..01a0227d5aaadb0fb6588c0ed77d7ef1629e1f44 100644 (file)
@@ -19,6 +19,9 @@ visible_slotmap_key!{ OccId(b'H') }
 #[derive(Copy,Clone,Debug)]
 pub struct ShowUnocculted(());
 
+#[derive(Copy,Clone,Debug)]
+pub struct OcculterRotationChecked(());
+
 #[derive(Debug,Serialize,Deserialize)]
 #[serde(transparent)]
 pub struct IPieceTraitObj(Box<dyn PieceTrait>);
@@ -414,6 +417,13 @@ impl GPiece {
     }
   }
 
+  pub fn occulter_check_unrotated(&self, _:ShowUnocculted)
+      -> Result<OcculterRotationChecked, PieceOpError> {
+    if self.angle.is_rotated() { Err(POE::OcculterAlreadyRotated) }
+    else { Ok(OcculterRotationChecked(())) }
+  }
+
+
   pub fn fully_visible_to(&self, goccults: &GameOccults, player: PlayerId)
                           -> Option<ShowUnocculted>
   {
@@ -871,6 +881,7 @@ pub fn create_occultation(
   ipieces: &IPieces,
   ioccults: &IOccults,
   to_recalculate: &mut ToRecalculate,
+  _: OcculterRotationChecked,
   region: Region,
   occulter: PieceId,
   views: OccultationViews,