summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Main.hs20
-rw-r--r--src/Sequence/Contact/Archetypes.hs90
-rw-r--r--src/Sequence/Contact/Types.hs12
-rw-r--r--src/Sequence/Types.hs40
-rw-r--r--src/Sequence/Utils.hs30
5 files changed, 172 insertions, 20 deletions
diff --git a/src/Main.hs b/src/Main.hs
index 8f955bb..9ea7a49 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -32,11 +32,14 @@ import Data.Function
32import Control.Monad.State.Strict 32import Control.Monad.State.Strict
33 33
34import Sequence.Types 34import Sequence.Types
35import Sequence.Contact.Archetypes
35import Sequence.Utils 36import Sequence.Utils
36import Sequence.Formula 37import Sequence.Formula
37 38
38import Text.Layout.Table 39import Text.Layout.Table
39 40
41import Text.Read (readMaybe)
42
40main :: IO () 43main :: IO ()
41main = do 44main = do
42 historyFile <- getUserCacheFile "sequence" "history" 45 historyFile <- getUserCacheFile "sequence" "history"
@@ -44,7 +47,7 @@ main = do
44 let 47 let
45 description = initialShellDescription 48 description = initialShellDescription
46 { historyFile = Just historyFile 49 { historyFile = Just historyFile
47 , prompt = \st -> return $ maybe "" (++ " ") ((evalState ?? st) . toName <$> view tip st) ++ "→ " 50 , prompt = \st -> return $ maybe "" (++ " ") ((evalState ?? st) . toName <$> view gFocus st) ++ "→ "
48 , beforePrompt = gets stateOutline >>= (\str -> if null str then return () else shellPutStrLn str) 51 , beforePrompt = gets stateOutline >>= (\str -> if null str then return () else shellPutStrLn str)
49 , commandStyle = OnlyCommands 52 , commandStyle = OnlyCommands
50 , shellCommands = [ exitCommand "exit" 53 , shellCommands = [ exitCommand "exit"
@@ -57,6 +60,8 @@ main = do
57 , cmd "factions" listFactions "List all inhabited factions" 60 , cmd "factions" listFactions "List all inhabited factions"
58 , cmd "members" listFaction "List all members of a faction" 61 , cmd "members" listFaction "List all members of a faction"
59 , cmd "align" alignEntity "Align the focused entity to a faction – creating it, if necessary" 62 , cmd "align" alignEntity "Align the focused entity to a faction – creating it, if necessary"
63 , cmd "name" nameEntity "Name the current entity overriding previous name assignments"
64 , cmd "spawn" spawnEntity "Create a new entity from an archetype focusing on it"
60 ] 65 ]
61 } 66 }
62 void $ runShell description haskelineBackend (def :: GameState) 67 void $ runShell description haskelineBackend (def :: GameState)
@@ -95,7 +100,7 @@ blur = gFocus .= Nothing
95 100
96-- Manual focus 101-- Manual focus
97setFocus :: Completable EntityIdentifier -> Sh GameState () 102setFocus :: Completable EntityIdentifier -> Sh GameState ()
98setFocus = withArg $ \ident -> gFocus .= Just ident 103setFocus = withArg $ \ident -> gFocus ?= ident
99 104
100-- Drop information 105-- Drop information
101remove :: Sh GameState () 106remove :: Sh GameState ()
@@ -106,3 +111,14 @@ remove = withFocus $ \ident -> do
106 gEntities %= Map.delete ident 111 gEntities %= Map.delete ident
107 gEntityNames %= Bimap.delete ident 112 gEntityNames %= Bimap.delete ident
108 blur 113 blur
114
115-- Manage Entity
116spawnEntity :: Completable Entity -> Sh GameState ()
117spawnEntity = withArg $ \entity -> do
118 identifier <- use gNextId'
119 modify $ insertEntity entity
120 gFocus ?= identifier
121
122nameEntity :: String -> Sh GameState ()
123nameEntity ('#':_) = shellPutErrLn "We do not allow names that might shadow explicit access to entities via their number (‘#<n>’)"
124nameEntity name = withFocus $ \ident -> modifying gEntityNames $ Bimap.insert ident (name ^. entityName)
diff --git a/src/Sequence/Contact/Archetypes.hs b/src/Sequence/Contact/Archetypes.hs
new file mode 100644
index 0000000..94addce
--- /dev/null
+++ b/src/Sequence/Contact/Archetypes.hs
@@ -0,0 +1,90 @@
1{-# LANGUAGE OverloadedStrings, OverloadedLists, ViewPatterns, MultiParamTypeClasses #-}
2
3module Sequence.Contact.Archetypes where
4
5import Control.Lens
6
7import Sequence.Contact.Types
8import Sequence.Formula
9
10import Sequence.Types
11import Sequence.Utils
12
13import Data.Map (Map)
14import qualified Data.Map as Map
15
16import Data.Default
17
18import Data.List
19
20import Data.CaseInsensitive (CI)
21import qualified Data.CaseInsensitive as CI
22
23
24instance Completion Entity GameState where
25 completableLabel _ = "<archetype>"
26 complete _ _ (CI.foldCase -> prefix) = return . filter (prefix `isPrefixOf`) . map CI.foldedCase $ Map.keys archetypes
27
28instance Argument Entity GameState where
29 arg = return . fmap (flip (set eStats) def) . flip Map.lookup archetypes . CI.mk
30
31archetypes :: Map (CI String) Stats
32archetypes = [ ("Mensch", human)
33 , ("Kind von Mu", childOfMu)
34 ]
35
36
37human = Humanoid
38 { _sAStrength = vStrength
39 , _sAEndurance = vEndurance
40 , _sAMass = vMass
41 , _sAReflexes = vReflexes
42 , _sAMobility = vMobility
43 , _sADexterity = vDexterity
44 , _sAIntelligence = vIntelligence
45 , _sACharisma = vCharisma
46 , _sAPerception = vPerception
47 , _sAWillpower = vWillpower
48
49 , _sSArchaicRanged = 20 + vStrength `quot'` 2 + vDexterity `quot'` 2 + vPerception
50 , _sSFirearms = 15 + vMobility `quot'` 2 + vDexterity `quot'` 2 + vPerception
51 , _sSHeavyWeapons = vStrength `quot'` 2 + vPerception
52 , _sSEnergyWeapons = 10 + vMobility `quot'` 2 + vDexterity `quot'` 2 + vPerception
53 , _sSUnarmedMelee = 30 + vReflexes + vMobility `quot'` 2
54 , _sSArmedMelee = 25 + vReflexes + vMobility `quot'` 2
55 , _sSThrownWeapons = 25 + vMobility `quot'` 2 + vPerception
56 , _sSStealth = 5 + vMobility + vDexterity
57 , _sSThievery = 5 + vDexterity * 2 + vIntelligence
58 , _sSLockpicking = vDexterity + vIntelligence
59 , _sSTrapping = vDexterity + vIntelligence + vPerception `quot'` 2
60 , _sSSciences = 10 + vIntelligence * 4
61 , _sSFirstAid = 10 + vDexterity + vIntelligence * 2
62 , _sSMedicine = 5 + vDexterity `quot'` 2 + vIntelligence * 3
63 , _sSHumanities = 20 + vIntelligence * 3
64 , _sSEngineering = 5 + vDexterity + vIntelligence * 2
65 , _sSCraft = 25 + vDexterity * 2
66 , _sSInterface = 5 + vIntelligence * 2 + vPerception `quot'` 2
67 , _sSSpeech = vIntelligence + vCharisma * 2 + vWillpower `quot'` 2
68 , _sSLeadership = 5 + vCharisma * 3 + vWillpower
69 , _sSHomeEconomics = 25 + vIntelligence
70 , _sSSurvival = 30 + vReflexes + vMobility + vIntelligence + vPerception + vWillpower `quot'` 2
71 , _sSMotorcycle = vReflexes * 2 + vMobility + vWillpower
72 , _sSWheeled = 15 + vReflexes + vWillpower
73 , _sSHovercraft = 10 + vReflexes + vWillpower
74 , _sSAircraft = vReflexes + vWillpower
75 , _sSSpacecraft = vReflexes + vIntelligence `quot'` 2 + vPerception `quot'` 2
76 , _sSWatercraft = 20 + vReflexes `quot'` 2 + vPerception `quot'` 2
77 , _sSTracked = 15 + vReflexes + vPerception
78 , _sSExoskeleton = 30 + vReflexes + vMobility * 2 + vPerception
79
80 , _sMaxVitality = vEndurance * 2 + vMass * 2 + vWillpower + 10
81 , _sSeqVal = vReflexes * 2 + vMobility + vPerception + d 10
82 , _sPainTolerance = vMass `quot'` 2 + vWillpower
83 , _sFatigueTolerance = vWillpower `quot'` 2 + vEndurance
84 }
85
86childOfMu = human
87 & sAStrength +~ 2
88 & sAReflexes +~ 5
89 & sAMobility +~ 5
90 & sAPerception +~ 2
diff --git a/src/Sequence/Contact/Types.hs b/src/Sequence/Contact/Types.hs
index b63b369..d3ca31e 100644
--- a/src/Sequence/Contact/Types.hs
+++ b/src/Sequence/Contact/Types.hs
@@ -38,7 +38,7 @@ data Stats = Prop
38 , _sSHumanities 38 , _sSHumanities
39 , _sSEngineering 39 , _sSEngineering
40 , _sSCraft 40 , _sSCraft
41 , _sSInterfacte 41 , _sSInterface
42 , _sSSpeech 42 , _sSSpeech
43 , _sSLeadership 43 , _sSLeadership
44 , _sSHomeEconomics 44 , _sSHomeEconomics
@@ -108,3 +108,13 @@ makeLenses ''Stats
108instance Default Stats where 108instance Default Stats where
109 def = Prop 109 def = Prop
110 110
111vStrength = val sAStrength "Stärke?" True
112vEndurance = val sAEndurance "Ausdauer?" True
113vMass = val sAMass "Masse?" True
114vReflexes = val sAReflexes "Reflexe?" True
115vMobility = val sAMobility "Beweglichkeit?" True
116vDexterity = val sADexterity "Geschicklichkeit?" True
117vIntelligence = val sAIntelligence "Intelligenz?" True
118vCharisma = val sACharisma "Charisma?" True
119vPerception = val sAPerception "Wahrnehmung?" True
120vWillpower = val sAWillpower "Entschlossenheit?" True
diff --git a/src/Sequence/Types.hs b/src/Sequence/Types.hs
index 4370618..c47136c 100644
--- a/src/Sequence/Types.hs
+++ b/src/Sequence/Types.hs
@@ -1,13 +1,13 @@
1{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, ViewPatterns, OverloadedStrings, TemplateHaskell, GeneralizedNewtypeDeriving #-} 1{-# LANGUAGE FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, ViewPatterns, OverloadedStrings, TemplateHaskell, GeneralizedNewtypeDeriving #-}
2 2
3module Sequence.Types 3module Sequence.Types
4 ( GameState(..), gEntities, gEntityNames, gFocus 4 ( GameState, gEntities, gEntityNames, gFocus, gNextId'
5 , Faction, faction, faction' 5 , Faction, faction, faction'
6 , SeqVal(..), seqVal 6 , SeqVal(..), seqVal
7 , Entity(..), eFaction, eSeqVal 7 , Entity(..), eFaction, eSeqVal, eStats
8 , EntityName(..), entityName 8 , EntityName(..), entityName
9 , EntityIdentifier(..), entityId 9 , EntityIdentifier(..), entityId, entityId'
10 , inhabitedFactions, priorityQueue, tip 10 , inhabitedFactions, priorityQueue, tip, insertEntity
11 ) where 11 ) where
12 12
13import Control.Lens 13import Control.Lens
@@ -24,13 +24,16 @@ import qualified Data.Map.Strict as Map
24import Data.Bimap (Bimap) 24import Data.Bimap (Bimap)
25import qualified Data.Bimap as Bimap 25import qualified Data.Bimap as Bimap
26 26
27import Control.Monad.State
28
27import Data.List 29import Data.List
28import Data.Maybe 30import Data.Maybe
29import Data.Tuple 31import Data.Tuple
30import Data.Ord 32import Data.Ord
31 33
32import Sequence.Contact.Types 34import Sequence.Contact.Types
33 35
36import Text.Read (readMaybe)
34 37
35newtype Faction = Faction { _lFaction :: Maybe (CI String) } 38newtype Faction = Faction { _lFaction :: Maybe (CI String) }
36 deriving (Show, Eq, Ord) 39 deriving (Show, Eq, Ord)
@@ -75,16 +78,24 @@ instance Default Entity where
75 78
76newtype EntityName = EntityName { _entityName :: CI String } 79newtype EntityName = EntityName { _entityName :: CI String }
77 deriving (Show, Eq, Ord) 80 deriving (Show, Eq, Ord)
78makeLenses ''EntityName 81
82entityName :: Iso' String EntityName
83entityName = iso (EntityName . CI.mk) (CI.original . _entityName)
79 84
80newtype EntityIdentifier = EntityIdentifier { _entityId :: Integer } 85newtype EntityIdentifier = EntityIdentifier { _entityId :: Integer }
81 deriving (Show, Eq, Ord) 86 deriving (Show, Eq, Ord, Enum)
82makeLenses ''EntityIdentifier 87
88entityId :: Iso' Integer EntityIdentifier
89entityId = iso EntityIdentifier _entityId
90
91entityId' :: Prism' String EntityIdentifier
92entityId' = prism' (show . _entityId) (fmap EntityIdentifier . readMaybe)
83 93
84data GameState = GameState 94data GameState = GameState
85 { _gEntities :: Map EntityIdentifier Entity 95 { _gEntities :: Map EntityIdentifier Entity
86 , _gEntityNames :: Bimap EntityIdentifier EntityName 96 , _gEntityNames :: Bimap EntityIdentifier EntityName
87 , _gFocus :: Maybe EntityIdentifier 97 , _gFocus :: Maybe EntityIdentifier
98 , _gNextId :: EntityIdentifier
88 } 99 }
89makeLenses ''GameState 100makeLenses ''GameState
90 101
@@ -93,6 +104,7 @@ instance Default GameState where
93 { _gEntities = def 104 { _gEntities = def
94 , _gEntityNames = Bimap.empty 105 , _gEntityNames = Bimap.empty
95 , _gFocus = Nothing 106 , _gFocus = Nothing
107 , _gNextId = toEnum 0
96 } 108 }
97 109
98inhabitedFactions :: Getter GameState [Faction] 110inhabitedFactions :: Getter GameState [Faction]
@@ -107,3 +119,13 @@ priorityQueue = to priorityQueue'
107 119
108tip :: Getter GameState (Maybe EntityIdentifier) 120tip :: Getter GameState (Maybe EntityIdentifier)
109tip = priorityQueue . to (fmap snd . listToMaybe) 121tip = priorityQueue . to (fmap snd . listToMaybe)
122
123gNextId' :: Getter GameState EntityIdentifier
124gNextId' = gNextId
125
126insertEntity :: Entity -> GameState -> GameState
127insertEntity entity = execState $ do
128 identifier <- use gNextId
129 gEntities . at identifier ?= entity
130 gNextId %= succ
131
diff --git a/src/Sequence/Utils.hs b/src/Sequence/Utils.hs
index 274a69d..9fc0ab2 100644
--- a/src/Sequence/Utils.hs
+++ b/src/Sequence/Utils.hs
@@ -2,7 +2,9 @@
2 2
3module Sequence.Utils 3module Sequence.Utils
4 ( withArg, withFocus 4 ( withArg, withFocus
5 , toName, fromName 5 , toName
6 , Argument(..)
7 , Completion(..)
6 , module Sequence.Utils.Ask 8 , module Sequence.Utils.Ask
7 ) where 9 ) where
8 10
@@ -10,6 +12,7 @@ import Sequence.Types
10 12
11import Control.Monad.State.Strict 13import Control.Monad.State.Strict
12 14
15import Control.Applicative
13import Control.Monad 16import Control.Monad
14import Control.Lens 17import Control.Lens
15 18
@@ -28,6 +31,7 @@ import Data.Maybe
28import Text.Read (readMaybe) 31import Text.Read (readMaybe)
29 32
30import Data.List 33import Data.List
34import Data.Bool
31 35
32import System.Console.Shell 36import System.Console.Shell
33import System.Console.Shell.ShellMonad 37import System.Console.Shell.ShellMonad
@@ -49,20 +53,30 @@ withFocus f = use gFocus >>= \focus -> case focus of
49 Just id -> f id 53 Just id -> f id
50 54
51unaligned = view faction' def 55unaligned = view faction' def
52
53toName :: MonadState GameState m => EntityIdentifier -> m String
54toName id = fromMaybe (show $ id ^. entityId) . fmap (CI.original . view entityName) . Bimap.lookup id <$> use gEntityNames
55 56
56fromName :: MonadState GameState m => String -> m (Maybe EntityIdentifier) 57toName :: MonadState GameState m => EntityIdentifier -> m String
57fromName (readMaybe -> (Just (EntityIdentifier -> n))) = (n <$) . guard . Map.member n <$> use gEntities 58toName ident = do
58fromName (EntityName . CI.mk -> name) = Bimap.lookupR name <$> use gEntityNames 59 let number = review entityId' ident
60 isShadowed <- uses gEntityNames . Bimap.memberR $ view entityName number
61 let number' = bool id ('#':) isShadowed $ number
62 fromMaybe number' . fmap (review entityName) . Bimap.lookup ident <$> use gEntityNames
59 63
60instance Completion EntityIdentifier GameState where 64instance Completion EntityIdentifier GameState where
61 completableLabel _ = "<entity>" 65 completableLabel _ = "<entity>"
62 complete _ st prefix = return . filter ((isPrefixOf `on` CI.foldCase) prefix) . map ((evalState ?? st) . toName) . Map.keys $ st ^. gEntities 66 complete _ st prefix = return . filter ((isPrefixOf `on` CI.foldCase) prefix) . map ((evalState ?? st) . toName) . Map.keys $ st ^. gEntities
63 67
64instance Argument EntityIdentifier GameState where 68instance Argument EntityIdentifier GameState where
65 arg = fromName 69 arg = \str -> do
70 fromForcedIdR <- fromForcedId str
71 fromNameR <- fromName str
72 fromIdR <- fromId str
73 return $ fromForcedIdR <|> fromNameR <|> fromIdR
74 where
75 fromName (EntityName . CI.mk -> name) = Bimap.lookupR name <$> use gEntityNames
76 fromId (preview entityId' -> Just n) = (n <$) . guard . Map.member n <$> use gEntities
77 fromId _ = return Nothing
78 fromForcedId ('#':str) = fromId str
79 fromForcedId _ = return Nothing
66 80
67instance Completion Faction GameState where 81instance Completion Faction GameState where
68 completableLabel _ = "<faction>" 82 completableLabel _ = "<faction>"