{-# LANGUAGE PatternGuards #-} module Creature (dbGenerateInitialPlayerCreature, dbNewCreature, Roll(..), dbRollCreatureScore, getCreatureFaction, dbRollInjury, dbInjureCreature, dbGetDead, deleteCreature, sweepDead) where import Data.Maybe import CreatureData import DB import SpeciesData import Species import DBData import FactionData import Control.Monad.Error import Dice import Tool -- | -- Generates a new Creature from the specified species. -- dbGenerateCreature :: Faction -> Species -> DB Creature dbGenerateCreature faction species = do (stats,attribs,name) <- generateCreatureData species random_id <- dbNextRandomInteger return (Creature { creature_stats=stats, creature_attribs=attribs, creature_species_name=name, creature_random_id=random_id, creature_damage=0, creature_faction=faction}) -- | -- During DBRaceSelectionState, generates a new Creature for the player character and sets it into the -- database's DBClassSelectionState. -- dbGenerateInitialPlayerCreature :: Species -> DB () dbGenerateInitialPlayerCreature species = do newc <- dbGenerateCreature Player species dbSetStartingRace species setPlayerState (ClassSelectionState newc) -- | -- Generates a new Creature from the specified Species and adds it to the database. -- dbNewCreature :: (CreatureLocation l) => Faction -> Species -> l -> DB CreatureRef dbNewCreature faction species loc = do creature <- dbGenerateCreature faction species dbAddCreature creature loc data Roll = Roll { ideal_score :: Integer, other_situation_bonus :: Integer, actual_roll :: Integer } dbRollCreatureScore :: (DBReadable db) => Score -> Integer -> CreatureRef -> db Roll dbRollCreatureScore score bonus creature_ref = do ideal <- liftM ((+ bonus) . creatureScore score) $ dbGetCreature creature_ref actual <- roll [0..ideal] return $ Roll ideal bonus actual getCreatureFaction :: (DBReadable db) => CreatureRef -> db Faction getCreatureFaction = liftM creature_faction . dbGetCreature dbRollInjury :: (DBReadable db) => CreatureRef -> Integer -> db Integer dbRollInjury creature_ref damage_roll = do damage_reduction <- liftM actual_roll $ dbRollCreatureScore DamageReduction 0 creature_ref return $ max 0 $ damage_roll - damage_reduction dbInjureCreature :: Integer -> CreatureRef -> DB () dbInjureCreature x = dbModCreature $ \c -> c { creature_damage = creature_damage c + x } dbGetDead :: (DBReadable db) => Reference a -> db [CreatureRef] dbGetDead parent_ref = filterRO (liftM (\c -> creatureScore HitPoints c <= 0) . dbGetCreature) =<< dbGetContents parent_ref deleteCreature :: CreatureRef -> DB () deleteCreature = dbUnsafeDeleteObject $ \l -> do m_dropped_loc <- maybe (return Nothing) (liftM Just . dbDropTool) $ coerceEntityTyped _tool l return $ case m_dropped_loc of Just dropped_loc -> generalizeLocationRecord dropped_loc Nothing -> error "dbDeleteCreature: no case for this type of entity" sweepDead :: Reference a -> DB () sweepDead ref = do worst_to_best_critters <- sortByRO (liftM ideal_score . dbRollCreatureScore HitPoints 0) =<< dbGetDead ref flip mapM_ worst_to_best_critters $ \creature_ref -> do dbPushSnapshot (KilledEvent creature_ref) deleteCreature creature_ref