packages feed

Allure 0.8.0.0 → 0.8.1.0

raw patch · 9 files changed

+465/−102 lines, 9 filesdep +transformersdep ~LambdaHack

Dependencies added: transformers

Dependency ranges changed: LambdaHack

Files

Allure.cabal view
@@ -5,7 +5,7 @@ -- PVP summary:+-+------- breaking API changes --             | | +----- minor or non-breaking API additions --             | | | +--- code changes with no API change-version:       0.8.0.0+version:       0.8.1.0 synopsis:      Near-future Sci-Fi roguelike and tactical squad game description:   Allure of the Stars is a near-future Sci-Fi roguelike                and tactical squad game. Binaries and the game manual@@ -74,19 +74,22 @@                       Content.PlaceKind,                       Content.RuleKind,                       Content.TileKind,-                      TieKnot,+                      Implementation.MonadClientImplementation,+                      Implementation.MonadServerImplementation,+                      Implementation.TieKnot,                       Paths_Allure-  build-depends:      LambdaHack >= 0.8.0.0 && < 0.8.1.0,+  build-depends:      LambdaHack >= 0.8.1.0 && < 0.8.2.0,                       template-haskell >= 2.6, -                      async      >= 2,+                      async      >= 2.2.1,                       base       >= 4.9 && < 99,                       containers >= 0.5.3.0,                       enummapset >= 0.5.2.2,                       filepath   >= 1.2.0.1,                       optparse-applicative >= 0.13,                       random     >= 1.1,-                      text       >= 0.11.2.3+                      text       >= 0.11.2.3,+                      transformers >= 0.4    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings@@ -127,7 +130,9 @@                       Content.PlaceKind,                       Content.RuleKind,                       Content.TileKind,-                      TieKnot,+                      Implementation.MonadClientImplementation,+                      Implementation.MonadServerImplementation,+                      Implementation.TieKnot,                       Paths_Allure   build-depends:      LambdaHack,                       template-haskell >= 2.6,@@ -138,12 +143,13 @@                       filepath   >= 1.2.0.1,                       optparse-applicative >= 0.13,                       random     >= 1.1,-                      text       >= 0.11.2.3+                      text       >= 0.11.2.3,+                      transformers >= 0.4    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings                       BangPatterns, RecordWildCards, NamedFieldPuns, MultiWayIf,-                      LambdaCase, StrictData+                      LambdaCase, StrictData, CPP   other-extensions:   TemplateHaskell   ghc-options:        -Wall -Wcompat -Worphans -Wincomplete-uni-patterns -Wincomplete-record-updates -Wimplicit-prelude -Wmissing-home-modules -Widentities -Wredundant-constraints   ghc-options:        -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively
CHANGELOG.md view
@@ -1,3 +1,9 @@+## [v0.8.1.0](https://github.com/AllureOfTheStars/Allure/v0.8.0.0...v0.8.1.0)++- no player-visible changes+- significantly reduce RAM usage when compiling library+- update and extend CI+ ## [v0.8.0.0, aka 'Explosive dashboard'](https://github.com/AllureOfTheStars/Allure/compare/v0.7.1.0...v0.8.0.0)  - display initial bits of backstory as a help screen and in-game
+ GameDefinition/Implementation/MonadClientImplementation.hs view
@@ -0,0 +1,153 @@+-- Copyright (c) 2008--2011 Andres Loeh+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history)+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-- | The implementation of our custom game client monads. Just as any other+-- component of the library, this implementation can be substituted.+module Implementation.MonadClientImplementation+  ( executorCli+#ifdef EXPOSE_INTERNAL+    -- * Internal operations+  , CliState(..), CliImplementation(..)+#endif+  ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import           Control.Concurrent+import qualified Control.Monad.IO.Class as IO+import           Control.Monad.Trans.State.Strict hiding (State)++import           Game.LambdaHack.Atomic (MonadStateWrite (..), putState)+import           Game.LambdaHack.Client+import           Game.LambdaHack.Client.ClientOptions+import           Game.LambdaHack.Client.HandleAtomicM+import           Game.LambdaHack.Client.HandleResponseM+import           Game.LambdaHack.Client.LoopM+import           Game.LambdaHack.Client.MonadClient+import           Game.LambdaHack.Client.State+import           Game.LambdaHack.Client.UI+import           Game.LambdaHack.Client.UI.SessionUI+import           Game.LambdaHack.Common.Faction+import           Game.LambdaHack.Common.Kind+import           Game.LambdaHack.Common.MonadStateRead+import qualified Game.LambdaHack.Common.Save as Save+import           Game.LambdaHack.Common.State+import           Game.LambdaHack.Server (ChanServer (..))++data CliState = CliState+  { cliState   :: State            -- ^ current global state+  , cliClient  :: StateClient      -- ^ current client state+  , cliSession :: Maybe SessionUI  -- ^ UI state, empty for AI clients+  , cliDict    :: ChanServer       -- ^ this client connection information+  , cliToSave  :: Save.ChanSave (StateClient, Maybe SessionUI)+                                   -- ^ connection to the save thread+  }++-- | Client state transformation monad.+newtype CliImplementation a = CliImplementation+  { runCliImplementation :: StateT CliState IO a }+  deriving (Monad, Functor, Applicative)++instance MonadStateRead CliImplementation where+  {-# INLINE getsState #-}+  getsState f = CliImplementation $ gets $ f . cliState++instance MonadStateWrite CliImplementation where+  {-# INLINE modifyState #-}+  modifyState f = CliImplementation $ state $ \cliS ->+    let !newCliState = f $ cliState cliS+    in ((), cliS {cliState = newCliState})++instance MonadClient CliImplementation where+  {-# INLINE getsClient #-}+  getsClient   f = CliImplementation $ gets $ f . cliClient+  {-# INLINE modifyClient #-}+  modifyClient f = CliImplementation $ state $ \cliS ->+    let !newCliState = f $ cliClient cliS+    in ((), cliS {cliClient = newCliState})+  liftIO = CliImplementation . IO.liftIO++instance MonadClientSetup CliImplementation where+  saveClient = CliImplementation $ do+    toSave <- gets cliToSave+    cli <- gets cliClient+    msess <- gets cliSession+    IO.liftIO $ Save.saveToChan toSave (cli, msess)+  restartClient  = CliImplementation $ state $ \cliS ->+    case cliSession cliS of+      Just sess ->+        let !newSess = (emptySessionUI (sUIOptions sess))+                         { schanF = schanF sess+                         , sbinding = sbinding sess+                         , shistory = shistory sess+                         , sstart = sstart sess+                         , sgstart = sgstart sess+                         , sallTime = sallTime sess+                         , snframes = snframes sess+                         , sallNframes = sallNframes sess+                         }+        in ((), cliS {cliSession = Just newSess})+      Nothing -> ((), cliS)++instance MonadClientUI CliImplementation where+  {-# INLINE getsSession #-}+  getsSession   f = CliImplementation $ gets $ f . fromJust . cliSession+  {-# INLINE modifySession #-}+  modifySession f = CliImplementation $ state $ \cliS ->+    let !newCliSession = f $ fromJust $ cliSession cliS+    in ((), cliS {cliSession = Just newCliSession})+  liftIO = CliImplementation . IO.liftIO++instance MonadClientReadResponse CliImplementation where+  receiveResponse = CliImplementation $ do+    ChanServer{responseS} <- gets cliDict+    IO.liftIO $ takeMVar responseS++instance MonadClientWriteRequest CliImplementation where+  sendRequestAI scmd = CliImplementation $ do+    ChanServer{requestAIS} <- gets cliDict+    IO.liftIO $ putMVar requestAIS scmd+  sendRequestUI scmd = CliImplementation $ do+    ChanServer{requestUIS} <- gets cliDict+    IO.liftIO $ putMVar (fromJust requestUIS) scmd+  clientHasUI = CliImplementation $ do+    mSession <- gets cliSession+    return $! isJust mSession++instance MonadClientAtomic CliImplementation where+  {-# INLINE execUpdAtomic #-}+  execUpdAtomic _ = return ()  -- handleUpdAtomic, until needed, save resources+    -- Don't catch anything; assume exceptions impossible.+  {-# INLINE execPutState #-}+  execPutState = putState++-- | Run the main client loop, with the given arguments and empty+-- initial states, in the @IO@ monad.+executorCli :: KeyKind -> UIOptions -> ClientOptions+            -> COps+            -> Bool+            -> FactionId+            -> ChanServer+            -> IO ()+executorCli copsClient sUIOptions clientOptions cops isUI fid cliDict =+  let cliSession | isUI = Just $ emptySessionUI sUIOptions+                 | otherwise = Nothing+      stateToFileName (cli, _) =+        ssavePrefixCli (soptions cli) <> Save.saveNameCli cops (sside cli)+      totalState cliToSave = CliState+        { cliState = updateCOpsAndCachedData (const cops) emptyState+            -- state is empty, so the cached data is left empty and untouched+        , cliClient = emptyStateClient fid+        , cliDict+        , cliToSave+        , cliSession+        }+      m = loopCli copsClient sUIOptions clientOptions+      exe = evalStateT (runCliImplementation m) . totalState+  in Save.wrapInSaves cops stateToFileName exe
+ GameDefinition/Implementation/MonadServerImplementation.hs view
@@ -0,0 +1,205 @@+-- Copyright (c) 2008--2011 Andres Loeh+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history)+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-- | The implementation of our custom game server monads. Just as any other+-- component of the library, this implementation can be substituted.+module Implementation.MonadServerImplementation+  ( executorSer+#ifdef EXPOSE_INTERNAL+    -- * Internal operations+  , SerState(..), SerImplementation(..)+#endif+  ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import           Control.Concurrent+import qualified Control.Exception as Ex+import qualified Control.Monad.IO.Class as IO+import           Control.Monad.Trans.State.Strict hiding (State)+import qualified Data.EnumMap.Strict as EM+import qualified Data.Text.IO as T+import           Options.Applicative (defaultPrefs, execParserPure,+                                      handleParseResult)+import           System.Exit (ExitCode (ExitSuccess))+import           System.FilePath+import           System.IO (hFlush, stdout)++import           Game.LambdaHack.Atomic+import           Game.LambdaHack.Client+import           Game.LambdaHack.Common.File+import           Game.LambdaHack.Common.Kind+import           Game.LambdaHack.Common.Misc+import           Game.LambdaHack.Common.MonadStateRead+import qualified Game.LambdaHack.Common.Save as Save+import           Game.LambdaHack.Common.State+import           Game.LambdaHack.Common.Thread+import           Game.LambdaHack.Server+import           Game.LambdaHack.Server.BroadcastAtomic+import           Game.LambdaHack.Server.HandleAtomicM+import           Game.LambdaHack.Server.MonadServer+import           Game.LambdaHack.Server.ProtocolM+import           Game.LambdaHack.Server.ServerOptions+import           Game.LambdaHack.Server.State++import Implementation.MonadClientImplementation (executorCli)++data SerState = SerState+  { serState  :: State           -- ^ current global state+  , serServer :: StateServer     -- ^ current server state+  , serDict   :: ConnServerDict  -- ^ client-server connection information+  , serToSave :: Save.ChanSave (State, StateServer)+                                 -- ^ connection to the save thread+  }++-- | Server state transformation monad.+newtype SerImplementation a =+    SerImplementation {runSerImplementation :: StateT SerState IO a}+  deriving (Monad, Functor, Applicative)++instance MonadStateRead SerImplementation where+  {-# INLINE getsState #-}+  getsState f = SerImplementation $ gets $ f . serState++instance MonadStateWrite SerImplementation where+  {-# INLINE modifyState #-}+  modifyState f = SerImplementation $ state $ \serS ->+    let !newSerState = f $ serState serS+    in ((), serS {serState = newSerState})++instance MonadServer SerImplementation where+  {-# INLINE getsServer #-}+  getsServer   f = SerImplementation $ gets $ f . serServer+  {-# INLINE modifyServer #-}+  modifyServer f = SerImplementation $ state $ \serS ->+    let !newSerServer = f $ serServer serS+    in ((), serS {serServer = newSerServer})+  chanSaveServer = SerImplementation $ gets serToSave+  liftIO         = SerImplementation . IO.liftIO++instance MonadServerReadRequest SerImplementation where+  {-# INLINE getsDict #-}+  getsDict   f = SerImplementation $ gets $ f . serDict+  {-# INLINE modifyDict #-}+  modifyDict f = SerImplementation $ state $ \serS ->+    let !newSerDict = f $ serDict serS+    in ((), serS {serDict = newSerDict})+  liftIO = SerImplementation . IO.liftIO++instance MonadServerAtomic SerImplementation where+  execUpdAtomic cmd = do+    oldState <- getState+    (ps, atomicBroken, executedOnServer) <- handleCmdAtomicServer cmd+    when executedOnServer $ cmdAtomicSemSer oldState cmd+    handleAndBroadcast ps atomicBroken (UpdAtomic cmd)+  execUpdAtomicSer cmd = SerImplementation $ StateT $ \cliS -> do+    cliSNewOrE <- Ex.try+                  $ execStateT (runSerImplementation $ handleUpdAtomic cmd)+                               cliS+    case cliSNewOrE of+      Left AtomicFail{} -> return (False, cliS)+      Right cliSNew ->+        -- We know @cliSNew@ differs only in @serState@.+        return (True, cliSNew)+  execUpdAtomicFid fid cmd = SerImplementation $ StateT $ \cliS -> do+    -- Don't catch anything; assume exceptions impossible.+    let sFid = sclientStates (serServer cliS) EM.! fid+    cliSNew <- execStateT (runSerImplementation $ handleUpdAtomic cmd)+                          cliS {serState = sFid}+    -- We know @cliSNew@ differs only in @serState@.+    let serServerNew = (serServer cliS)+          {sclientStates = EM.insert fid (serState cliSNew)+                           $ sclientStates $ serServer cliS}+    return $! ((), cliS {serServer = serServerNew})+  execUpdAtomicFidCatch fid cmd = SerImplementation $ StateT $ \cliS -> do+    let sFid = sclientStates (serServer cliS) EM.! fid+    cliSNewOrE <- Ex.try+                  $ execStateT (runSerImplementation $ handleUpdAtomic cmd)+                               cliS {serState = sFid}+    case cliSNewOrE of+      Left AtomicFail{} -> return (False, cliS)+      Right cliSNew -> do+        -- We know @cliSNew@ differs only in @serState@.+        let serServerNew = (serServer cliS)+              {sclientStates = EM.insert fid (serState cliSNew)+                               $ sclientStates $ serServer cliS}+        return $! (True, cliS {serServer = serServerNew})+  execSfxAtomic sfx = do+    ps <- posSfxAtomic sfx+    handleAndBroadcast ps [] (SfxAtomic sfx)+  execSendPer = sendPer++-- Don't inline this, to keep GHC hard work inside the library+-- for easy access of code analysis tools.+-- | Run the main server loop, with the given arguments and empty+-- initial states, in the @IO@ monad.+executorSer :: COps -> KeyKind -> ServerOptions -> IO ()+executorSer cops copsClient soptionsNxtCmdline = do+  -- Parse UI client configuration file.+  -- It is reparsed at each start of the game executable.+  let benchmark = sbenchmark $ sclientOptions soptionsNxtCmdline+  -- Fail here, not inside client code, so that savefiles are not removed,+  -- because they are not the source of the failure.+  sUIOptions <- mkUIOptions cops benchmark+  soptionsNxt <- case uCmdline sUIOptions of+    []   -> return soptionsNxtCmdline+    args -> handleParseResult $ execParserPure defaultPrefs serverOptionsPI args+  -- Options for the clients modified with the configuration file.+  -- The client debug inside server debug only holds the client commandline+  -- options and is never updated with config options, etc.+  let clientOptions = applyUIOptions cops sUIOptions+                      $ sclientOptions soptionsNxt+      -- Partially applied main loop of the clients.+      executorClient = executorCli copsClient sUIOptions clientOptions cops+  -- Wire together game content, the main loop of game clients+  -- and the game server loop.+  let stateToFileName (_, ser) =+        ssavePrefixSer (soptions ser) <> Save.saveNameSer cops+      totalState serToSave = SerState+        { serState = updateCOpsAndCachedData (const cops) emptyState+            -- state is empty, so the cached data is left empty and untouched+        , serServer = emptyStateServer+        , serDict = EM.empty+        , serToSave+        }+      m = loopSer soptionsNxt executorClient+      exe = evalStateT (runSerImplementation m) . totalState+      exeWithSaves = Save.wrapInSaves cops stateToFileName exe+      defPrefix = ssavePrefixSer defServerOptions+      bkpOneSave name = do+        dataDir <- appDataDir+        let path bkp = dataDir </> "saves" </> bkp <> name+        b <- doesFileExist (path "")+        when b $ renameFile (path "") (path "bkp.")+      bkpAllSaves = if benchmark then return () else do+        T.hPutStrLn stdout "The game crashed, so savefiles are moved aside."+        bkpOneSave $ defPrefix <> Save.saveNameSer cops+        forM_ [-99..99] $ \n ->+          bkpOneSave $ defPrefix <> Save.saveNameCli cops (toEnum n)+  -- Wait for clients to exit even in case of server crash+  -- (or server and client crash), which gives them time to save+  -- and report their own inconsistencies, if any.+  Ex.handle (\(ex :: Ex.SomeException) -> case Ex.fromException ex of+               Just ExitSuccess ->+                 -- User-forced shutdown, not crash, so the intention is+                 -- to keep old saves and also clients may be not ready to save.+                 Ex.throwIO ex+               _ -> do+                 Ex.uninterruptibleMask_ $ threadDelay 1000000+                   -- let clients report their errors and save+                 when (ssavePrefixSer soptionsNxt == defPrefix) bkpAllSaves+                 hFlush stdout+                 Ex.throwIO ex  -- crash eventually, which kills clients+            )+            exeWithSaves+--  T.hPutStrLn stdout "Server exiting, waiting for clients."+--  hFlush stdout+  waitForChildren childrenServer  -- no crash, wait for clients indefinitely+--  T.hPutStrLn stdout "Server exiting now."+--  hFlush stdout
+ GameDefinition/Implementation/TieKnot.hs view
@@ -0,0 +1,83 @@+-- Copyright (c) 2008--2011 Andres Loeh+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history)+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+-- | Here the knot of engine code pieces, frontend and the game-specific+-- content definitions is tied, resulting in an executable game.+module Implementation.TieKnot+  ( tieKnot+  ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import qualified System.Random as R++import           Game.LambdaHack.Common.Kind+import qualified Game.LambdaHack.Common.Tile as Tile+import qualified Game.LambdaHack.Content.CaveKind as CK+import qualified Game.LambdaHack.Content.ItemKind as IK+import qualified Game.LambdaHack.Content.ModeKind as MK+import qualified Game.LambdaHack.Content.PlaceKind as PK+import qualified Game.LambdaHack.Content.RuleKind as RK+import qualified Game.LambdaHack.Content.TileKind as TK+import           Game.LambdaHack.Server++import qualified Client.UI.Content.KeyKind as Content.KeyKind+import qualified Content.CaveKind+import qualified Content.ItemKind+import qualified Content.ModeKind+import qualified Content.PlaceKind+import qualified Content.RuleKind+import qualified Content.TileKind+import           Implementation.MonadServerImplementation (executorSer)++-- | Tie the LambdaHack engine client, server and frontend code+-- with the game-specific content definitions, and run the game.+--+-- The custom monad types to be used are determined by the 'executorSer'+-- call, which in turn calls 'executorCli'. If other functions are used+-- in their place- the types are different and so the whole pattern+-- of computation differs. Which of the frontends is run inside the UI client+-- depends on the flags supplied when compiling the engine library.+-- Similarly for the choice of native vs JS builds.+tieKnot :: ServerOptions -> IO ()+tieKnot options@ServerOptions{sallClear, sboostRandomItem, sdungeonRng} = do+  -- This setup ensures the boosting option doesn't affect generating initial+  -- RNG for dungeon, etc., and also, that setting dungeon RNG on commandline+  -- equal to what was generated last time, ensures the same item boost.+  initialGen <- maybe R.getStdGen return sdungeonRng+  let soptionsNxt = options {sdungeonRng = Just initialGen}+      boostedItems = IK.boostItemKindList initialGen Content.ItemKind.items+      coitem = IK.makeData $+        if sboostRandomItem+        then boostedItems ++ Content.ItemKind.otherItemContent+        else Content.ItemKind.content+      coItemSpeedup = IK.speedupItem coitem+      cotile = TK.makeData coitem Content.TileKind.content+      coTileSpeedup = Tile.speedupTile sallClear cotile+      coplace = PK.makeData cotile Content.PlaceKind.content+      cocave = CK.makeData coitem coplace cotile Content.CaveKind.content+      -- Common content operations, created from content definitions.+      -- Evaluated fully to discover errors ASAP and to free memory.+      -- Fail here, not inside server code, so that savefiles are not removed,+      -- because they are not the source of the failure.+      !cops = COps+        { cocave+        , coitem+        , comode  = MK.makeData cocave coitem Content.ModeKind.content+        , coplace+        , corule  = RK.makeData Content.RuleKind.content+        , cotile+        , coItemSpeedup+        , coTileSpeedup+        }+      -- Client content operations containing default keypresses+      -- and command descriptions.+      !copsClient = Content.KeyKind.standardKeys+  -- Wire together game content, the main loops of game clients+  -- and the game server loop.+  executorSer cops copsClient soptionsNxt
GameDefinition/Main.hs view
@@ -29,7 +29,8 @@ #endif  import Game.LambdaHack.Server (serverOptionsPI)-import TieKnot++import Implementation.TieKnot  -- | Parse commandline options, tie the engine, content and clients knot, -- run the game and handle exit.
− GameDefinition/TieKnot.hs
@@ -1,83 +0,0 @@--- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history)--- This file is a part of the computer game Allure of the Stars--- and is released under the terms of the GNU Affero General Public License.--- For license and copyright information, see the file LICENSE.------ | Here the knot of engine code pieces and the game-specific--- content definitions is tied, resulting in an executable game.-module TieKnot-  ( tieKnot-  ) where--import Prelude ()--import Game.LambdaHack.Common.Prelude--import qualified System.Random as R--import           Game.LambdaHack.Common.Kind-import qualified Game.LambdaHack.Common.Tile as Tile-import qualified Game.LambdaHack.Content.CaveKind as CK-import qualified Game.LambdaHack.Content.ItemKind as IK-import qualified Game.LambdaHack.Content.ModeKind as MK-import qualified Game.LambdaHack.Content.PlaceKind as PK-import qualified Game.LambdaHack.Content.RuleKind as RK-import qualified Game.LambdaHack.Content.TileKind as TK-import           Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer)-import           Game.LambdaHack.Server--import qualified Client.UI.Content.KeyKind as Content.KeyKind-import qualified Content.CaveKind-import qualified Content.ItemKind-import qualified Content.ModeKind-import qualified Content.PlaceKind-import qualified Content.RuleKind-import qualified Content.TileKind---- | Tie the LambdaHack engine client, server and frontend code--- with the game-specific content definitions, and run the game.------ The custom monad types to be used are determined by the 'executorSer'--- call, which in turn calls 'executorCli'. If other functions are used--- in their place- the types are different and so the whole pattern--- of computation differs. Which of the frontends is run inside the UI client--- depends on the flags supplied when compiling the engine library.--- Similarly for the choice of native vs JS builds.-tieKnot :: ServerOptions -> IO ()-tieKnot options@ServerOptions{sallClear, sboostRandomItem, sdungeonRng} = do-  -- This setup ensures the boosting option doesn't affect generating initial-  -- RNG for dungeon, etc., and also, that setting dungeon RNG on commandline-  -- equal to what was generated last time, ensures the same item boost.-  initialGen <- maybe R.getStdGen return sdungeonRng-  let soptionsNxt = options {sdungeonRng = Just initialGen}-      boostedItems = IK.boostItemKindList initialGen Content.ItemKind.items-      coitem = IK.makeData $-        if sboostRandomItem-        then boostedItems ++ Content.ItemKind.otherItemContent-        else Content.ItemKind.content-      coItemSpeedup = IK.speedupItem coitem-      cotile = TK.makeData coitem Content.TileKind.content-      coTileSpeedup = Tile.speedupTile sallClear cotile-      coplace = PK.makeData cotile Content.PlaceKind.content-      cocave = CK.makeData coitem coplace cotile Content.CaveKind.content-      -- Common content operations, created from content definitions.-      -- Evaluated fully to discover errors ASAP and to free memory.-      -- Fail here, not inside server code, so that savefiles are not removed,-      -- because they are not the source of the failure.-      !cops = COps-        { cocave-        , coitem-        , comode  = MK.makeData cocave coitem Content.ModeKind.content-        , coplace-        , corule  = RK.makeData Content.RuleKind.content-        , cotile-        , coItemSpeedup-        , coTileSpeedup-        }-      -- Client content operations containing default keypresses-      -- and command descriptions.-      !copsClient = Content.KeyKind.standardKeys-  -- Wire together game content, the main loops of game clients-  -- and the game server loop.-  executorSer cops copsClient soptionsNxt
Makefile view
@@ -209,15 +209,7 @@ build-binary-common: 	cabal install --disable-library-profiling --disable-profiling --disable-documentation -f-release --only-dependencies 	cabal configure --disable-library-profiling --disable-profiling -f-release --prefix=/ --datadir=. --datasubdir=.-	which ld-	which ld.gold-	which ld.bfd-	which gcc-	ld --version-	ld.gold --version-	ld.bfd --version-	gcc --version-	cabal build -v2 exe:Allure+	cabal build exe:Allure 	mkdir -p AllureOfTheStars/GameDefinition/fonts 	cabal copy --destdir=AllureOfTheStarsInstall 	cp GameDefinition/config.ui.default AllureOfTheStars/GameDefinition
test/test.hs view
@@ -5,7 +5,7 @@ import Game.LambdaHack.Common.Prelude import Game.LambdaHack.Server -import TieKnot+import Implementation.TieKnot  main :: IO () main = do