diff options
-rw-r--r-- | src/Main.hs | 8 | ||||
-rw-r--r-- | src/Sequence/Contact/Archetypes.hs | 29 | ||||
-rw-r--r-- | src/Sequence/Contact/Tests.hs | 32 | ||||
-rw-r--r-- | src/Sequence/Contact/Types.hs | 218 | ||||
-rw-r--r-- | src/Sequence/Contact/Types/Internal.hs | 200 | ||||
-rw-r--r-- | src/Sequence/Formula.hs | 25 |
6 files changed, 377 insertions, 135 deletions
diff --git a/src/Main.hs b/src/Main.hs index 145df7a..b7c6a6e 100644 --- a/src/Main.hs +++ b/src/Main.hs | |||
@@ -15,7 +15,7 @@ import System.Directory | |||
15 | 15 | ||
16 | import Data.Default | 16 | import Data.Default |
17 | import Data.CaseInsensitive (CI) | 17 | import Data.CaseInsensitive (CI) |
18 | import qualified Data.CaseInsensitive | 18 | import qualified Data.CaseInsensitive as CI |
19 | 19 | ||
20 | import Data.Map.Strict (Map) | 20 | import Data.Map.Strict (Map) |
21 | import qualified Data.Map.Strict as Map | 21 | import qualified Data.Map.Strict as Map |
@@ -183,7 +183,8 @@ rollTest = withArg $ enactTest' >=> maybe (return ()) (shellPutStrLn . ppResult) | |||
183 | 183 | ||
184 | enactTest' :: (FormulaM Stats Test) -> Sh GameState (Maybe TestResult) | 184 | enactTest' :: (FormulaM Stats Test) -> Sh GameState (Maybe TestResult) |
185 | enactTest' test = withFocus' $ \focus -> do | 185 | enactTest' test = withFocus' $ \focus -> do |
186 | (newFocus, result) <- evalFormula focus (enactTest =<< test) | 186 | focusName <- use gFocus >>= toName . fromJust |
187 | (newFocus, result) <- evalFormula focusName focus (enactTest =<< test) | ||
187 | gFocus' .= newFocus | 188 | gFocus' .= newFocus |
188 | return result | 189 | return result |
189 | 190 | ||
@@ -200,5 +201,6 @@ entitySeqVal' ident = do | |||
200 | case (,) <$> entity <*> sVal of | 201 | case (,) <$> entity <*> sVal of |
201 | Nothing -> return () | 202 | Nothing -> return () |
202 | Just (entity, sVal) -> do | 203 | Just (entity, sVal) -> do |
203 | (newEntity, view (seqVal . re _Just) -> val) <- evalFormula entity sVal | 204 | name <- toName ident |
205 | (newEntity, view (seqVal . re _Just) -> val) <- evalFormula name entity sVal | ||
204 | gEntities . at ident .= Just (newEntity & set eSeqVal val) | 206 | gEntities . at ident .= Just (newEntity & set eSeqVal val) |
diff --git a/src/Sequence/Contact/Archetypes.hs b/src/Sequence/Contact/Archetypes.hs index 193892a..3e9b416 100644 --- a/src/Sequence/Contact/Archetypes.hs +++ b/src/Sequence/Contact/Archetypes.hs | |||
@@ -85,6 +85,17 @@ human = Humanoid | |||
85 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + d 10 | 85 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + d 10 |
86 | , _sPainTolerance = vMass `quot'` 2 + vWillpower | 86 | , _sPainTolerance = vMass `quot'` 2 + vWillpower |
87 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance | 87 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance |
88 | |||
89 | , _sHitzones = [ ("Kopf", 0.05) | ||
90 | , ("Torso", 0.49) | ||
91 | , ("Rechter Arm", 0.08) | ||
92 | , ("Linker Arm", 0.08) | ||
93 | , ("Unterleib", 0.10) | ||
94 | , ("Rechtes Bein", 0.10) | ||
95 | , ("Linkes Bein", 0.10) | ||
96 | ] | ||
97 | , _sDamage = const 0 | ||
98 | , _sArmor = const def | ||
88 | } | 99 | } |
89 | 100 | ||
90 | dog = Quadruped | 101 | dog = Quadruped |
@@ -109,6 +120,17 @@ dog = Quadruped | |||
109 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + 2 * d 10 | 120 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + 2 * d 10 |
110 | , _sPainTolerance = vMass `quot'` 2 + vWillpower | 121 | , _sPainTolerance = vMass `quot'` 2 + vWillpower |
111 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance | 122 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance |
123 | |||
124 | , _sHitzones = [ ("Kopf", 0.05) | ||
125 | , ("Torso", 0.49) | ||
126 | , ("Rechter Vorderlauf", 0.08) | ||
127 | , ("Linker Vorderlauf", 0.08) | ||
128 | , ("Hinterteil", 0.10) | ||
129 | , ("Rechter Hinterlauf", 0.10) | ||
130 | , ("Linker Hinterlauf", 0.10) | ||
131 | ] | ||
132 | , _sDamage = const 0 | ||
133 | , _sArmor = const def | ||
112 | } | 134 | } |
113 | 135 | ||
114 | dolphin = Dolphin | 136 | dolphin = Dolphin |
@@ -133,6 +155,13 @@ dolphin = Dolphin | |||
133 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + 2 * d 10 | 155 | , _sSeqVal = vReflexes * 2 + vMobility + vPerception + 2 * d 10 |
134 | , _sPainTolerance = vMass `quot'` 2 + vWillpower | 156 | , _sPainTolerance = vMass `quot'` 2 + vWillpower |
135 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance | 157 | , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance |
158 | |||
159 | , _sHitzones = [ ("Kopf", 0.10) | ||
160 | , ("Rumpf", 0.65) | ||
161 | , ("Schwanz", 0.25) | ||
162 | ] | ||
163 | , _sDamage = const 0 | ||
164 | , _sArmor = const def | ||
136 | } | 165 | } |
137 | 166 | ||
138 | childOfMu = human | 167 | childOfMu = human |
diff --git a/src/Sequence/Contact/Tests.hs b/src/Sequence/Contact/Tests.hs index 8aa072a..82b1cf3 100644 --- a/src/Sequence/Contact/Tests.hs +++ b/src/Sequence/Contact/Tests.hs | |||
@@ -1,9 +1,7 @@ | |||
1 | {-# LANGUAGE TemplateHaskell, OverloadedStrings, OverloadedLists, ViewPatterns, MultiParamTypeClasses, FlexibleContexts, RankNTypes, TypeSynonymInstances, FlexibleInstances, ImpredicativeTypes #-} | 1 | {-# LANGUAGE TemplateHaskell, OverloadedStrings, OverloadedLists, ViewPatterns, MultiParamTypeClasses, FlexibleContexts, RankNTypes, TypeSynonymInstances, FlexibleInstances #-} |
2 | 2 | ||
3 | module Sequence.Contact.Tests | 3 | module Sequence.Contact.Tests |
4 | ( TestResult(..), rWith, rBy | 4 | ( enactTest |
5 | , Test, tCritSuccessMod, tCritFailureMod, tBaseDifficulty, tMod | ||
6 | , enactTest | ||
7 | ) where | 5 | ) where |
8 | 6 | ||
9 | import Sequence.Formula | 7 | import Sequence.Formula |
@@ -13,6 +11,7 @@ import Sequence.Contact.Types | |||
13 | 11 | ||
14 | import Control.Monad | 12 | import Control.Monad |
15 | import Control.Monad.Reader | 13 | import Control.Monad.Reader |
14 | import Control.Monad.Base | ||
16 | import Control.Lens | 15 | import Control.Lens |
17 | 16 | ||
18 | import Data.Default | 17 | import Data.Default |
@@ -29,31 +28,6 @@ import Data.Traversable (mapM) | |||
29 | 28 | ||
30 | import Prelude hiding (mapM) | 29 | import Prelude hiding (mapM) |
31 | 30 | ||
32 | |||
33 | data TestResult = CritSuccess { _rWith, _rBy :: Int } | ||
34 | | Success { _rWith, _rBy :: Int } | ||
35 | | Failure { _rWith, _rBy :: Int } | ||
36 | | CritFailure { _rWith, _rBy :: Int } | ||
37 | deriving (Eq, Ord, Show) | ||
38 | makeLenses ''TestResult | ||
39 | |||
40 | data Test = Test | ||
41 | { _tCritSuccessMod | ||
42 | , _tCritFailureMod | ||
43 | , _tBaseDifficulty | ||
44 | , _tMod :: Int | ||
45 | } | ||
46 | deriving (Eq, Ord) | ||
47 | makeLenses ''Test | ||
48 | |||
49 | instance Default Test where | ||
50 | def = Test | ||
51 | { _tCritSuccessMod = 0 | ||
52 | , _tCritFailureMod = 0 | ||
53 | , _tBaseDifficulty = 50 | ||
54 | , _tMod = 0 | ||
55 | } | ||
56 | |||
57 | tests :: MonadReader Stats m => m (Map (CI String) (FormulaM Stats Test)) | 31 | tests :: MonadReader Stats m => m (Map (CI String) (FormulaM Stats Test)) |
58 | tests = mconcat <$> sequence [ test "Stärke" $ sAStrength . attributeTest | 32 | tests = mconcat <$> sequence [ test "Stärke" $ sAStrength . attributeTest |
59 | 33 | ||
diff --git a/src/Sequence/Contact/Types.hs b/src/Sequence/Contact/Types.hs index c00a60d..cd1bc02 100644 --- a/src/Sequence/Contact/Types.hs +++ b/src/Sequence/Contact/Types.hs | |||
@@ -1,6 +1,9 @@ | |||
1 | {-# LANGUAGE TemplateHaskell, RecordWildCards, OverloadedStrings, OverloadedLists, ViewPatterns, RankNTypes #-} | 1 | {-# LANGUAGE TemplateHaskell, RecordWildCards, OverloadedStrings, OverloadedLists, ViewPatterns, RankNTypes, ImpredicativeTypes #-} |
2 | 2 | ||
3 | module Sequence.Contact.Types where | 3 | module Sequence.Contact.Types |
4 | ( module Sequence.Contact.Types | ||
5 | , module Sequence.Contact.Types.Internal | ||
6 | ) where | ||
4 | 7 | ||
5 | import Sequence.Formula | 8 | import Sequence.Formula |
6 | 9 | ||
@@ -9,105 +12,103 @@ import Control.Lens | |||
9 | 12 | ||
10 | import Data.Default | 13 | import Data.Default |
11 | 14 | ||
12 | data Stats = Prop | 15 | import Data.Map (Map) |
13 | | Humanoid | 16 | import qualified Data.Map as Map |
14 | { _sAStrength | 17 | |
15 | , _sAEndurance | 18 | import Data.CaseInsensitive (CI) |
16 | , _sAMass | 19 | import qualified Data.CaseInsensitive as CI |
17 | , _sAReflexes | 20 | |
18 | , _sAMobility | 21 | import Data.String (IsString(..)) |
19 | , _sADexterity | 22 | import Data.Function (on) |
20 | , _sAIntelligence | 23 | import Data.Maybe |
21 | , _sACharisma | 24 | import Data.Ratio |
22 | , _sAPerception | 25 | |
23 | , _sAWillpower | 26 | import Control.Monad.Reader (ask) |
24 | 27 | import Control.Monad.State | |
25 | , _sSArchaicRanged | 28 | |
26 | , _sSFirearms | 29 | import Sequence.Contact.Types.Internal |
27 | , _sSHeavyWeapons | 30 | |
28 | , _sSEnergyWeapons | 31 | hitzone :: Iso' String Hitzone |
29 | , _sSUnarmedMelee | 32 | hitzone = iso (Hitzone . CI.mk) (CI.original . _hitzone) |
30 | , _sSArmedMelee | 33 | |
31 | , _sSThrownWeapons | 34 | instance IsString Hitzone where |
32 | , _sSStealth | 35 | fromString = view hitzone |
33 | , _sSThievery | 36 | |
34 | , _sSLockpicking | 37 | makeLenses ''Armor |
35 | , _sSTrapping | 38 | |
36 | , _sSSciences | 39 | instance Default Armor where |
37 | , _sSFirstAid | 40 | def = Armor |
38 | , _sSMedicine | 41 | { _aBallistic = 0 |
39 | , _sSHumanities | 42 | , _aPiercing = 0 |
40 | , _sSEngineering | 43 | , _aBlunt = 0 |
41 | , _sSCraft | 44 | , _aHeat = 0 |
42 | , _sSInterface | 45 | , _aCold = 0 |
43 | , _sSSpeech | 46 | , _aToxic = 0 |
44 | , _sSLeadership | 47 | , _aExplosive = 0 |
45 | , _sSHomeEconomics | 48 | } |
46 | , _sSSurvival | 49 | |
47 | , _sSMotorcycle | 50 | makeLenses ''TestResult |
48 | , _sSWheeled | 51 | |
49 | , _sSHovercraft | 52 | makeLenses ''Test |
50 | , _sSAircraft | 53 | |
51 | , _sSSpacecraft | 54 | instance Default Test where |
52 | , _sSWatercraft | 55 | def = Test |
53 | , _sSTracked | 56 | { _tName = "" |
54 | , _sSExoskeleton | 57 | , _tCritSuccessMod = 0 |
55 | 58 | , _tCritFailureMod = 0 | |
56 | , _sMaxVitality | 59 | , _tBaseDifficulty = 50 |
57 | , _sSeqVal | 60 | , _tMod = 0 |
58 | , _sPainTolerance | 61 | } |
59 | , _sFatigueTolerance :: Formula Stats | 62 | |
60 | } | 63 | makePrisms ''Modifier |
61 | | Quadruped | 64 | |
62 | { _sAStrength | 65 | instance Eq Modifier where |
63 | , _sAEndurance | 66 | (==) = (==) `on` (view $ _Modifier . _1) |
64 | , _sAMass | 67 | |
65 | , _sAReflexes | 68 | instance Ord Modifier where |
66 | , _sAMobility | 69 | compare = compare `on` (view $ _Modifier . _1) |
67 | , _sADexterity | 70 | |
68 | , _sAIntelligence | 71 | instance Default Modifier where |
69 | , _sACharisma | 72 | def = Modifier "" pure |
70 | , _sAPerception | 73 | |
71 | , _sAWillpower | 74 | makePrisms ''Effect |
72 | 75 | ||
73 | , _sSBiting | 76 | instance Eq Effect where |
74 | , _sSSearching | 77 | (==) = (==) `on` (view $ _Effect . _1) |
75 | , _sSStealth | 78 | |
76 | , _sSLeadership | 79 | instance Ord Effect where |
77 | , _sSDemeanour | 80 | compare = compare `on` (view $ _Effect . _1) |
78 | 81 | ||
79 | , _sMaxVitality | 82 | instance Default Effect where |
80 | , _sSeqVal | 83 | def = Effect "" pure |
81 | , _sPainTolerance | 84 | |
82 | , _sFatigueTolerance :: Formula Stats | 85 | makeLenses ''ShockEffect |
83 | } | 86 | |
84 | | Dolphin | 87 | instance Default ShockEffect where |
85 | { _sAStrength | 88 | def = ShockEffect { _seApplied = False |
86 | , _sAEndurance | 89 | , _seVal = pure Nothing |
87 | , _sAMass | 90 | , _seBar = pure Nothing |
88 | , _sAReflexes | 91 | , _seEffect = def |
89 | , _sAMobility | 92 | } |
90 | , _sADexterity | 93 | |
91 | , _sAIntelligence | ||
92 | , _sACharisma | ||
93 | , _sAPerception | ||
94 | , _sAWillpower | ||
95 | |||
96 | , _sSRamming | ||
97 | , _sSTargeting | ||
98 | , _sSSearching | ||
99 | , _sSStealth | ||
100 | , _sSComprehension | ||
101 | |||
102 | , _sMaxVitality | ||
103 | , _sSeqVal | ||
104 | , _sPainTolerance | ||
105 | , _sFatigueTolerance :: Formula Stats | ||
106 | } | ||
107 | makeLenses ''Stats | 94 | makeLenses ''Stats |
108 | 95 | ||
109 | instance Default Stats where | 96 | instance Default Stats where |
110 | def = Prop | 97 | def = Prop |
98 | { _sHitzones = [("Volumen", 1)] | ||
99 | , _sDamage = const 0 | ||
100 | , _sFatigue = 0 | ||
101 | , _sCripple = const def | ||
102 | , _sArmor = const def | ||
103 | |||
104 | , _sExtraSkills = [] | ||
105 | , _sModifiers = [] | ||
106 | } | ||
107 | |||
108 | applyModifier :: String -> (Test -> FormulaM Stats Test) -> Effect | ||
109 | applyModifier effectName modifier = Effect (CI.mk effectName) $ return . apply | ||
110 | where | ||
111 | apply = sModifiers <>~ [Modifier (CI.mk $ effectName ++ " (modifier)") modifier] | ||
111 | 112 | ||
112 | vStrength = val sAStrength "Stärke?" True | 113 | vStrength = val sAStrength "Stärke?" True |
113 | vEndurance = val sAEndurance "Ausdauer?" True | 114 | vEndurance = val sAEndurance "Ausdauer?" True |
@@ -119,3 +120,26 @@ vIntelligence = val sAIntelligence "Intelligenz?" True | |||
119 | vCharisma = val sACharisma "Charisma?" True | 120 | vCharisma = val sACharisma "Charisma?" True |
120 | vPerception = val sAPerception "Wahrnehmung?" True | 121 | vPerception = val sAPerception "Wahrnehmung?" True |
121 | vWillpower = val sAWillpower "Entschlossenheit?" True | 122 | vWillpower = val sAWillpower "Entschlossenheit?" True |
123 | |||
124 | scaled :: (Real a, Fractional a, Integral b) => Ratio b -> Iso' a a | ||
125 | scaled (realToFrac -> ratio) = iso (* ratio) (/ ratio) | ||
126 | |||
127 | sDamage' :: String -> Traversal' Stats Int | ||
128 | sDamage' (view hitzone -> zone) = sDamage . ix zone | ||
129 | |||
130 | sCripple' :: String -> Traversal' Stats ShockEffect | ||
131 | sCripple' (view hitzone -> zone) = sCripple . ix zone | ||
132 | |||
133 | sTotalDamage :: Lens' Stats Int | ||
134 | sTotalDamage = lens retrieve undefined | ||
135 | where | ||
136 | retrieve = do | ||
137 | hitzones <- Map.keys <$> view sHitzones | ||
138 | damageMap <- view sDamage | ||
139 | return . sum $ pure damageMap <*> hitzones | ||
140 | |||
141 | sDead :: Fold Stats (FormulaM Stats Bool) | ||
142 | sDead = folding $ do | ||
143 | maxVitality <- preview sMaxVitality | ||
144 | damage <- view sTotalDamage | ||
145 | return $ liftM2 (>) <$> Just (return damage) <*> maxVitality | ||
diff --git a/src/Sequence/Contact/Types/Internal.hs b/src/Sequence/Contact/Types/Internal.hs new file mode 100644 index 0000000..9929801 --- /dev/null +++ b/src/Sequence/Contact/Types/Internal.hs | |||
@@ -0,0 +1,200 @@ | |||
1 | {-# LANGUAGE RankNTypes #-} | ||
2 | |||
3 | module Sequence.Contact.Types.Internal where | ||
4 | |||
5 | import Sequence.Formula (Formula, FormulaM, Table) | ||
6 | |||
7 | import Data.Map (Map) | ||
8 | import Data.Set (Set) | ||
9 | import Data.Ratio | ||
10 | |||
11 | import Control.Lens | ||
12 | |||
13 | import Data.CaseInsensitive (CI) | ||
14 | |||
15 | newtype Hitzone = Hitzone { _hitzone :: CI String } | ||
16 | deriving (Eq, Ord) | ||
17 | |||
18 | data Armor = Armor | ||
19 | { _aBallistic | ||
20 | , _aPiercing | ||
21 | , _aBlunt | ||
22 | , _aHeat | ||
23 | , _aCold | ||
24 | , _aToxic | ||
25 | , _aExplosive :: Int | ||
26 | } | ||
27 | |||
28 | data TestResult = CritSuccess { _rWith, _rBy :: Int } | ||
29 | | Success { _rWith, _rBy :: Int } | ||
30 | | Failure { _rWith, _rBy :: Int } | ||
31 | | CritFailure { _rWith, _rBy :: Int } | ||
32 | deriving (Eq, Ord, Show) | ||
33 | |||
34 | data Test = Test | ||
35 | { _tName :: CI String | ||
36 | , _tCritSuccessMod | ||
37 | , _tCritFailureMod | ||
38 | , _tBaseDifficulty | ||
39 | , _tMod :: Int | ||
40 | } | ||
41 | deriving (Eq, Ord) | ||
42 | |||
43 | data Modifier = Modifier (CI String) (Test -> FormulaM Stats Test) | ||
44 | |||
45 | data Effect = Effect (CI String) (Stats -> FormulaM Stats Stats) | ||
46 | |||
47 | data ShockEffect = ShockEffect | ||
48 | { _seApplied :: Bool | ||
49 | , _seVal :: FormulaM Stats (Maybe Int) | ||
50 | , _seBar :: FormulaM Stats (Maybe Int) | ||
51 | , _seEffect :: Table Effect | ||
52 | } | ||
53 | |||
54 | data Stats = Prop | ||
55 | { _sHitzones :: Table Hitzone | ||
56 | , _sArmor :: Hitzone -> Armor | ||
57 | , _sCripple :: Hitzone -> ShockEffect | ||
58 | |||
59 | , _sDamage :: Hitzone -> Int | ||
60 | , _sFatigue :: Int | ||
61 | |||
62 | , _sPainShock :: ShockEffect | ||
63 | , _sFatigueShock :: ShockEffect | ||
64 | |||
65 | , _sExtraSkills :: Map (CI String) (FormulaM Stats Test) | ||
66 | , _sModifiers :: Set Modifier | ||
67 | } | ||
68 | | Humanoid | ||
69 | { _sAStrength | ||
70 | , _sAEndurance | ||
71 | , _sAMass | ||
72 | , _sAReflexes | ||
73 | , _sAMobility | ||
74 | , _sADexterity | ||
75 | , _sAIntelligence | ||
76 | , _sACharisma | ||
77 | , _sAPerception | ||
78 | , _sAWillpower | ||
79 | |||
80 | , _sSArchaicRanged | ||
81 | , _sSFirearms | ||
82 | , _sSHeavyWeapons | ||
83 | , _sSEnergyWeapons | ||
84 | , _sSUnarmedMelee | ||
85 | , _sSArmedMelee | ||
86 | , _sSThrownWeapons | ||
87 | , _sSStealth | ||
88 | , _sSThievery | ||
89 | , _sSLockpicking | ||
90 | , _sSTrapping | ||
91 | , _sSSciences | ||
92 | , _sSFirstAid | ||
93 | , _sSMedicine | ||
94 | , _sSHumanities | ||
95 | , _sSEngineering | ||
96 | , _sSCraft | ||
97 | , _sSInterface | ||
98 | , _sSSpeech | ||
99 | , _sSLeadership | ||
100 | , _sSHomeEconomics | ||
101 | , _sSSurvival | ||
102 | , _sSMotorcycle | ||
103 | , _sSWheeled | ||
104 | , _sSHovercraft | ||
105 | , _sSAircraft | ||
106 | , _sSSpacecraft | ||
107 | , _sSWatercraft | ||
108 | , _sSTracked | ||
109 | , _sSExoskeleton | ||
110 | |||
111 | , _sMaxVitality | ||
112 | , _sSeqVal | ||
113 | , _sPainTolerance | ||
114 | , _sFatigueTolerance :: Formula Stats | ||
115 | |||
116 | , _sHitzones :: Table Hitzone | ||
117 | , _sArmor :: Hitzone -> Armor | ||
118 | , _sCripple :: Hitzone -> ShockEffect | ||
119 | |||
120 | , _sDamage :: Hitzone -> Int | ||
121 | , _sFatigue :: Int | ||
122 | |||
123 | , _sPainShock :: ShockEffect | ||
124 | , _sFatigueShock :: ShockEffect | ||
125 | |||
126 | , _sExtraSkills :: Map (CI String) (FormulaM Stats Test) | ||
127 | , _sModifiers :: Set Modifier | ||
128 | } | ||
129 | | Quadruped | ||
130 | { _sAStrength | ||
131 | , _sAEndurance | ||
132 | , _sAMass | ||
133 | , _sAReflexes | ||
134 | , _sAMobility | ||
135 | , _sADexterity | ||
136 | , _sAIntelligence | ||
137 | , _sACharisma | ||
138 | , _sAPerception | ||
139 | , _sAWillpower | ||
140 | |||
141 | , _sSBiting | ||
142 | , _sSSearching | ||
143 | , _sSStealth | ||
144 | , _sSLeadership | ||
145 | , _sSDemeanour | ||
146 | |||
147 | , _sMaxVitality | ||
148 | , _sSeqVal | ||
149 | , _sPainTolerance | ||
150 | , _sFatigueTolerance :: Formula Stats | ||
151 | |||
152 | , _sHitzones :: Table Hitzone | ||
153 | , _sArmor :: Hitzone -> Armor | ||
154 | , _sCripple :: Hitzone -> ShockEffect | ||
155 | |||
156 | , _sDamage :: Hitzone -> Int | ||
157 | , _sFatigue :: Int | ||
158 | |||
159 | , _sPainShock :: ShockEffect | ||
160 | , _sFatigueShock :: ShockEffect | ||
161 | |||
162 | , _sExtraSkills :: Map (CI String) (FormulaM Stats Test) | ||
163 | , _sModifiers :: Set Modifier | ||
164 | } | ||
165 | | Dolphin | ||
166 | { _sAStrength | ||
167 | , _sAEndurance | ||
168 | , _sAMass | ||
169 | , _sAReflexes | ||
170 | , _sAMobility | ||
171 | , _sADexterity | ||
172 | , _sAIntelligence | ||
173 | , _sACharisma | ||
174 | , _sAPerception | ||
175 | , _sAWillpower | ||
176 | |||
177 | , _sSRamming | ||
178 | , _sSTargeting | ||
179 | , _sSSearching | ||
180 | , _sSStealth | ||
181 | , _sSComprehension | ||
182 | |||
183 | , _sMaxVitality | ||
184 | , _sSeqVal | ||
185 | , _sPainTolerance | ||
186 | , _sFatigueTolerance :: Formula Stats | ||
187 | |||
188 | , _sHitzones :: Table Hitzone | ||
189 | , _sArmor :: Hitzone -> Armor | ||
190 | , _sCripple :: Hitzone -> ShockEffect | ||
191 | |||
192 | , _sDamage :: Hitzone -> Int | ||
193 | , _sFatigue :: Int | ||
194 | |||
195 | , _sPainShock :: ShockEffect | ||
196 | , _sFatigueShock :: ShockEffect | ||
197 | |||
198 | , _sExtraSkills :: Map (CI String) (FormulaM Stats Test) | ||
199 | , _sModifiers :: Set Modifier | ||
200 | } | ||
diff --git a/src/Sequence/Formula.hs b/src/Sequence/Formula.hs index d486bab..ca945f8 100644 --- a/src/Sequence/Formula.hs +++ b/src/Sequence/Formula.hs | |||
@@ -2,10 +2,11 @@ | |||
2 | 2 | ||
3 | module Sequence.Formula | 3 | module Sequence.Formula |
4 | ( FormulaM, Formula, quot' | 4 | ( FormulaM, Formula, quot' |
5 | , (:<:)(..), Context(..) | 5 | , (:<:)(..), Context(..), ctx |
6 | , evalFormula | 6 | , evalFormula |
7 | , val | 7 | , val |
8 | , d, z | 8 | , d, z |
9 | , Table, table | ||
9 | ) where | 10 | ) where |
10 | 11 | ||
11 | import Control.Lens hiding (Context(..)) | 12 | import Control.Lens hiding (Context(..)) |
@@ -31,6 +32,9 @@ import Data.Either | |||
31 | import Data.Set (Set) | 32 | import Data.Set (Set) |
32 | import qualified Data.Set as Set | 33 | import qualified Data.Set as Set |
33 | 34 | ||
35 | import Data.Map (Map) | ||
36 | import qualified Data.Map as Map | ||
37 | |||
34 | class (:<:) small large where | 38 | class (:<:) small large where |
35 | ctx' :: Traversal' large small | 39 | ctx' :: Traversal' large small |
36 | 40 | ||
@@ -89,16 +93,20 @@ instance Integral a => Num (FormulaM input a) where | |||
89 | quot' :: Integral a => FormulaM input a -> FormulaM input a -> FormulaM input a | 93 | quot' :: Integral a => FormulaM input a -> FormulaM input a -> FormulaM input a |
90 | quot' = liftM2 quot | 94 | quot' = liftM2 quot |
91 | 95 | ||
92 | askQuestion :: (MonadIO m, sInput :<: lInput) => lInput -> Question sInput -> m lInput | 96 | askQuestion :: (MonadIO m, sInput :<: lInput) => String -> lInput -> Question sInput -> m lInput |
93 | askQuestion input q@(Question{..}) = flip (set $ ctx' . answer) input . maybe (throwError q) return <$> askQ prompt (join . fmap readMaybe) | 97 | askQuestion promptPref input q@(Question{..}) = flip (set $ ctx' . answer) input . maybe (throwError q) return <$> askQ (promptPref' ++ prompt) (join . fmap readMaybe) |
98 | where | ||
99 | promptPref' | ||
100 | | null promptPref = "" | ||
101 | | otherwise = promptPref ++ " » " | ||
94 | 102 | ||
95 | evalFormula :: (MonadIO m, sInput :<: lInput) => lInput -> FormulaM sInput a -> m (lInput, a) | 103 | evalFormula :: (MonadIO m, sInput :<: lInput) => String -> lInput -> FormulaM sInput a -> m (lInput, a) |
96 | evalFormula = evalFormula' [] | 104 | evalFormula = evalFormula' [] |
97 | where | 105 | where |
98 | evalFormula' finalChanges input formula = do | 106 | evalFormula' finalChanges promptPref input formula = do |
99 | result <- liftIO . enact . runExceptT . (runReaderT ?? (Context input)) . (evalStateT ?? Set.empty) $ formula | 107 | result <- liftIO . enact . runExceptT . (runReaderT ?? (Context input)) . (evalStateT ?? Set.empty) $ formula |
100 | case result of | 108 | case result of |
101 | Left q@(Question{..}) -> askQuestion input q >>= flip (evalFormula' $ bool (pure . set (ctx' . answer) $ throwError q) mempty keepResult ++ finalChanges) formula | 109 | Left q@(Question{..}) -> askQuestion promptPref input q >>= flip (flip evalFormula' promptPref $ bool (pure . set (ctx' . answer) $ throwError q) mempty keepResult ++ finalChanges) formula |
102 | Right result -> return (foldr ($) input finalChanges, result) | 110 | Right result -> return (foldr ($) input finalChanges, result) |
103 | 111 | ||
104 | val :: Integral a => Traversal' input (Formula input) -> String -> Bool -> Formula input | 112 | val :: Integral a => Traversal' input (Formula input) -> String -> Bool -> Formula input |
@@ -109,3 +117,8 @@ val answer prompt keepResult = do | |||
109 | d, z :: Integral a => Int -> FormulaM input a | 117 | d, z :: Integral a => Int -> FormulaM input a |
110 | d n = liftBase . fmap fromIntegral $ D.d n | 118 | d n = liftBase . fmap fromIntegral $ D.d n |
111 | z n = liftBase . fmap fromIntegral $ D.z n | 119 | z n = liftBase . fmap fromIntegral $ D.z n |
120 | |||
121 | type Table a = Map a Rational | ||
122 | |||
123 | table :: Ord a => Table a -> FormulaM input a | ||
124 | table = liftBase . makeEventProb . Map.assocs | ||