module Game.LambdaHack.Actor
(
ActorId(..), isAHero, isAMonster, invalidActorId
, findHeroName, monsterGenChance
, Actor(..), template, addHp, unoccupied, heroKindId
, Target(..)
) where
import Control.Monad
import Data.Binary
import Data.Maybe
import Data.Ratio
import Game.LambdaHack.Utils.Assert
import Game.LambdaHack.Misc
import Game.LambdaHack.Vector
import Game.LambdaHack.Point
import Game.LambdaHack.Content.ActorKind
import qualified Game.LambdaHack.Kind as Kind
import Game.LambdaHack.Random
import qualified Game.LambdaHack.Config as Config
data Actor = Actor
{ bkind :: !(Kind.Id ActorKind)
, bsymbol :: !(Maybe Char)
, bname :: !(Maybe String)
, bhp :: !Int
, bdir :: !(Maybe (Vector, Int))
, btarget :: Target
, bloc :: !Point
, bletter :: !Char
, btime :: !Time
}
deriving Show
instance Binary Actor where
put (Actor ak an as ah ad at al ale ati) = do
put ak
put an
put as
put ah
put ad
put at
put al
put ale
put ati
get = do
ak <- get
an <- get
as <- get
ah <- get
ad <- get
at <- get
al <- get
ale <- get
ati <- get
return (Actor ak an as ah ad at al ale ati)
data ActorId = AHero !Int
| AMonster !Int
deriving (Show, Eq, Ord)
instance Binary ActorId where
put (AHero n) = putWord8 0 >> put n
put (AMonster n) = putWord8 1 >> put n
get = do
tag <- getWord8
case tag of
0 -> liftM AHero get
1 -> liftM AMonster get
_ -> fail "no parse (ActorId)"
isAHero :: ActorId -> Bool
isAHero (AHero _) = True
isAHero (AMonster _) = False
isAMonster :: ActorId -> Bool
isAMonster = not . isAHero
invalidActorId :: ActorId
invalidActorId = AMonster (1)
findHeroName :: Config.CP -> Int -> String
findHeroName config n =
let heroName = Config.getOption config "heroes" ("HeroName_" ++ show n)
in fromMaybe ("hero number " ++ show n) heroName
monsterGenChance :: Int -> Int -> Rnd Bool
monsterGenChance d numMonsters =
chance $ 1%(fromIntegral (250 + 200 * (numMonsters d)) `max` 50)
template :: Kind.Id ActorKind -> Maybe Char -> Maybe String -> Int -> Point
-> Actor
template mk mc ms hp loc =
let invalidTarget = TEnemy invalidActorId loc
in Actor mk mc ms hp Nothing invalidTarget loc 'a' 0
addHp :: Kind.Ops ActorKind -> Int -> Actor -> Actor
addHp Kind.Ops{okind} extra m =
assert (extra >= 0 `blame` extra) $
let maxHP = maxDice (ahp $ okind $ bkind m)
currentHP = bhp m
in if currentHP > maxHP
then m
else m {bhp = min maxHP (currentHP + extra)}
unoccupied :: [Actor] -> Point -> Bool
unoccupied actors loc =
all (\ body -> bloc body /= loc) actors
heroKindId :: Kind.Ops ActorKind -> Kind.Id ActorKind
heroKindId Kind.Ops{ouniqGroup} = ouniqGroup "hero"
data Target =
TEnemy ActorId Point
| TLoc Point
| TCursor
deriving (Show, Eq)
instance Binary Target where
put (TEnemy a ll) = putWord8 0 >> put a >> put ll
put (TLoc loc) = putWord8 1 >> put loc
put TCursor = putWord8 2
get = do
tag <- getWord8
case tag of
0 -> liftM2 TEnemy get get
1 -> liftM TLoc get
2 -> return TCursor
_ -> fail "no parse (Target)"