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 | ||
