EtaMOO-0.2.0.0: src/MOO/Builtins/Objects.hs
{-# LANGUAGE OverloadedStrings #-}
module MOO.Builtins.Objects ( builtins ) where
import Control.Concurrent.STM (STM, TVar, newTVar, readTVar, writeTVar)
import Control.Monad (when, unless, liftM, void, forM_, foldM, join)
import Data.Maybe (isJust, isNothing, fromJust)
import Data.Set (Set)
import Data.Text (Text)
import Prelude hiding (getContents)
import qualified Data.HashMap.Strict as HM
import qualified Data.IntSet as IS
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Vector as V
import MOO.AST
import MOO.Builtins.Common
import {-# SOURCE #-} MOO.Compiler
import MOO.Connection
import MOO.Database
import MOO.Object
import MOO.Parser
import MOO.Task
import MOO.Types
import MOO.Unparser
import MOO.Verb
import qualified MOO.String as Str
{-# ANN module ("HLint: ignore Use camelCase" :: String) #-}
-- | § 4.4.3 Manipulating Objects
builtins :: [Builtin]
builtins = [
-- § 4.4.3.1 Fundamental Operations on Objects
bf_create
, bf_chparent
, bf_valid
, bf_parent
, bf_children
, bf_recycle
, bf_object_bytes
, bf_max_object
-- § 4.4.3.2 Object Movement
, bf_move
-- § 4.4.3.3 Operations on Properties
, bf_properties
, bf_property_info
, bf_set_property_info
, bf_add_property
, bf_delete_property
, bf_is_clear_property
, bf_clear_property
-- § 4.4.3.4 Operations on Verbs
, bf_verbs
, bf_verb_info
, bf_set_verb_info
, bf_verb_args
, bf_set_verb_args
, bf_add_verb
, bf_delete_verb
, bf_verb_code
, bf_set_verb_code
, bf_disassemble
-- § 4.4.3.5 Operations on Player Objects
, bf_players
, bf_is_player
, bf_set_player_flag
]
-- § 4.4.3.1 Fundamental Operations on Objects
modifyQuota :: ObjId -> (IntT -> MOO IntT) -> MOO ()
modifyQuota player f = do
maybeQuota <- readProperty player ownershipQuota
case maybeQuota of
Just (Int quota) -> do
quota' <- f quota
writeProperty player ownershipQuota (Int quota')
_ -> return ()
where ownershipQuota = "ownership_quota"
bf_create = Builtin "create" 1 (Just 2)
[TObj, TObj] TObj $ \(Obj parent : optional) -> do
let (maybeOwner : _) = maybeDefaults optional
maybeParent <- case parent of
-1 -> return Nothing
oid -> checkFertile oid >> return (Just oid)
db <- getDatabase
let newOid = maxObject db + 1
ownerOid <- case maybeOwner of
Nothing -> frame permissions
Just (Obj (-1)) -> checkWizard >> return newOid
Just (Obj oid) -> checkPermission oid >> return oid
modifyQuota ownerOid $ \quota ->
if quota <= 0 then raise E_QUOTA else return (quota - 1)
properties <- case maybeParent of
Nothing -> return $ objectProperties initObject
Just oid -> do
-- add to parent's set of children
liftSTM $ modifyObject oid db $ addChild newOid
-- properties inherited from parent
Just parent <- getObject oid
HM.fromList `liftM` mapM mkProperty (HM.toList $ objectProperties parent)
where mkProperty :: (StrT, TVar Property) -> MOO (StrT, TVar Property)
mkProperty (name, propTVar) = liftSTM $ do
prop <- readTVar propTVar
let prop' = prop {
propertyValue = Nothing
, propertyInherited = True
, propertyOwner = if propertyPermC prop then ownerOid
else propertyOwner prop
}
propTVar' <- newTVar prop'
return (name, propTVar')
let newObj = initObject {
objectParent = maybeParent
, objectOwner = ownerOid
, objectProperties = properties
}
putDatabase =<< liftSTM (addObject newObj db)
callFromFunc "create" 0 (newOid, "initialize") []
return (Obj newOid)
reparentObject :: (ObjId, Object) -> (ObjId, Maybe Object) -> MOO ()
reparentObject (object, obj) (new_parent, maybeNewParent) = do
-- Verify that neither object nor any of its descendants defines a property
-- with the same name as one defined on new_parent or any of its ancestors
case maybeNewParent of
Just newParent -> do
let props = HM.keys (objectProperties newParent)
flip traverseDescendants object $ \obj -> forM_ props $ \propName -> do
maybeProp <- liftSTM $ lookupProperty obj propName
case maybeProp of
Just prop | not (propertyInherited prop) -> raise E_INVARG
_ -> return ()
Nothing -> return ()
-- Find the nearest ancestor that object and new_parent have in common
oldAncestors <- ancestors object
newAncestors <- case maybeNewParent of
Just _ -> ancestors' new_parent
Nothing -> return []
let maybeCommon = findCommon oldAncestors newAncestors
underCommon ancestors = maybe ancestors prefix maybeCommon
where prefix common = takeWhile (/= common) ancestors
-- Remove properties defined by ancestors of object under common, and add
-- properties defined by new_parent or its ancestors under common
db <- getDatabase
oldProperties <- allDefinedProperties (underCommon oldAncestors)
newProperties <- case maybeNewParent of
Just newParent ->
allDefinedProperties (underCommon newAncestors) >>=
mapM (liftSTM . liftM fromJust . lookupProperty newParent)
Nothing -> return []
flip (modifyDescendants db) object $ \obj -> do
obj' <- foldM (flip deleteProperty) obj oldProperties
foldM (flip addInheritedProperty) obj' newProperties
-- Update the parent/child hierarchy
liftSTM $ modifyObject object db $ \obj ->
return obj { objectParent = const new_parent `fmap` maybeNewParent }
case objectParent obj of
Just parentOid -> liftSTM $ modifyObject parentOid db $ deleteChild object
Nothing -> return ()
case maybeNewParent of
Just _ -> liftSTM $ modifyObject new_parent db $ addChild object
Nothing -> return ()
where ancestors :: ObjId -> MOO [ObjId]
ancestors oid = do
maybeObject <- getObject oid
case join $ objectParent `fmap` maybeObject of
Just parent -> do
ancestors <- ancestors parent
return (parent : ancestors)
Nothing -> return []
ancestors' :: ObjId -> MOO [ObjId]
ancestors' oid = (oid :) `liftM` ancestors oid
findCommon :: [ObjId] -> [ObjId] -> Maybe ObjId
findCommon xs ys = findCommon' (reverse xs) (reverse ys) Nothing
findCommon' (x:xs) (y:ys) _
| x == y = findCommon' xs ys (Just x)
findCommon' _ _ common = common
allDefinedProperties :: [ObjId] -> MOO [StrT]
allDefinedProperties = liftM ($ []) . foldM concatProps id
where concatProps acc oid = do
Just obj <- getObject oid
props <- liftSTM $ definedProperties obj
return (acc props ++)
bf_chparent = Builtin "chparent" 2 (Just 2)
[TObj, TObj] TAny $ \[Obj object, Obj new_parent] -> do
obj <- checkValid object
maybeNewParent <- case new_parent of
-1 -> return Nothing
oid -> do
newParent <- checkValid oid
checkFertile oid
return (Just newParent)
checkPermission (objectOwner obj)
checkRecurrence objectParent object new_parent
reparentObject (object, obj) (new_parent, maybeNewParent)
return zero
bf_valid = Builtin "valid" 1 (Just 1) [TObj] TInt $ \[Obj object] ->
(truthValue . isJust) `liftM` getObject object
bf_parent = Builtin "parent" 1 (Just 1) [TObj] TObj $ \[Obj object] ->
(Obj . getParent) `liftM` checkValid object
bf_children = Builtin "children" 1 (Just 1) [TObj] TLst $ \[Obj object] ->
(objectList . getChildren) `liftM` checkValid object
bf_recycle = Builtin "recycle" 1 (Just 1) [TObj] TAny $ \[Obj object] -> do
obj <- checkValid object
let owner = objectOwner obj
checkPermission owner
callFromFunc "recycle" 0 (object, "recycle") []
moveContentsToNothing object
moveToNothing object
reparentChildren object (objectParent obj)
reparent object Nothing
setPlayerFlag True object False
getDatabase >>= liftSTM . deleteObject object
modifyQuota owner $ return . (+ 1)
return zero
where moveContentsToNothing :: ObjId -> MOO ()
moveContentsToNothing object = do
maybeObj <- getObject object
case getContents `fmap` maybeObj of
Just (oid:_) -> do
moveToNothing oid
moveContentsToNothing object
_ -> return ()
moveToNothing :: ObjId -> MOO ()
moveToNothing oid = moveObject "recycle" oid nothing
reparentChildren :: ObjId -> Maybe ObjId -> MOO ()
reparentChildren object maybeParent = do
maybeObj <- getObject object
case getChildren `fmap` maybeObj of
Just (oid:_) -> do
reparent oid maybeParent
reparentChildren object maybeParent
_ -> return ()
reparent :: ObjId -> Maybe ObjId -> MOO ()
reparent object maybeParent = do
maybeObj <- getObject object
case maybeObj of
Just obj -> do
newParent <- case maybeParent of
Just parentOid -> do
parent <- getObject parentOid
return (parentOid, parent)
Nothing -> return (nothing, Nothing)
reparentObject (object, obj) newParent
Nothing -> return ()
bf_object_bytes = Builtin "object_bytes" 1 (Just 1)
[TObj] TInt $ \[Obj object] -> do
checkWizard
obj <- checkValid object
propertyBytes <- liftM storageBytes $ liftSTM $
mapM readTVar $ HM.elems (objectProperties obj)
verbBytes <- liftM storageBytes $ liftSTM $
mapM (readTVar . snd) $ objectVerbs obj
return $ Int $ fromIntegral $ storageBytes obj + propertyBytes + verbBytes
bf_max_object = Builtin "max_object" 0 (Just 0) [] TObj $ \[] ->
(Obj . maxObject) `liftM` getDatabase
-- § 4.4.3.2 Object Movement
moveObject :: StrT -> ObjId -> ObjId -> MOO ()
moveObject funcName what where_ = do
let newWhere = case where_ of
-1 -> Nothing
oid -> Just oid
maybeWhat <- getObject what
case maybeWhat of
Nothing -> return ()
Just whatObj -> unless (objectLocation whatObj == newWhere) $ do
maybeWhere <- getObject where_
when (isNothing newWhere || isJust maybeWhere) $ do
checkRecurrence objectLocation what where_
let oldWhere = objectLocation whatObj
db <- getDatabase
liftSTM $ modifyObject what db $ \obj ->
return obj { objectLocation = newWhere }
case oldWhere of
Nothing -> return ()
Just oldWhere' -> liftSTM $ modifyObject oldWhere' db $ \obj ->
return obj { objectContents = IS.delete what (objectContents obj) }
case newWhere of
Nothing -> return ()
Just newWhere' -> liftSTM $ modifyObject newWhere' db $ \obj ->
return obj { objectContents = IS.insert what (objectContents obj) }
case oldWhere of
Nothing -> return ()
Just oldWhere' ->
void $ callFromFunc funcName 1 (oldWhere', "exitfunc") [Obj what]
maybeWhat <- getObject what
case maybeWhat of
Nothing -> return ()
Just whatObj ->
when (objectLocation whatObj == newWhere) $
void $ callFromFunc funcName 2 (where_, "enterfunc") [Obj what]
bf_move = Builtin "move" 2 (Just 2)
[TObj, TObj] TAny $ \[Obj what, Obj where_] -> do
what' <- checkValid what
where' <- case where_ of
-1 -> return Nothing
oid -> Just `liftM` checkValid oid
checkPermission (objectOwner what')
when (isJust where') $ do
accepted <- maybe False truthOf `liftM`
callFromFunc "move" 0 (where_, "accept") [Obj what]
unless accepted $ do
wizard <- isWizard =<< frame permissions
unless wizard $ raise E_NACC
moveObject "move" what where_
return zero
-- § 4.4.3.3 Operations on Properties
bf_properties = Builtin "properties" 1 (Just 1)
[TObj] TLst $ \[Obj object] -> do
obj <- checkValid object
unless (objectPermR obj) $ checkPermission (objectOwner obj)
stringList `liftM` liftSTM (definedProperties obj)
bf_property_info = Builtin "property_info" 2 (Just 2)
[TObj, TStr] TLst $ \[Obj object, Str prop_name] -> do
obj <- checkValid object
prop <- getProperty obj prop_name
unless (propertyPermR prop) $ checkPermission (propertyOwner prop)
return $ fromList [Obj $ propertyOwner prop, Str $ perms prop]
where perms prop = Str.fromString $ concat [['r' | propertyPermR prop],
['w' | propertyPermW prop],
['c' | propertyPermC prop]]
traverseDescendants :: (Object -> MOO a) -> ObjId -> MOO ()
traverseDescendants f oid = do
Just obj <- getObject oid
f obj
mapM_ (traverseDescendants f) $ getChildren obj
modifyDescendants :: Database -> (Object -> STM Object) -> ObjId -> MOO ()
modifyDescendants db f oid = do
liftSTM $ modifyObject oid db f
Just obj <- getObject oid
mapM_ (modifyDescendants db f) $ getChildren obj
{-# ANN module ("HLint: ignore Use String" :: String) #-}
checkPerms :: [Char] -> StrT -> MOO (Set Char)
checkPerms valid perms = do
let permSet = S.fromList (T.unpack $ Str.toCaseFold perms)
unless (S.null $ permSet `S.difference` S.fromList valid) $ raise E_INVARG
return permSet
bf_set_property_info = Builtin "set_property_info" 3 (Just 3)
[TObj, TStr, TLst]
TAny $ \[Obj object, Str prop_name, Lst info] -> do
(owner, perms, new_name) <- case V.toList info of
[Obj owner, Str perms] -> return (owner, perms, Nothing)
[_ , _ ] -> raise E_TYPE
[Obj owner, Str perms, Str new_name] -> return (owner, perms, Just new_name)
[_ , _ , _ ] -> raise E_TYPE
_ -> raise E_INVARG
permSet <- checkPerms "rwc" perms
checkValid owner
obj <- checkValid object
prop <- getProperty obj prop_name
unless (propertyPermW prop) $ checkPermission (propertyOwner prop)
checkPermission owner
let setInfo = modifyProperty obj prop_name $ \prop ->
return prop {
propertyOwner = owner
, propertyPermR = 'r' `S.member` permSet
, propertyPermW = 'w' `S.member` permSet
, propertyPermC = 'c' `S.member` permSet
}
case new_name of
Nothing -> setInfo
Just newName -> do
let oldName = prop_name
unless (objectPermW obj) $ checkPermission (objectOwner obj)
when (propertyInherited prop) $ raise E_INVARG
unless (newName == oldName) $ flip traverseDescendants object $ \obj ->
when (isJust $ lookupPropertyRef obj newName) $ raise E_INVARG
setInfo
db <- getDatabase
flip (modifyDescendants db) object $ \obj -> do
let Just propTVar = lookupPropertyRef obj oldName
prop <- readTVar propTVar
writeTVar propTVar $ prop { propertyName = newName }
return obj { objectProperties =
HM.insert newName propTVar $
HM.delete oldName (objectProperties obj) }
return zero
bf_add_property = Builtin "add_property" 4 (Just 4) [TObj, TStr, TAny, TLst]
TAny $ \[Obj object, Str prop_name, value, Lst info] -> do
(owner, perms) <- case V.toList info of
[Obj owner, Str perms] -> return (owner, perms)
[_ , _ ] -> raise E_TYPE
_ -> raise E_INVARG
permSet <- checkPerms "rwc" perms
checkValid owner
obj <- checkValid object
unless (objectPermW obj) $ checkPermission (objectOwner obj)
checkPermission owner
when (isBuiltinProperty prop_name) $ raise E_INVARG
flip traverseDescendants object $ \obj ->
when (isJust $ lookupPropertyRef obj prop_name) $ raise E_INVARG
let newProperty = initProperty {
propertyName = prop_name
, propertyValue = Just value
, propertyInherited = False
, propertyOwner = owner
, propertyPermR = 'r' `S.member` permSet
, propertyPermW = 'w' `S.member` permSet
, propertyPermC = 'c' `S.member` permSet
}
db <- getDatabase
liftSTM $ modifyObject object db (addProperty newProperty)
forM_ (getChildren obj) $
modifyDescendants db $ addInheritedProperty newProperty
return zero
bf_delete_property = Builtin "delete_property" 2 (Just 2)
[TObj, TStr] TAny $ \[Obj object, Str prop_name] -> do
obj <- checkValid object
unless (objectPermW obj) $ checkPermission (objectOwner obj)
prop <- getProperty obj prop_name
when (propertyInherited prop) $ raise E_PROPNF
db <- getDatabase
flip (modifyDescendants db) object $ \obj ->
return obj { objectProperties = HM.delete prop_name (objectProperties obj) }
return zero
bf_is_clear_property = Builtin "is_clear_property" 2 (Just 2)
[TObj, TStr] TInt $ \[Obj object, Str prop_name] -> do
obj <- checkValid object
if isBuiltinProperty prop_name
then return $ truthValue False
else do
prop <- getProperty obj prop_name
unless (propertyPermR prop) $ checkPermission (propertyOwner prop)
return (truthValue $ isNothing $ propertyValue prop)
bf_clear_property = Builtin "clear_property" 2 (Just 2)
[TObj, TStr] TAny $ \[Obj object, Str prop_name] -> do
obj <- checkValid object
if isBuiltinProperty prop_name
then raise E_PERM
else do
modifyProperty obj prop_name $ \prop -> do
unless (propertyPermW prop) $ checkPermission (propertyOwner prop)
unless (propertyInherited prop) $ raise E_INVARG
return prop { propertyValue = Nothing }
return zero
-- § 4.4.3.4 Operations on Verbs
bf_verbs = Builtin "verbs" 1 (Just 1) [TObj] TLst $ \[Obj object] -> do
obj <- checkValid object
unless (objectPermR obj) $ checkPermission (objectOwner obj)
stringList `liftM` liftSTM (definedVerbs obj)
bf_verb_info = Builtin "verb_info" 2 (Just 2)
[TObj, TAny] TLst $ \[Obj object, verb_desc] -> do
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermR verb) $ checkPermission (verbOwner verb)
return $ fromList
[Obj $ verbOwner verb, Str $ perms verb, Str $ verbNames verb]
where perms verb = Str.fromString $ concat [['r' | verbPermR verb],
['w' | verbPermW verb],
['x' | verbPermX verb],
['d' | verbPermD verb]]
verbInfo :: LstT -> MOO (ObjId, Set Char, StrT)
verbInfo info = do
(owner, perms, names) <- case V.toList info of
[Obj owner, Str perms, Str names] -> return (owner, perms, names)
[_ , _ , _ ] -> raise E_TYPE
_ -> raise E_INVARG
permSet <- checkPerms "rwxd" perms
checkValid owner
when (null $ Str.words names) $ raise E_INVARG
return (owner, permSet, names)
bf_set_verb_info = Builtin "set_verb_info" 3 (Just 3) [TObj, TAny, TLst]
TAny $ \[Obj object, verb_desc, Lst info] -> do
(owner, permSet, names) <- verbInfo info
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermW verb) $ checkPermission (verbOwner verb)
checkPermission owner
unless (names == verbNames verb || objectPermW obj) $
checkPermission (objectOwner obj)
modifyVerb (object, obj) verb_desc $ \verb ->
return verb {
verbNames = names
, verbOwner = owner
, verbPermR = 'r' `S.member` permSet
, verbPermW = 'w' `S.member` permSet
, verbPermX = 'x' `S.member` permSet
, verbPermD = 'd' `S.member` permSet
}
return zero
bf_verb_args = Builtin "verb_args" 2 (Just 2)
[TObj, TAny] TLst $ \[Obj object, verb_desc] -> do
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermR verb) $ checkPermission (verbOwner verb)
return $ stringList [dobj verb, prep verb, iobj verb]
where dobj = obj2string . verbDirectObject
iobj = obj2string . verbIndirectObject
prep = prep2string . verbPreposition
verbArgs :: LstT -> MOO (ObjSpec, PrepSpec, ObjSpec)
verbArgs args = do
(dobj, prep, iobj) <- case V.toList args of
[Str dobj, Str prep, Str iobj] -> return (dobj, breakSlash prep, iobj)
where breakSlash = fst . Str.breakOn "/"
[_ , _ , _ ] -> raise E_TYPE
_ -> raise E_INVARG
dobj' <- maybe (raise E_INVARG) return $ string2obj dobj
prep' <- maybe (raise E_INVARG) return $ string2prep prep
iobj' <- maybe (raise E_INVARG) return $ string2obj iobj
return (dobj', prep', iobj')
bf_set_verb_args = Builtin "set_verb_args" 3 (Just 3) [TObj, TAny, TLst]
TAny $ \[Obj object, verb_desc, Lst args] -> do
(dobj, prep, iobj) <- verbArgs args
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermW verb) $ checkPermission (verbOwner verb)
modifyVerb (object, obj) verb_desc $ \verb ->
return verb {
verbDirectObject = dobj
, verbPreposition = prep
, verbIndirectObject = iobj
}
return zero
bf_add_verb = Builtin "add_verb" 3 (Just 3)
[TObj, TLst, TLst] TInt $ \[Obj object, Lst info, Lst args] -> do
(owner, permSet, names) <- verbInfo info
(dobj, prep, iobj) <- verbArgs args
obj <- checkValid object
unless (objectPermW obj) $ checkPermission (objectOwner obj)
checkPermission owner
let definedVerb = initVerb {
verbNames = names
, verbOwner = owner
, verbPermR = 'r' `S.member` permSet
, verbPermW = 'w' `S.member` permSet
, verbPermX = 'x' `S.member` permSet
, verbPermD = 'd' `S.member` permSet
, verbDirectObject = dobj
, verbPreposition = prep
, verbIndirectObject = iobj
}
db <- getDatabase
liftSTM $ modifyObject object db $ addVerb definedVerb
return $ Int $ fromIntegral $ length (objectVerbs obj) + 1
bf_delete_verb = Builtin "delete_verb" 2 (Just 2)
[TObj, TAny] TAny $ \[Obj object, verb_desc] -> do
obj <- checkValid object
getVerb obj verb_desc
unless (objectPermW obj) $ checkPermission (objectOwner obj)
case lookupVerbRef obj verb_desc of
Nothing -> raise E_VERBNF
Just (index, _) -> do
db <- getDatabase
liftSTM $ modifyObject object db $ deleteVerb index
return zero
bf_verb_code = Builtin "verb_code" 2 (Just 4) [TObj, TAny, TAny, TAny]
TLst $ \(Obj object : verb_desc : optional) -> do
let [fully_paren, indent] = booleanDefaults optional [False, True]
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermR verb) $ checkPermission (verbOwner verb)
checkProgrammer
let code = init $ Str.splitOn "\n" $ Str.fromText $ TL.toStrict $
unparse fully_paren indent (verbProgram verb)
return (stringList code)
bf_set_verb_code = Builtin "set_verb_code" 3 (Just 3) [TObj, TAny, TLst]
TLst $ \[Obj object, verb_desc, Lst code] -> do
obj <- checkValid object
verb <- getVerb obj verb_desc
text <- (T.concat . ($ [])) `liftM` V.foldM addLine id code
unless (verbPermW verb) $ checkPermission (verbOwner verb)
checkProgrammer
case parse text of
Left errors -> return $ fromListBy (Str . Str.fromString) errors
Right program -> do
modifyVerb (object, obj) verb_desc $ \verb ->
return verb {
verbProgram = program
, verbCode = compile program
}
return emptyList
where addLine :: ([Text] -> [Text]) -> Value -> MOO ([Text] -> [Text])
addLine add (Str line) = return (add [Str.toText line, "\n"] ++)
addLine _ _ = raise E_INVARG
bf_disassemble = Builtin "disassemble" 2 (Just 2)
[TObj, TAny] TLst $ \[Obj object, verb_desc] -> do
obj <- checkValid object
verb <- getVerb obj verb_desc
unless (verbPermR verb) $ checkPermission (verbOwner verb)
let Program statements = verbProgram verb
return $ fromListBy (Str . Str.fromString . show) statements
-- § 4.4.3.5 Operations on Player Objects
bf_players = Builtin "players" 0 (Just 0) [] TLst $ \[] ->
(objectList . allPlayers) `liftM` getDatabase
bf_is_player = Builtin "is_player" 1 (Just 1) [TObj] TInt $ \[Obj object] ->
(truthValue . objectIsPlayer) `liftM` checkValid object
setPlayerFlag :: Bool -> ObjId -> Bool -> MOO ()
setPlayerFlag recycled object isPlayer = do
db <- getDatabase
liftSTM $ modifyObject object db $ \obj ->
return obj { objectIsPlayer = isPlayer }
putDatabase $ setPlayer isPlayer object db
unless isPlayer $ bootPlayer' recycled object
bf_set_player_flag = Builtin "set_player_flag" 2 (Just 2)
[TObj, TAny] TAny $ \[Obj object, value] -> do
checkValid object
checkWizard
setPlayerFlag False object (truthOf value)
return zero