MazesOfMonad-1.0.5: src/MoresmauJP/Rpg/MazeObjects.hs
-- | Handling of items in the maze
-- (c) JP Moresmau 2009
module MoresmauJP.Rpg.MazeObjects where
import Control.Monad
import Data.List
import Data.Maybe
import qualified Data.Map as M
import MoresmauJP.Maze1.Maze
import MoresmauJP.Rpg.Character
import MoresmauJP.Rpg.Inventory hiding (dropItem)
import MoresmauJP.Rpg.Items
import MoresmauJP.Rpg.Magic
import MoresmauJP.Rpg.NPC
import MoresmauJP.Util.Lists
import MoresmauJP.Util.Random
import Text.Printf
data MazeObjects= MazeObjects {
items::(M.Map Cell [ItemType]),
npcs::(M.Map Cell NPCCharacter)
}
deriving (Read,Show,Eq)
data MazeOptions = MazeOptions {
itemProportion::Int,
npcProportion::Int,
trapProportion::Int
}
deriving (Read,Show)
generateObjects :: (MonadRandom m)=>Maze -> MazeOptions -> Int -> m MazeObjects
generateObjects mz options characterLevel =do
let ratio=((fromIntegral characterLevel/12.0) ** 2)::Float
-- less items as we progress
let realItemProportion=(fromIntegral $ itemProportion options) * ratio
itemMap<-generateItems (size mz) realItemProportion
let realTrapProportion=(fromIntegral $ trapProportion options) / ratio
itemMap2<-generateTraps (size mz) realTrapProportion itemMap
npcMap<-generateNPCs mz (fromIntegral $ npcProportion options) characterLevel
return (MazeObjects itemMap2 npcMap)
generateItems :: (MonadRandom m)=>Size -> Float -> m (M.Map Cell [ItemType])
generateItems sz proportion=do
cellsWithItems<-getCellWithItems sz proportion
let occ=occurenceList itemOccurences
foldM (\m cell -> do
it <- generateScroll =<< randomPickp occ
let m2=case M.lookup cell m of
Nothing->M.insert cell [it] m
Just its->M.insert cell (it:its) m
return m2) M.empty cellsWithItems
generateScroll :: (MonadRandom m) => ItemType -> m (ItemType)
generateScroll (Scroll "" "" g)=do
s<-randomPickp allSpells
return (Scroll (printf "Scroll of %s" (spellName s)) (spellName s) g)
generateScroll it=return it
generateTraps :: (MonadRandom m)=>Size -> Float -> (M.Map Cell [ItemType]) -> m (M.Map Cell [ItemType])
generateTraps sz proportion m=do
cellsWithItems<-getCellWithItems sz proportion
let occ=occurenceList trapOccurences
foldM (\m cell -> do
it <- randomPickp occ
let m2=case M.lookup cell m of
Nothing->M.insert cell [it] m
Just its->M.insert cell (it:its) m
return m2) m cellsWithItems
generateNPCs :: (MonadRandom m)=> Maze -> Float -> Int -> m (M.Map Cell NPCCharacter)
generateNPCs mz proportion characterLevel=do
cellsWithItems<-(getCellWithItems (size mz) proportion)
let attitudeModifier=floor ((fromIntegral characterLevel/10.0) ** 2)
-- no npc on start cell
let cells2=delete (start mz) cellsWithItems
let occ=occurenceList (getNPCOccurences characterLevel)
foldM (\m cell -> do
t <- randomPickp occ
case M.lookup cell m of
Nothing->do
c<-generateFromTemplate t attitudeModifier
return (M.insert cell c m)
Just _->return m
) M.empty cells2
getCellWithItems :: (MonadRandom m)=> Size -> Float -> m [Cell]
getCellWithItems (w,h) proportion=do
let nb=round (fromIntegral (h*w)/proportion)
replicateM nb (getCellWithItems' (w,h))
getCellWithItems' :: (MonadRandom m)=> Size -> m Cell
getCellWithItems' (w,h) =do
cellx<-getRandomRange (1,w)
celly<-getRandomRange (1,h)
return (cellx,celly)
listPickableItems :: GameWorld -> MazeObjects -> [ItemType]
listPickableItems gw mo=(filter (not . isTrap)) $ listItems' gw mo
getTrap:: GameWorld -> MazeObjects -> (MazeObjects,Maybe ItemType)
getTrap gw mo=let
maybeTrap=listToMaybe $ (filter isTrap) $ listItems' gw mo
in case maybeTrap of
Nothing->(mo,Nothing)
Just it->((MoresmauJP.Rpg.MazeObjects.takeItem gw mo it),Just it)
listItems':: GameWorld -> MazeObjects -> [ItemType]
listItems' gw mo =fromMaybe [] $ M.lookup (position gw) (items mo)
takeItem :: GameWorld -> MazeObjects -> ItemType -> MazeObjects
takeItem gw mo it=
let its=fromJust $ M.lookup (position gw) (items mo)
in mo{items=(M.insert (position gw) (delete it its) (items mo))}
dropItem :: GameWorld -> MazeObjects -> ItemType -> MazeObjects
dropItem gw mo it=
let its=case M.lookup (position gw) (items mo) of
Just its-> its
Nothing->[]
in mo{items= (M.insert (position gw) (it:its) (items mo))}
getNPC:: GameWorld -> MazeObjects -> Maybe NPCCharacter
getNPC gw mo = M.lookup (position gw) (npcs mo)
killNPC :: GameWorld -> MazeObjects -> Character -> (MazeObjects,Character,Gold)
killNPC gw mo c@(Character {inventory=inv})= let
killed=fromJust $ M.lookup (position gw) (npcs mo)
killedItems=map snd (listCarriedItemsUniqueObject $ inventory $ npcCharacter killed)
mo2=foldl (\mazeobj item->dropItem gw mazeobj item) mo killedItems
extraGold=getGold $ inventory $ npcCharacter killed
c2=c{inventory=addGold inv extraGold}
in (mo2{npcs= (M.delete (position gw) (npcs mo2))},c2,extraGold)
updateNPC :: GameWorld -> MazeObjects -> NPCCharacter -> MazeObjects
updateNPC gw mo npc= mo{npcs= (M.insert (position gw) npc (npcs mo))}
moveNPC :: (MonadRandom m)=> GameWorld -> MazeObjects -> NPCCharacter -> m MazeObjects
moveNPC gw mo npc= do
let mo2=mo{npcs= (M.delete (position gw) (npcs mo))}
let eligibleCells= filter (\x->x /= (position gw) && M.notMember x (npcs mo2)) (M.keys $ cellmap $ maze $ gw)
cell<-randomPickp eligibleCells
return mo2{npcs= (M.insert cell npc (npcs mo2))}
recoverNPCWithTime:: MazeObjects -> Int -> Int -> MazeObjects
recoverNPCWithTime mo tickCount toAdd=let
allnpcs=npcs mo
allnpcs2=M.map (\npc@(NPCCharacter{npcCharacter=c})->npc{npcCharacter=restoreWithTime c tickCount toAdd}) allnpcs
in mo{npcs=allnpcs2}