diff options
author | Gregor Kleen <pngwjpgh@users.noreply.github.com> | 2016-11-12 22:25:47 +0100 |
---|---|---|
committer | Gregor Kleen <pngwjpgh@users.noreply.github.com> | 2016-11-12 22:25:47 +0100 |
commit | ec57713b3d4acea066c30cf4285339303860df01 (patch) | |
tree | b869a0fbe85e1f8498ac4484857f7b4b5f475188 /src/Main.hs | |
parent | cf4bda4d1c9a5e3e57c0b2682c7647d811a31740 (diff) | |
download | 2017-01-16_17:13:37-ec57713b3d4acea066c30cf4285339303860df01.tar 2017-01-16_17:13:37-ec57713b3d4acea066c30cf4285339303860df01.tar.gz 2017-01-16_17:13:37-ec57713b3d4acea066c30cf4285339303860df01.tar.bz2 2017-01-16_17:13:37-ec57713b3d4acea066c30cf4285339303860df01.tar.xz 2017-01-16_17:13:37-ec57713b3d4acea066c30cf4285339303860df01.zip |
Timers for use with probabilistic focus and without
Diffstat (limited to 'src/Main.hs')
-rw-r--r-- | src/Main.hs | 134 |
1 files changed, 106 insertions, 28 deletions
diff --git a/src/Main.hs b/src/Main.hs index 54ec08a..db49e14 100644 --- a/src/Main.hs +++ b/src/Main.hs | |||
@@ -36,6 +36,7 @@ import Data.Maybe | |||
36 | import Data.Bool | 36 | import Data.Bool |
37 | import Data.Monoid (All(..)) | 37 | import Data.Monoid (All(..)) |
38 | import Data.Ord | 38 | import Data.Ord |
39 | import Data.Ratio | ||
39 | 40 | ||
40 | import Data.Foldable (toList) | 41 | import Data.Foldable (toList) |
41 | 42 | ||
@@ -84,7 +85,7 @@ main = do | |||
84 | , helpCommand "help" | 85 | , helpCommand "help" |
85 | , cmd "entities" listEntities "List all entities" | 86 | , cmd "entities" listEntities "List all entities" |
86 | , cmd "tip" focusTip "Focus the entity at the top of the queue" | 87 | , cmd "tip" focusTip "Focus the entity at the top of the queue" |
87 | , cmd "ptip" pFocusTip "Focus a random entity" | 88 | , cmd "pTip" pFocusTip "Focus a random entity" |
88 | , cmd "focus" setFocus "Focus a specific entity" | 89 | , cmd "focus" setFocus "Focus a specific entity" |
89 | , cmd "blur" blur "Focus no entity" | 90 | , cmd "blur" blur "Focus no entity" |
90 | , cmd "remove" remove "Remove the focused entity from the queue" | 91 | , cmd "remove" remove "Remove the focused entity from the queue" |
@@ -98,6 +99,9 @@ main = do | |||
98 | , cmd "test" rollTest "Roll a test using the stats of the currently focused entity" | 99 | , cmd "test" rollTest "Roll a test using the stats of the currently focused entity" |
99 | , cmd "combat" entitySeqVal "Roll sequence value for the current focus and enter combat" | 100 | , cmd "combat" entitySeqVal "Roll sequence value for the current focus and enter combat" |
100 | , cmd "combat'" factionSeqVal "Roll sequence values for all members of a faction and have them enter combat" | 101 | , cmd "combat'" factionSeqVal "Roll sequence values for all members of a faction and have them enter combat" |
102 | , cmd "timer" entityTimer "Set a timer associated with the current entity" | ||
103 | , cmd "pTimer" pEntityTimer "Set a timer associated with the current entity. Scale remaining time dynamically with the number of combatants" | ||
104 | , cmd "untimer" clearEntityTimer "Remove the timer associated with the current entity" | ||
101 | , cmd "uncombat" clearEntitySeqVal "Drop the focused entity out of combat" | 105 | , cmd "uncombat" clearEntitySeqVal "Drop the focused entity out of combat" |
102 | , cmd "uncombat'" clearFactionSeqVal "Drop all members of a faction out of combat" | 106 | , cmd "uncombat'" clearFactionSeqVal "Drop all members of a faction out of combat" |
103 | , cmd "spend" spendSeq "Spend some of the current focusĀ“ AP" | 107 | , cmd "spend" spendSeq "Spend some of the current focusĀ“ AP" |
@@ -117,13 +121,19 @@ main = do | |||
117 | stateOutline :: Sh GameState String | 121 | stateOutline :: Sh GameState String |
118 | stateOutline = do | 122 | stateOutline = do |
119 | st <- get | 123 | st <- get |
120 | case st of | 124 | time <- use gTimer |
121 | st | null (st ^. priorityQueue) -> return "" | 125 | |
122 | | otherwise -> unlines <$> mapM table (st ^. gRounds') | 126 | unlines <$> sequence ( ( if not (null $ st ^. timers) || not (null $ st ^. gRounds') |
127 | then [ return $ "Round timer: " ++ show time ] | ||
128 | else [] | ||
129 | ) | ||
130 | ++ ( if not (null $ st ^. timers) then [ tTable ] else [] ) | ||
131 | ++ ( if not (null $ st ^. gRounds') then map table (st ^. gRounds') else [] ) | ||
132 | ) | ||
123 | where | 133 | where |
124 | table :: Int -> Sh GameState String | 134 | table :: Int -> Sh GameState String |
125 | table round = do | 135 | table round = do |
126 | factions <- map (view faction') <$> use inhabitedFactions | 136 | factions <- map (view faction') <$> use combatFactions |
127 | st <- get | 137 | st <- get |
128 | let | 138 | let |
129 | roundStr 0 = "Current Round" | 139 | roundStr 0 = "Current Round" |
@@ -147,6 +157,27 @@ stateOutline = do | |||
147 | colsAllG top . ([maybe "" show $ view seqVal seq] :) <$> mapM factionColumn [0..(length factions - 1)] | 157 | colsAllG top . ([maybe "" show $ view seqVal seq] :) <$> mapM factionColumn [0..(length factions - 1)] |
148 | -- layoutTableToString <$> rowGs <*> pure (Just (roundStr round : factions, repeat def)) <*> pure (repeat def) <*> pure unicodeBoldHeaderS | 158 | -- layoutTableToString <$> rowGs <*> pure (Just (roundStr round : factions, repeat def)) <*> pure (repeat def) <*> pure unicodeBoldHeaderS |
149 | tableString <$> pure (repeat def) <*> pure unicodeBoldHeaderS <*> pure (titlesH $ roundStr round : factions) <*> rowGs | 159 | tableString <$> pure (repeat def) <*> pure unicodeBoldHeaderS <*> pure (titlesH $ roundStr round : factions) <*> rowGs |
160 | tTable :: Sh GameState String | ||
161 | tTable = do | ||
162 | factions <- map (view faction') <$> use combatFactions' | ||
163 | st <- get | ||
164 | let | ||
165 | time = st ^. gTimer | ||
166 | protoRows = groupBy ((==) `on` fst) $ st ^. timers | ||
167 | faction id = fromJust $ view eFaction <$> Map.lookup id (st ^. gEntities) | ||
168 | |||
169 | rowGs :: Sh GameState [RowGroup] | ||
170 | rowGs = runListT $ do | ||
171 | rowGroup'@((t, _):_) <- ListT $ return protoRows | ||
172 | let | ||
173 | rowGroup = map snd rowGroup' | ||
174 | factionColumn i = runListT $ do | ||
175 | x <- ListT $ return rowGroup | ||
176 | guard $ factionIndex x == i | ||
177 | toDesc x | ||
178 | factionIndex id = fromJust $ elemIndex (view faction' $ faction id) factions | ||
179 | colsAllG top . ([show . round $ t ^. absTime - fromIntegral time] :) <$> mapM factionColumn [0..(length factions - 1)] | ||
180 | tableString <$> pure (repeat def) <*> pure unicodeBoldHeaderS <*> pure (titlesH $ ("Time left") : factions) <*> rowGs | ||
150 | 181 | ||
151 | focusNotes :: GameState -> String | 182 | focusNotes :: GameState -> String |
152 | focusNotes st | 183 | focusNotes st |
@@ -191,24 +222,52 @@ stateMaintenance = do | |||
191 | gFocus' . eSeqVal .= Nothing | 222 | gFocus' . eSeqVal .= Nothing |
192 | -- gFocus .= Nothing | 223 | -- gFocus .= Nothing |
193 | void $ do | 224 | void $ do |
225 | newCount <- fromIntegral . length <$> use priorityQueue | ||
226 | lastCount <- fromIntegral <$> use gLastCount | ||
227 | time <- use gTimer | ||
228 | when (newCount /= lastCount) $ do | ||
229 | let | ||
230 | scale :: Entity -> Sh GameState Entity | ||
231 | scale entity = (execStateT ?? entity) $ do | ||
232 | eTimer . _Just %= scaleTimer time (newCount % (max 1 lastCount)) | ||
233 | gEntities <~ (mapM scale =<< use gEntities) | ||
234 | gLastCount <~ length <$> use priorityQueue | ||
235 | void $ do | ||
194 | round <- use gRound | 236 | round <- use gRound |
195 | let | 237 | let |
196 | finished sVal = fromMaybe False (previews (seqVal . _Just) (<= 0) sVal) || view (seqRound . _Wrapped) sVal /= round | 238 | finished sVal = fromMaybe False (previews (seqVal . _Just) (<= 0) sVal) || view (seqRound . _Wrapped) sVal /= round |
197 | allFinished <- getAll . foldMapOf (gEntities . each . eStats . sSequence . _Just) (All . finished) <$> get | 239 | allFinished <- getAll . foldMapOf (gEntities . each . eSeqVal . _Just) (All . finished) <$> get |
198 | when allFinished $ do | 240 | when allFinished $ do |
199 | let | 241 | let |
200 | advanceRound' :: EntityIdentifier -> Entity -> Sh GameState Entity | 242 | advanceRound' :: EntityIdentifier -> Entity -> Sh GameState Entity |
201 | advanceRound' ident entity = fmap (fromMaybe entity . (\(m, s) -> s <$ m)) . (runStateT ?? entity) . runMaybeT $ do | 243 | advanceRound' ident entity = fmap (fromMaybe entity . (\(m, s) -> s <$ m)) . (runStateT ?? entity) . runMaybeT $ do |
202 | cRound <- MaybeT . preuse $ eStats . sSequence . _Just . seqRound . _Wrapped | 244 | cRound <- MaybeT . preuse $ eSeqVal . _Just . seqRound . _Wrapped |
203 | guard $ cRound < 0 | 245 | guard $ cRound < 0 |
204 | cVal <- MaybeT . preuse $ eStats . sSequence . _Just . seqVal . _Just | 246 | cVal <- MaybeT . preuse $ eSeqVal . _Just . seqVal . _Just |
205 | name <- lift . lift $ toName ident | 247 | name <- lift . lift $ toName ident |
206 | nVal' <- MaybeT . preuse $ eStats . sSeqVal | 248 | (newEntity, nVal) <- lift . lift $ rollSeqVal entity name |
207 | nVal <- MaybeT . focusState eStats $ evalFormula' [name] nVal' | 249 | put $ set eSeqVal nVal newEntity |
208 | eStats . sSequence . _Just . seqVal . _Just += nVal | 250 | when (cVal < 0) $ -- Carry over negative values from previous rounds |
209 | eStats . sSequence . _Just . seqRound . _Wrapped += 1 | 251 | eSeqVal . _Just . seqVal . _Just += cVal |
252 | eSeqVal . _Just . seqRound . _Wrapped += 1 | ||
253 | advanceTimer :: Entity -> Sh GameState Entity | ||
254 | advanceTimer entity = (execStateT ?? entity) $ do | ||
255 | rTime <- lift $ use gTimer | ||
256 | eTimer . _Just . absTime -= fromIntegral rTime | ||
210 | gRounds -= 1 | 257 | gRounds -= 1 |
211 | gEntities <~ (imapM advanceRound' =<< use gEntities) | 258 | gEntities <~ (mapM advanceTimer =<< imapM advanceRound' =<< use gEntities) |
259 | gTimer .= 0 | ||
260 | |||
261 | rollSeqVal :: Entity -> String -> Sh GameState (Entity, Maybe SeqVal) | ||
262 | rollSeqVal entity name = do | ||
263 | let sVal = fromMaybe (val ignored ["Sequenzwert"] False) $ preview (eStats . sSeqVal) entity | ||
264 | (newEntity, sNum) <- evalFormula [name] entity sVal | ||
265 | round <- use gRound | ||
266 | let val = Just $ def | ||
267 | & set (seqRound . _Wrapped) round | ||
268 | & set seqVal (Just sNum) | ||
269 | & set seqEpsilon (entity ^. eStats . sSeqEpsilon) | ||
270 | return (newEntity, val) | ||
212 | 271 | ||
213 | -- Query state | 272 | -- Query state |
214 | listFactions, listEntities :: Sh GameState () | 273 | listFactions, listEntities :: Sh GameState () |
@@ -220,18 +279,39 @@ focusTip, blur, pFocusTip :: Sh GameState () | |||
220 | focusTip = gFocus <~ preuse tip | 279 | focusTip = gFocus <~ preuse tip |
221 | blur = gFocus .= Nothing | 280 | blur = gFocus .= Nothing |
222 | pFocusTip = do | 281 | pFocusTip = do |
282 | nextTimer <- preuse $ timers . folding listToMaybe | ||
283 | time <- fromIntegral <$> use gTimer | ||
223 | round <- use gRound | 284 | round <- use gRound |
224 | let | 285 | let |
225 | eWeight :: Maybe SeqVal -> Int | 286 | eWeight :: Maybe SeqVal -> Int |
226 | eWeight sVal | 287 | eWeight sVal |
227 | | preview (_Just . seqRound . _Wrapped) sVal == Just round | 288 | | preview (_Just . seqRound . _Wrapped) sVal == Just round |
228 | , (preview (_Just . seqVal . _Just) -> Just n) <- sVal = n | 289 | , (preview (_Just . seqVal . _Just) -> Just n) <- sVal = max 0 n |
229 | | otherwise = 0 | 290 | | otherwise = 0 |
230 | entities <- map (over _2 . view $ eSeqVal . to eWeight) . Map.toList <$> use gEntities | 291 | entities <- map (over _2 . view $ eSeqVal . to eWeight) . Map.toList <$> use gEntities |
231 | case entities of | 292 | case nextTimer of |
232 | [] -> gFocus .= Nothing | 293 | nextTimer |
233 | _ -> gFocus <~ Just <$> liftIO (enact $ makeEventProb entities) | 294 | | Just timer <- nextTimer |
234 | 295 | , fst $ over _1 (\t -> t ^. absTime <= time) timer | |
296 | -> gFocus .= Just (snd timer) | ||
297 | | null entities -> gFocus .= Nothing | ||
298 | | otherwise -> gFocus <~ Just <$> liftIO (enact $ makeEventProb entities) | ||
299 | |||
300 | entityTimer, pEntityTimer :: Completable TimerLength -> Sh GameState () | ||
301 | entityTimer = entityTimer' Constant | ||
302 | pEntityTimer = entityTimer' Scaled | ||
303 | entityTimer' toTimer = withArg $ \(TimerLength origin n) -> do | ||
304 | time <- use gTimer | ||
305 | entities <- length <$> use priorityQueue | ||
306 | let | ||
307 | timer = case origin of | ||
308 | Absolute -> n | ||
309 | Now -> time + n | ||
310 | gFocus' . eTimer .= Just (scaleTimer time (max 1 $ fromIntegral entities) . toTimer $ fromIntegral timer) | ||
311 | |||
312 | clearEntityTimer :: Sh GameState () | ||
313 | clearEntityTimer = gFocus' . eTimer .= Nothing | ||
314 | |||
235 | -- Manual focus | 315 | -- Manual focus |
236 | setFocus :: Completable EntityIdentifier -> Sh GameState () | 316 | setFocus :: Completable EntityIdentifier -> Sh GameState () |
237 | setFocus = withArg $ \ident -> gFocus ?= ident | 317 | setFocus = withArg $ \ident -> gFocus ?= ident |
@@ -346,21 +426,18 @@ clearFactionSeqVal = withArg $ \qFaction -> use gEntities >>= mapM_ (clearEntity | |||
346 | entitySeqVal', clearEntitySeqVal' :: EntityIdentifier -> Sh GameState () | 426 | entitySeqVal', clearEntitySeqVal' :: EntityIdentifier -> Sh GameState () |
347 | entitySeqVal' ident = void . runMaybeT $ do | 427 | entitySeqVal' ident = void . runMaybeT $ do |
348 | entity <- MaybeT $ preuse (gEntities . ix ident) | 428 | entity <- MaybeT $ preuse (gEntities . ix ident) |
349 | let sVal = fromMaybe (val ignored ["Sequenzwert"] False) $ preview (eStats . sSeqVal) entity | ||
350 | name <- toName ident | 429 | name <- toName ident |
351 | round <- use gRound | 430 | (newEntity, val) <- lift $ rollSeqVal entity name |
352 | (newEntity, sNum) <- evalFormula [name] entity sVal | ||
353 | let val = Just $ def | ||
354 | & set (seqRound . _Wrapped) round | ||
355 | & set seqVal (Just sNum) | ||
356 | & set seqEpsilon (entity ^. eStats . sSeqEpsilon) | ||
357 | gEntities . at ident .= Just (newEntity & set eSeqVal val) | 431 | gEntities . at ident .= Just (newEntity & set eSeqVal val) |
358 | gLog <>= pure (ident, "Sequence: " ++ show sNum) | 432 | gLog <>= pure (ident, "Sequence: " ++ show (fromJust $ view seqVal =<< val)) |
359 | clearEntitySeqVal' ident = gEntities . ix ident . eSeqVal .= Nothing | 433 | clearEntitySeqVal' ident = gEntities . ix ident . eSeqVal .= Nothing |
360 | 434 | ||
361 | spendSeq :: Int -> String -> Sh GameState () | 435 | spendSeq :: Int -> String -> Sh GameState () |
362 | spendSeq n logStr = withFocus $ \focusId -> do | 436 | spendSeq n logStr = withFocus $ \focusId -> do |
363 | gEntities . ix focusId . eStats . sSequence . _Just . seqVal . _Just -= n | 437 | gFocus' . eSeqVal . _Just . seqVal . _Just -= n |
438 | hasSeq <- isJust <$> preuse (gFocus' . eSeqVal . _Just . seqVal . _Just) | ||
439 | when hasSeq $ | ||
440 | gTimer += n | ||
364 | gLog <>= pure (focusId, logStr) | 441 | gLog <>= pure (focusId, logStr) |
365 | 442 | ||
366 | delay :: Sh GameState () | 443 | delay :: Sh GameState () |
@@ -478,4 +555,5 @@ printVal = withArg $ \formula -> withFocus $ \focusId -> do | |||
478 | (fromRational prob :: Double) | 555 | (fromRational prob :: Double) |
479 | barLength (replicate (round $ fromInteger barLength * normalize prob) '#') | 556 | barLength (replicate (round $ fromInteger barLength * normalize prob) '#') |
480 | lengths = map (length . show . fst) vals | 557 | lengths = map (length . show . fst) vals |
481 | normalize p = p / maximum (map snd vals) | 558 | -- normalize p = p / maximum (map snd vals) |
559 | normalize = id | ||