-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mob.hs
181 lines (154 loc) · 4.25 KB
/
Mob.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
module Mob where
import Util
import Item
import {-# SOURCE #-} Level
import Data.Maybe
import System.Random
theStairsCanWanderAround :: Bool
theStairsCanWanderAround = True
defaultStats :: Stats
defaultStats = Stats { hpmax = 10, hp = 10, atk = 10, def = 10, spd = 10 }
applyStats :: Stats -> Stats -> Stats
applyStats l r = Stats {
hpmax = (hpmax l + hpmax r),
hp = (hp l + hp r),
atk = ((atk l) + (atk r)),
def = ((def l) + (def r)),
spd = ((spd l) + (spd r))
}
class Mob a where
inv :: a -> Inv
pos :: a -> Pos
heading :: a -> Heading
name :: a -> String
baseStats :: a -> Stats
baseStats _ = defaultStats
effStats :: a -> Stats
effStats x = foldr (applyStats) (baseStats x) (catMaybes $ map equipStats $ inv x)
healPlayer :: Int -> Player -> Player
healPlayer n m = let s = statsP m in m{statsP=s{hp=max (hpmax s) (n + hp s)}}
data Player = Player {
nameP :: String,
posP :: Pos,
invP :: Inv,
headingP :: Heading,
statsP :: Stats
}
startingPlayer :: Player
startingPlayer = Player {
nameP = "bbrian",
posP = (5,10),
invP = [],
headingP = Util.Up,
statsP = defaultStats
}
instance Mob Player where
inv = invP
pos = posP
heading = headingP
name = nameP
baseStats = statsP
getHeading :: Player -> Heading
getHeading = headingP
getPos :: Player -> Pos
getPos = posP
data Monster = Monster {
nameM :: String,
descM :: String,
posM :: Pos,
invM :: Inv,
headingM :: Heading,
statsM :: Stats,
gen :: StdGen,
heardStepPos :: Maybe Pos,
heardStepExpTime :: Int
}
setHeard :: Monster -> Pos -> Int -> Monster
setHeard m p i = m{heardStepPos = Just p, heardStepExpTime = i}
getMonsterPos :: Monster -> Pos
getMonsterPos = posM
instance Mob Monster where
inv = invM
pos = posM
heading = headingM
name = nameM
baseStats = statsM
spaceman :: Pos -> IO Monster
spaceman p = do
gen <- newStdGen
return $ Monster {
nameM = "Spaceman",
descM = "A little green man. How did he get here?",
posM = p,
invM = [],
headingM = Util.Up,
statsM = Stats {
hpmax = 4,
hp = 4,
atk = 3,
def = 4,
spd = 6
},
gen = gen,
heardStepPos = Nothing,
heardStepExpTime = 0
}
stairs :: Pos -> IO Monster
stairs p = do
gen <- newStdGen
return $ Monster {
nameM = "stairs",
descM = "They send you places!",
posM = p,
invM = [],
headingM = Util.Up,
statsM = Stats {
hpmax = 4,
hp = 4,
atk = 3,
def = 4,
spd = 6
},
gen = gen,
heardStepPos = Nothing,
heardStepExpTime = 0
}
attackMob :: Player -> Monster -> Maybe Monster
attackMob p m = let s = statsP p
s' = statsM m
damage = (atk s - def s')
hpcount = hp s'
in if hpcount > damage then Just m{statsM=s'{hp=hpcount-damage}} else Nothing
movePlayer :: Heading -> Player -> Level -> Player
movePlayer h p l = let
newPos = applyHeading (posP p) h 1
headP = p{headingP = h}
in case (tile l newPos) of
Just Floor -> headP{posP = newPos}
_ -> headP
moveMonster :: Heading -> Monster -> Level -> Monster
moveMonster h m l = let
newPos = applyHeading (posM m) h 1
headM = m{headingM = h}
in case (tile l newPos) of
Just Floor -> headM{posM = newPos}
_ -> headM
monsterThink :: Monster -> World -> Monster
monsterThink m (Overworld l p lm) = if (nameM m) == "stairs" && (not theStairsCanWanderAround)
then m
else let
valid = filter (\(h, t) -> t == Just Floor) (map (\h -> (h, tile l $ applyHeading (posM m) h 1)) allHeadings)
in if null valid then m else let
(move, newGen) = choice (gen m) valid
randMoved = moveMonster (fst $ move) m{gen = newGen} l
in case heardStepPos m of
Nothing -> randMoved
Just pos -> let
(hdx,hdy) = (closestHeadings (posM m) pos)
in if (heardStepExpTime m) > 0
then if (elem hdx (map fst valid))
then moveMonster hdx m{heardStepExpTime = (heardStepExpTime m) - 1} l
else if (elem hdy (map fst valid))
then moveMonster hdy m{heardStepExpTime = (heardStepExpTime m) - 1} l
else randMoved
else randMoved