{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances #-}
module DBData
(Reference,
toUID,
CreatureRef,
PlaneRef,
ToolRef,
TheUniverse(..),
the_universe,
(=:=),
GenericReference(..),
locationsOf,
ReferenceType(..),
LocationType(..),
Location,
Position(..),
Standing(..),
Dropped(..),
Inventory(..),
Wielded(..),
_nullary,
_creature,
_tool,
_plane,
_standing,
_dropped,
_inventory,
_wielded,
_position,
_facing,
_the_universe,
asLocationTyped,
DBPrivate.S,
location,
entity,
coerceReferenceTyped,
isReferenceTyped,
coerceLocationTyped,
isLocationTyped,
coerceEntityTyped,
isEntityTyped,
coerceLocationRecord,
coerceLocation,
coerceEntity,
getLocation,
getEntity,
generalizeLocation,
generalizeEntity,
generalizeLocationRecord,
toStanding,
toDropped,
toInventory,
toWielded,
returnToInventory)
where
import Facing
import DBPrivate
import ToolData
import CreatureData
import PlaneData
import Data.Maybe
import Control.Monad
import Position
--
-- Type Instances
--
newtype Type a = Type a
_nullary :: Type (Reference ())
_nullary = Type $ error "_nullary: undefined"
_creature :: Type CreatureRef
_creature = Type $ error "_creature: undefined"
_tool :: Type ToolRef
_tool = Type $ error "_tool: undefined"
_plane :: Type PlaneRef
_plane = Type $ error "_plane: undefined"
_standing :: Type Standing
_standing = Type $ error "_standing: undefined"
_dropped :: Type Dropped
_dropped = Type $ error "_dropped: undefined"
_inventory :: Type Inventory
_inventory = Type $ error "_inventory: undefined"
_wielded :: Type Wielded
_wielded = Type $ error "_wielded: undefined"
_position :: Type Position
_position = Type $ error "_position: undefined"
_facing :: Type Facing
_facing = Type $ error "_facing: undefined"
_the_universe :: Type (Reference TheUniverse)
_the_universe = Type $ error "_the_universe: undefined"
--
-- Getting References generically.
--
class GenericReference a m | a -> m where
fromLocation :: (ReferenceType x) => Location m (Reference x) b -> Maybe a
generalizeReference :: a -> Reference ()
instance (ReferenceType a) => GenericReference (Reference a) m where
fromLocation = coerceReference . entity
generalizeReference = unsafeReference
instance (LocationType a,LocationType b) => GenericReference (Location m a b) m where
fromLocation = coerceLocationRecord
generalizeReference = getEntity
locationsOf :: (Monad m,LocationType a) => m [Location S (Reference ()) a] -> m [a]
locationsOf = liftM (map location)
--
-- Reference Equality
--
(=:=) :: (GenericReference a m,GenericReference b n) => a -> b -> Bool
a =:= b = generalizeReference a == generalizeReference b
--
-- References
--
the_universe :: Reference TheUniverse
the_universe = UniverseRef
coerceReferenceTyped :: (ReferenceType a) => Type (Reference a) -> Reference x -> Maybe (Reference a)
coerceReferenceTyped = const coerceReference
isReferenceTyped :: (ReferenceType a) => Type (Reference a) -> Reference x -> Bool
isReferenceTyped a = isJust . coerceReferenceTyped a
class ReferenceType a where
coerceReference :: Reference x -> Maybe (Reference a)
instance ReferenceType () where
coerceReference = Just . unsafeReference
instance ReferenceType Plane where
coerceReference (PlaneRef ref) = Just $ PlaneRef ref
coerceReference _ = Nothing
instance ReferenceType Tool where
coerceReference (ToolRef ref) = Just $ ToolRef ref
coerceReference _ = Nothing
instance ReferenceType Creature where
coerceReference (CreatureRef ref) = Just $ CreatureRef ref
coerceReference _ = Nothing
instance ReferenceType TheUniverse where
coerceReference UniverseRef = Just UniverseRef
coerceReference _ = Nothing
--
-- Locations
--
generalizeLocationRecord :: Location m e t -> Location m (Reference ()) ()
generalizeLocationRecord = unsafeLocation
generalizeLocation :: Location m e t -> Location m e ()
generalizeLocation = unsafeLocation
generalizeEntity :: Location m e t -> Location m (Reference ()) t
generalizeEntity = unsafeLocation
getLocation :: Location m e t -> Reference ()
getLocation (IsStanding _ s) = unsafeReference $ standing_plane s
getLocation (IsDropped _ d) = unsafeReference $ dropped_plane d
getLocation (InInventory _ c) = unsafeReference $ inventory_creature c
getLocation (IsWielded _ c) = unsafeReference $ wielded_creature c
getLocation (InTheUniverse _) = unsafeReference UniverseRef
getEntity :: Location m e t -> Reference ()
getEntity (IsStanding r _) = unsafeReference r
getEntity (IsDropped r _) = unsafeReference r
getEntity (InInventory r _) = unsafeReference r
getEntity (IsWielded r _) = unsafeReference r
getEntity (InTheUniverse r) = unsafeReference r
asLocationTyped :: (LocationType e,LocationType t) => Type e -> Type t -> Location m e t -> Location m e t
asLocationTyped _ _ = id
coerceLocationTyped :: (LocationType e,LocationType t) => Type t -> Location m e x -> Maybe (Location m e t)
coerceLocationTyped = const coerceLocation
isLocationTyped :: (LocationType e,LocationType t) => Type t -> Location m e x -> Bool
isLocationTyped t = isJust . coerceLocationTyped t
coerceEntityTyped :: (LocationType e,LocationType t) => Type e -> Location m x t -> Maybe (Location m e t)
coerceEntityTyped = const coerceEntity
isEntityTyped :: (LocationType e,LocationType t) => Type e -> Location m x t -> Bool
isEntityTyped t = isJust . coerceEntityTyped t
coerceLocation :: (LocationType e,LocationType t) => Location m e x -> Maybe (Location m e t)
coerceLocation = coerceLocationRecord
coerceEntity :: (LocationType e,LocationType t) => Location m x t -> Maybe (Location m e t)
coerceEntity = coerceLocationRecord
coerceLocationRecord :: (LocationType e,LocationType t) => Location m x y -> Maybe (Location m e t)
coerceLocationRecord = fmap fst . coerceUnify
where coerceUnify :: (LocationType e,LocationType t) =>
Location m x y -> Maybe (Location m e t,(e,t))
coerceUnify l = do t <- extractLocation l
e <- extractEntity l
return (unsafeLocation l,(e,t))
location :: (LocationType t) => Location m e t -> t
location l = fromMaybe (error "location: type error") $ extractLocation l
entity :: (LocationType e) => Location m e t -> e
entity l = fromMaybe (error "entity: type error") $ extractEntity l
class (Eq a,Ord a) => LocationType a where
extractLocation :: Location m e t -> Maybe a
extractEntity :: Location m e t -> Maybe a
instance LocationType Standing where
extractLocation (IsStanding _ s) = Just s
extractLocation _ = Nothing
extractEntity = const Nothing
instance LocationType Dropped where
extractLocation (IsDropped _ d) = Just d
extractLocation _ = Nothing
extractEntity = const Nothing
instance LocationType Inventory where
extractLocation (InInventory _ i) = Just i
extractLocation _ = Nothing
extractEntity = const Nothing
instance LocationType Wielded where
extractLocation (IsWielded _ i) = Just i
extractLocation _ = Nothing
extractEntity = const Nothing
instance LocationType () where
extractLocation = const $ Just ()
extractEntity = const Nothing
instance LocationType Position where
extractLocation (IsStanding _ s) = Just $ standing_position s
extractLocation (IsDropped _ d) = Just $ dropped_position d
extractLocation (InInventory {}) = Nothing
extractLocation (IsWielded {}) = Nothing
extractLocation (InTheUniverse {}) = Nothing
extractEntity = const Nothing
instance LocationType Facing where
extractLocation (IsStanding _ s) = Just $ standing_facing s
extractLocation (IsDropped {}) = Nothing
extractLocation (InInventory {}) = Nothing
extractLocation (IsWielded {}) = Nothing
extractLocation (InTheUniverse {}) = Nothing
extractEntity = const Nothing
instance ReferenceType a => LocationType (Reference a) where
extractLocation = coerceReference . getLocation
extractEntity = coerceReference . getEntity
instance (LocationType a,LocationType b) => LocationType (a,b) where
extractLocation l = liftM2 (,) (extractLocation l) (extractLocation l)
extractEntity l = liftM2 (,) (extractEntity l) (extractEntity l)
--
-- Manipulating Locations
--
toStanding :: (LocationType t) => Standing -> Location m CreatureRef t -> Location m CreatureRef Standing
toStanding s l | isEntityTyped _creature l = IsStanding (entity l) s
toStanding _ _ = error "toStanding: type error"
toDropped :: (LocationType t) => Dropped -> Location m ToolRef t -> Location m ToolRef Dropped
toDropped d l | isEntityTyped _tool l = IsDropped (entity l) d
toDropped _ _ = error "toDropped: type error"
toInventory :: (LocationType t) => Inventory -> Location m ToolRef t -> Location m ToolRef Inventory
toInventory i l | isEntityTyped _tool l = InInventory (entity l) i
toInventory _ _ = error "toInventory: type error"
toWielded :: (LocationType t) => Wielded -> Location m ToolRef t -> Location m ToolRef Wielded
toWielded i l | isEntityTyped _tool l = IsWielded (entity l) i
toWielded _ _ = error "toWielded: type error"
returnToInventory :: Location m ToolRef Wielded -> Location m ToolRef Inventory
returnToInventory l = InInventory (entity l) (Inventory c)
where Wielded c = location l