use slotmap::secondary;
+type OccK = OccultationKind;
+
+visible_slotmap_key!{ OccId(b'H') }
+
// ========== data structures ==========
#[derive(Clone,Debug,Default,Serialize,Deserialize)]
pub struct GameOccults {
- // todo
+ occults: DenseSlotMap<OccId, Occultation>,
}
#[derive(Clone,Debug,Default,Serialize,Deserialize)]
+// kept in synch with Occultation::pieces
pub struct PieceOccult {
- // todo
+ active: Option<OccId>, // kept in synch with Occultation::occulter
+ passive: Option<OccId>, // kept in synch with Occultation::pieces
+}
+
+#[derive(Clone,Debug,Serialize,Deserialize)]
+pub struct Occultation {
+ region: [Pos; 2], // automatically affect pieces here
+ occulter: PieceId, // kept in synch with PieceOccult::active
+ views: Vec<OccultView>,
+ defview: Option<OccultationKind>,
+ pieces: BTreeSet<PieceId>, // kept in synch with PieceOccult::passive
+}
+
+#[derive(Clone,Debug,Serialize,Deserialize)]
+pub struct OccultView {
+ players: Vec<PlayerId>,
+ occult: Option<OccultationKind>,
+}
+
+#[derive(Clone,Copy,Debug,Serialize,Deserialize)]
+#[derive(Eq,PartialEq)]
+pub enum OccultationKind {
+ Scrambled,
+ Displaced { within: Area },
+ Invisible,
+}
+
+impl PartialOrd for OccultationKind {
+ fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
+ fn level(k: &OccK) -> u8 { use OccultationKind::*; match k {
+ Scrambled => 0,
+ Displaced{..} => 1,
+ Invisible => 2,
+ } }
+
+ level(self).partial_cmp(&level(rhs))
+ }
+}
+
+trait OccOptExt {
+ fn at_all_visible(&self) -> bool;
+}
+
+impl OccOptExt for Option<OccultationKind> {
+ fn at_all_visible(&self) -> bool {
+ match self {
+ None |
+ Some(OccK::Scrambled) |
+ Some(OccK::Displaced { .. })
+ => false,
+ Some(OccK::Invisible)
+ => true,
+ }
+ }
+}
+
+impl Occultation {
+ pub fn get_kind(&self, player: PlayerId) -> Option<&OccultationKind> {
+ let kind = self.views.iter().find_map(|view| {
+ if view.players.contains(&player) { return Some(view.occult.as_ref()); }
+ None
+ }).unwrap_or(
+ self.defview.as_ref()
+ );
+ kind
+ }
+}
+
+impl GameOccults {
+ #[throws(IE)]
+ fn by_id(&self, occid: OccId) -> &Occultation {
+ self.occults.get(occid).ok_or_else(
+ || internal_logic_error("piece missing"))?
+ }
+
+ #[throws(IE)]
+ pub fn get_kind(&self, occid: OccId, player: PlayerId)
+ -> Option<&OccultationKind> {
+ let occ = self.by_id(occid)?;
+ let kind = occ.get_kind(player);
+ kind
+ }
}
// ========== PerPlayerIdMap ==========
-#[derive(Default,Debug,Clone,Serialize,Deserialize)]
+#[derive(Clone,Debug,Default,Serialize,Deserialize)]
pub struct PerPlayerIdMap {
f: SecondarySlotMap<PieceId, VisiblePieceId>,
r: DenseSlotMap<VisiblePieceId, PieceId>,