packages feed

LambdaHack 0.9.3.1 → 0.9.4.0

raw patch · 30 files changed

+365/−255 lines, 30 filesdep ~assert-failuredep ~asyncdep ~base

Dependency ranges changed: assert-failure, async, base, base-compat, binary, containers, deepseq, enummapset, filepath, hashable, keys, miniutter, optparse-applicative, primitive, random, template-haskell, text, time, transformers, unordered-containers, vector, vector-binary-instances

Files

CHANGELOG.md view
@@ -1,3 +1,34 @@+## [v0.9.4.0](https://github.com/LambdaHack/LambdaHack/compare/v0.9.3.0...v0.9.4.0)++- In vty frontend highlight actors more+- Clean up actor highlighting+- Add yell/yawn to minimal command set, remove swerving the aiming line+- Invoke yell/yawn exclusively with '%', due tor Windows and terminal woes+- Move C-c command to C, not to mask C-c on console frontends+- Tweak and fix vty console frontends, for screen-readers+- React specially at gameover under certain special circumstances+- Simpliy assignSlot now that slots are auto-sorted+- Get rid of explicit item sorting; let lore and menu slots agree+- Make DetectExit non-modal+- Mark in a game end confirmation message that more treasure can be found+- Add a description to the escape embedded item+- Reword gameover text for raid scenario+- Be more verbose when confirming escape from the game+- Don't claim to summon, when not possible on this level+- Fix missing 'no longer poisoned' when applying antidote+- Don't ask confirmation for neutral (e.g., not IDed) items+- Fix 'you fall down; you stand on a sword'+- Prevent selecting regions via mouse down in web frontend+- Deselect item if player declines to apply or fling+- Hand-hold the player, warning if flung item is beneficial+- Hand-hold the player, warning if applied item is harmful+- Rewrite the condition in UI applyItem check+- Improve the lobable item skill failure message+- Let mouse buttons describe tiles, etc.+- Unblock S-MouseButton in SDL2 frontend+- Always describe things under mouse button+- Make the message when hitting dead foe more varied+ ## [v0.9.3.0, aka 'Velvet smoking jacket'](https://github.com/LambdaHack/LambdaHack/compare/v0.8.3.0...v0.9.3.0)  - Introduce message classes with configurable behaviour
GameDefinition/Content/ItemKindEmbed.hs view
@@ -7,12 +7,12 @@  import Game.LambdaHack.Core.Prelude +import Game.LambdaHack.Content.ItemKind+import Game.LambdaHack.Core.Dice import Game.LambdaHack.Definition.Ability import Game.LambdaHack.Definition.Color import Game.LambdaHack.Definition.Defs-import Game.LambdaHack.Core.Dice import Game.LambdaHack.Definition.Flavour-import Game.LambdaHack.Content.ItemKind  embeds :: [ItemKind] embeds =@@ -260,7 +260,7 @@   , iflavour = zipPlain [BrYellow]   , iaspects = [SetFlag Durable]   , ieffects = [Escape]-  , idesc    = ""+  , idesc    = "May this nightmare have an end?"   } staircaseTrapUp = ItemKind   { isymbol  = '^'
GameDefinition/Content/ModeKind.hs view
@@ -39,7 +39,7 @@   , mroster = rosterRaid   , mcaves  = cavesRaid   , mendMsg = [  (Killed, "This expedition has gone wrong. However, scientific mind does not despair, but analyzes and corrects. Did you perchance awake one animal too many? Did you remember to try using all consumables at your disposal for your immediate survival? Did you choose a challenge with difficulty level within your means? Answer honestly, ponder wisely, experiment methodically.")-              , (Defeated, "Sadly, the other team snatched the grant, while you were busy contemplating natural phenomena. Science is a competitive sport, as sad as it sounds. It's not enough to make a discovery, you have to get there first.")+              , (Defeated, "Regrettably, the other team snatched the grant, while you were busy contemplating natural phenomena. Science is a competitive sport, as sad as it sounds. It's not enough to make a discovery, you have to get there first.")               , (Escape, "You've got hold of the machine! Think of the hours of fun taking it apart and putting it back together again! That's a great first step on your quest to solve the typing problems of the world.") ]   , mdesc   = "An incredibly advanced typing machine worth 100 gold is buried at the exit of this maze. Be the first to find it and fund a research team that makes typing accurate and dependable forever."   }
GameDefinition/InGameHelp.txt view
@@ -18,12 +18,12 @@   In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair).  Press `KP_5` (`5` on keypad) to wait, bracing for impact, which reduces any- damage taken and prevents displacement by foes. Press `C-KP_5` (the same key- with Control) to lurk 0.1 of a turn, without bracing and `S-KP_5` (with Shift)- or `%` to yell/yawn, taunting and waking up enemies/yourself. Displace enemies- by running into them with Shift/Control or S-LMB. Search, open, descend and- attack by bumping into walls, doors, stairs and enemies. The best melee weapon- is automatically chosen from your equipment and from among your body parts.+ damage taken and prevents displacement by foes. Press `S-KP_5` or `C-KP_5`+ (the same key with Shift or Control) to lurk 0.1 of a turn, without bracing.+ Displace enemies by running into them with Shift/Control or S-LMB. Search,+ open, descend and attack by bumping into walls, doors, stairs and enemies.+ The best melee weapon is automatically chosen from your equipment+ and from among your body parts.   The following commands, joined with the basic set above,  let you accomplish anything in the game, though@@ -43,7 +43,7 @@  KP_* or !    cycle x-hair among enemies  KP_/ or /    cycle x-hair among items  c            close door- +            swerve the aiming line+ %            yell/yawn   Here is the complete list of commands from the snapshot of in-game help.@@ -76,7 +76,6 @@  A            manage all owned items  @            describe organs of the leader  #            show skill summary of the leader- ^            sort items by kind and rolled aspects  ~            display known lore   Note how upper case item commands (manage Pack, Equipment,@@ -92,7 +91,7 @@  TAB          cycle among party members on the level  S-TAB        cycle among all party members  c            close door- C-c          open or close or alter+ C            open or close or alter  =            select (or deselect) party member  _            deselect (or select) all on the level  ;            go to x-hair for 25 steps
GameDefinition/Main.hs view
@@ -12,11 +12,11 @@ import qualified Control.Exception as Ex import qualified Options.Applicative as OA import           System.Exit+import qualified System.IO as SIO  #ifndef USE_JSFILE import qualified GHC.IO.Handle import           System.FilePath-import qualified System.IO as SIO  import Game.LambdaHack.Common.File (tryCreateDir) import Game.LambdaHack.Common.Misc@@ -48,6 +48,9 @@     fstderr <- SIO.openFile (dataDir </> "stderr.txt") SIO.WriteMode     GHC.IO.Handle.hDuplicateTo fstdout SIO.stdout     GHC.IO.Handle.hDuplicateTo fstderr SIO.stderr+#else+  -- Work around display of one character per line.+  SIO.hSetBuffering SIO.stderr SIO.LineBuffering #endif   -- Fail here, not inside server code, so that savefiles are not removed,   -- because they are not the source of the failure.
GameDefinition/MoveKeys.txt view
@@ -11,9 +11,9 @@  In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair). Press `KP_5` (`5` on keypad) to wait, bracing for impact, which reduces any-damage taken and prevents displacement by foes. Press `C-KP_5` (the same key-with Control) to lurk 0.1 of a turn, without bracing and `S-KP_5` (with Shift)-or `%` to yell/yawn, taunting and waking up enemies/yourself. Displace enemies-by running into them with Shift/Control or S-LMB. Search, open, descend and-attack by bumping into walls, doors, stairs and enemies. The best melee weapon-is automatically chosen from your equipment and from among your body parts.+damage taken and prevents displacement by foes. Press `S-KP_5` or `C-KP_5`+(the same key with Shift or Control) to lurk 0.1 of a turn, without bracing.+Displace enemies by running into them with Shift/Control or S-LMB. Search,+open, descend and attack by bumping into walls, doors, stairs and enemies.+The best melee weapon is automatically chosen from your equipment+and from among your body parts.
GameDefinition/PLAYING.md view
@@ -93,7 +93,7 @@ ------  The heroes are displayed on the map with bright white color (red if they are-about to be lost) and symbols `@` and `1` through `9` (never `0`).+about to fall down) and symbols `@` and `1` through `9` (never `0`). The currently chosen party leader is yellow-highlighted on the map and his attributes are displayed at the bottom-most status line which, in its most complex form, looks as follows.@@ -105,6 +105,8 @@ movement with keyboard's keypad or `LMB` (left mouse button). If more heroes are selected (highlighted in blue), they run together whenever `:` or `S-LMB` (while holding Shift) over map area is pressed.+Any sleeping hero is highlighted in green and can be woken up+by yelling with `%`, which also taunts or stresses nearby enemies.  Next on the bottom-most status line is the leader's current and maximum Calm (morale, composure, focus, attentiveness), then his current@@ -179,12 +181,12 @@  In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair). Press `KP_5` (`5` on keypad) to wait, bracing for impact, which reduces any-damage taken and prevents displacement by foes. Press `C-KP_5` (the same key-with Control) to lurk 0.1 of a turn, without bracing and `S-KP_5` (with Shift)-or `%` to yell/yawn, taunting and waking up enemies/yourself. Displace enemies-by running into them with Shift/Control or S-LMB. Search, open, descend and-attack by bumping into walls, doors, stairs and enemies. The best melee weapon-is automatically chosen from your equipment and from among your body parts.+damage taken and prevents displacement by foes. Press `S-KP_5` or `C-KP_5`+(the same key with Shift or Control) to lurk 0.1 of a turn, without bracing.+Displace enemies by running into them with Shift/Control or S-LMB. Search,+open, descend and attack by bumping into walls, doors, stairs and enemies.+The best melee weapon is automatically chosen from your equipment+and from among your body parts.  The following commands, joined with the basic set above, let you accomplish anything in the game, though@@ -204,7 +206,7 @@     KP_* or !    cycle x-hair among enemies     KP_/ or /    cycle x-hair among items     c            close door-    +            swerve the aiming line+    %            yell/yawn  Screen area and UI mode (exploration/aiming) determine mouse click effects. First, we give an overview
GameDefinition/game-src/Client/UI/Content/Input.hs view
@@ -73,7 +73,7 @@   , ("c", ( [CmdMinimal, CmdMove]           , descTs closeDoorTriggers           , AlterDir closeDoorTriggers ))-  , ("+", ([CmdMinimal, CmdAim], "swerve the aiming line", EpsIncr True))+  , ("%", ([CmdMinimal, CmdMeta], "yell/yawn", Yell))    -- Item menu, first part of item use commands   , ("comma", grabItems "")@@ -96,7 +96,7 @@                          "and share item" False)    -- Terrain exploration and alteration-  , ("C-c", ([CmdMove], "open or close or alter", AlterDir []))+  , ("C", ([CmdMove], "open or close or alter", AlterDir []))   , ("=", ( [CmdMove], "select (or deselect) party member", SelectActor) )   , ("_", ([CmdMove], "deselect (or select) all on the level", SelectNone))   , ("semicolon", ( [CmdMove]@@ -137,7 +137,6 @@   , ("#", ( [CmdItem, CmdDashboard]           , "show skill summary of the leader"           , ChooseItemMenu MSkills ))-  , ("^", ( [CmdItem], "sort items by kind and rolled aspects", SortSlots))   , ("~", ( [CmdItem]           , "display known lore"           , ChooseItemMenu (MLore SItem) ))@@ -160,6 +159,7 @@   -- Aiming   , ("!", ([CmdAim], "", AimEnemy))   , ("/", ([CmdAim], "", AimItem))+  , ("+", ([CmdAim], "swerve the aiming line", EpsIncr True))   , ("-", ([CmdAim], "unswerve the aiming line", EpsIncr False))   , ("\\", ([CmdAim], "cycle aiming modes", AimFloor))   , ("C-?", ( [CmdAim]@@ -195,8 +195,8 @@   , ("C-V", repeatTriple 25)   , ("'", ([CmdMeta], "start recording commands", Record))   , ("C-S", ([CmdMeta], "save game backup", GameSave))+  , ("C-c", ([CmdMeta], "exit without saving", GameDrop))   , ("C-P", ([CmdMeta], "print screen", PrintScreen))-  , ("%", ([CmdMeta], "yell/yawn", Yell))    -- Dashboard, in addition to commands marked above   , ("safeD101", ([CmdInternal, CmdDashboard], "display history", AllHistory))
LambdaHack.cabal view
@@ -6,7 +6,7 @@ -- PVP summary:+-+------- breaking API changes --             | | +----- minor or non-breaking API additions --             | | | +--- code changes with no API change-version:       0.9.3.1+version:       0.9.4.0 synopsis:      A game engine library for tactical squad ASCII roguelike dungeon crawlers description:   LambdaHack is a Haskell game engine library for ASCII roguelike                games of arbitrary theme, size and complexity, with optional@@ -42,10 +42,6 @@                when developing the library --- library users are free                to access any modules, since the library authors are in                no position to guess their particular needs.-               .-               This is a workaround .cabal file, flattened to eliminated-               internal libraries until generating haddocks for them-               is fixed. The original .cabal file is stored in the github repo. homepage:      https://lambdahack.github.io bug-reports:   http://github.com/LambdaHack/LambdaHack/issues license:       BSD-3-Clause@@ -165,12 +161,9 @@   if !flag(supportNodeJS)     ghcjs-options:    -DGHCJS_BROWSER -library+library definition   import: options-  hs-source-dirs:     definition-src,-                      engine-src,-                      GameDefinition/game-src,-                      GameDefinition+  hs-source-dirs:     definition-src   exposed-modules:    Game.LambdaHack.Core.Dice                       Game.LambdaHack.Core.Frequency                       Game.LambdaHack.Core.Prelude@@ -186,7 +179,30 @@                       Game.LambdaHack.Content.PlaceKind                       Game.LambdaHack.Content.RuleKind                       Game.LambdaHack.Content.TileKind-                      Game.LambdaHack.Atomic+  build-depends:+                      ,assert-failure+                      ,base+                      ,base-compat+                      ,binary+                      ,containers+                      ,deepseq+                      ,enummapset+                      ,ghc-prim+                      ,hashable+                      ,keys+                      ,miniutter+                      ,random+                      ,time+                      ,text+                      ,transformers+                      ,unordered-containers+                      ,vector+                      ,vector-binary-instances++library+  import: options+  hs-source-dirs:     engine-src+  exposed-modules:    Game.LambdaHack.Atomic                       Game.LambdaHack.Atomic.CmdAtomic                       Game.LambdaHack.Atomic.HandleAtomicWrite                       Game.LambdaHack.Atomic.MonadStateWrite@@ -294,26 +310,25 @@                       Game.LambdaHack.Server.ServerOptions                       Game.LambdaHack.Server.StartM                       Game.LambdaHack.Server.State-  exposed-modules:    Content.CaveKind-                      Content.ItemKind-                      Content.ItemKindEmbed-                      Content.ItemKindActor-                      Content.ItemKindOrgan-                      Content.ItemKindBlast-                      Content.ItemKindTemporary-                      Content.ModeKind-                      Content.ModeKindPlayer-                      Content.PlaceKind-                      Content.RuleKind-                      Content.TileKind-                      TieKnot-                      Client.UI.Content.Input-                      Client.UI.Content.Screen-                      Implementation.MonadClientImplementation-                      Implementation.MonadServerImplementation+  reexported-modules: ,Game.LambdaHack.Core.Dice+                      ,Game.LambdaHack.Core.Frequency+                      ,Game.LambdaHack.Core.Prelude+                      ,Game.LambdaHack.Core.Random+                      ,Game.LambdaHack.Definition.Ability+                      ,Game.LambdaHack.Definition.Color+                      ,Game.LambdaHack.Definition.ContentData+                      ,Game.LambdaHack.Definition.Defs+                      ,Game.LambdaHack.Definition.Flavour+                      ,Game.LambdaHack.Content.CaveKind+                      ,Game.LambdaHack.Content.ItemKind+                      ,Game.LambdaHack.Content.ModeKind+                      ,Game.LambdaHack.Content.PlaceKind+                      ,Game.LambdaHack.Content.RuleKind+                      ,Game.LambdaHack.Content.TileKind   other-modules:      Paths_LambdaHack   autogen-modules:    Paths_LambdaHack-  build-depends:      assert-failure >= 0.1.2 && < 0.2,+  build-depends:      definition,+                      assert-failure >= 0.1.2 && < 0.2,                       async      >= 2,                       base       >= 4.10 && < 99,                       base-compat >= 0.8.0,@@ -339,9 +354,7 @@                       transformers >= 0.4,                       unordered-containers >= 0.2.3,                       vector     >= 0.11,-                      vector-binary-instances >= 0.2.3.1,-                      template-haskell >= 2.6,-                      ghc-compact+                      vector-binary-instances >= 0.2.3.1    if impl(ghcjs) || flag(jsaddle) {     exposed-modules:    Game.LambdaHack.Client.UI.Frontend.Dom@@ -372,10 +385,56 @@     build-depends:    zlib >= 0.5.3.1   } +library this-game-content+  import: options+  hs-source-dirs:     GameDefinition+  exposed-modules:    Content.CaveKind+                      Content.ItemKind+                      Content.ItemKindEmbed+                      Content.ItemKindActor+                      Content.ItemKindOrgan+                      Content.ItemKindBlast+                      Content.ItemKindTemporary+                      Content.ModeKind+                      Content.ModeKindPlayer+                      Content.PlaceKind+                      Content.RuleKind+                      Content.TileKind+  other-modules:      Paths_LambdaHack+  autogen-modules:    Paths_LambdaHack+  build-depends:      ,definition+                      ,base+                      ,filepath+                      ,template-haskell+                      ,text++library this-game-src+  import: options+  hs-source-dirs:     GameDefinition/game-src+  exposed-modules:    TieKnot+  other-modules:      Client.UI.Content.Input+                      Client.UI.Content.Screen+                      Implementation.MonadClientImplementation+                      Implementation.MonadServerImplementation+  build-depends:      ,LambdaHack+                      ,this-game-content+                      ,async+                      ,base+                      ,enummapset+                      ,filepath+                      ,ghc-compact+                      ,optparse-applicative+                      ,primitive+                      ,random+                      ,template-haskell >= 2.6+                      ,text+                      ,transformers+ executable LambdaHack   import: options, exe-options   main-is:            GameDefinition/Main.hs   build-depends:      ,LambdaHack+                      ,this-game-src                       ,async                       ,base                       ,filepath@@ -386,6 +445,7 @@   type:               exitcode-stdio-1.0   main-is:            test/test.hs   build-depends:      ,LambdaHack+                      ,this-game-src                       ,async                       ,base                       ,filepath
Makefile view
@@ -29,10 +29,10 @@ 	google-chrome --no-sandbox --js-flags="--logfile=%t.log --prof" ../lambdahack.github.io/index.html  minific:-	npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.3.1/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.3.1/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js.externs --jscomp_off="*" > ../lambdahack.github.io/lambdahack.all.js+	npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.4.0/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.4.0/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js.externs --jscomp_off="*" > ../lambdahack.github.io/lambdahack.all.js  minificForNode:-	npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.3.1/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.3.1/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js.externs --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/assert.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/child_process.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/crypto.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dns.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/events.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/globals.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/https.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/os.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/punycode.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/readline.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/stream.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tls.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/url.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/vm.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/buffer.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/cluster.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dgram.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/domain.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/fs.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/http.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/net.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/path.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/querystring.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/repl.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/string_decoder.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tty.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/util.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/zlib.js --jscomp_off="*" > ../lambdahack.github.io/lambdahack.all.js+	npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.4.0/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/LambdaHack-0.9.4.0/x/LambdaHack/build/LambdaHack/LambdaHack.jsexe/all.js.externs --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/assert.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/child_process.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/crypto.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dns.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/events.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/globals.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/https.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/os.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/punycode.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/readline.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/stream.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tls.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/url.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/vm.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/buffer.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/cluster.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dgram.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/domain.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/fs.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/http.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/net.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/path.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/querystring.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/repl.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/string_decoder.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tty.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/util.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/zlib.js --jscomp_off="*" > ../lambdahack.github.io/lambdahack.all.js  # Low delay to display animations swiftly and not bore the public too much. # Delay can't be lower than 2, because browsers sometimes treat delay 1@@ -241,8 +241,8 @@  build-binary-common: 	mkdir -p LambdaHackTheGame/GameDefinition/fonts-	cabal v1-install --force-reinstalls --disable-library-profiling --disable-profiling --disable-documentation --only-dependencies-	cabal v1-configure --disable-library-profiling --disable-profiling --prefix=/ --datadir=. --datasubdir=.+	cabal v1-install --force-reinstalls --disable-library-profiling --disable-profiling --disable-documentation --enable-optimization --only-dependencies+	cabal v1-configure --disable-library-profiling --disable-profiling --enable-optimization --prefix=/ --datadir=. --datasubdir=. 	cabal v1-build exe:LambdaHack 	cabal v1-copy --destdir=LambdaHackTheGameInstall 	([ -f "LambdaHackTheGameInstall/bin/LambdaHack" ] && mv LambdaHackTheGameInstall/bin/LambdaHack LambdaHackTheGame) || exit 0
engine-src/Game/LambdaHack/Atomic/CmdAtomic.hs view
@@ -34,6 +34,7 @@ import           Game.LambdaHack.Common.Item import qualified Game.LambdaHack.Common.ItemAspect as IA import           Game.LambdaHack.Common.Perception+import           Game.LambdaHack.Common.Point import           Game.LambdaHack.Common.ReqFailure import           Game.LambdaHack.Common.State import           Game.LambdaHack.Common.Time@@ -44,7 +45,6 @@ import qualified Game.LambdaHack.Content.PlaceKind as PK import           Game.LambdaHack.Content.TileKind (TileKind) import qualified Game.LambdaHack.Core.Dice as Dice-import           Game.LambdaHack.Common.Point import qualified Game.LambdaHack.Definition.Ability as Ability import           Game.LambdaHack.Definition.Defs @@ -152,7 +152,6 @@   | SfxEffect FactionId ActorId IK.Effect Int64   | SfxMsgFid FactionId SfxMsg   | SfxRestart-  | SfxSortSlots   | SfxCollideTile ActorId Point   | SfxTaunt Bool ActorId   deriving Show@@ -169,6 +168,7 @@   | SfxSummonLackCalm ActorId   | SfxSummonTooManyOwn ActorId   | SfxSummonTooManyAll ActorId+  | SfxSummonFailure ActorId   | SfxLevelNoMore   | SfxLevelPushed   | SfxBracedImmune ActorId@@ -266,7 +266,6 @@   SfxEffect{} -> cmd  -- not ideal?   SfxMsgFid{} -> cmd   SfxRestart -> cmd-  SfxSortSlots -> cmd   SfxCollideTile{} -> cmd   SfxTaunt{} -> cmd 
engine-src/Game/LambdaHack/Atomic/PosAtomicRead.hs view
@@ -25,9 +25,9 @@ import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.MonadStateRead import Game.LambdaHack.Common.Perception+import Game.LambdaHack.Common.Point import Game.LambdaHack.Common.State import Game.LambdaHack.Common.Types-import Game.LambdaHack.Common.Point import Game.LambdaHack.Definition.Defs  -- All functions here that take an atomic action are executed@@ -187,7 +187,6 @@   SfxEffect _ aid _ _ -> singleAid aid  -- sometimes we don't see source, OK   SfxMsgFid fid _ -> return $! PosFid fid   SfxRestart -> return PosAll-  SfxSortSlots -> return PosAll   SfxCollideTile aid _ -> singleAid aid   SfxTaunt _ aid -> singleAid aid 
engine-src/Game/LambdaHack/Client/UI/Content/Input.hs view
@@ -47,8 +47,6 @@ makeData UIOptions{uCommands, uVi, uLaptop} (InputContentRaw copsClient) =   let waitTriple = ([CmdMove], "", Wait)       wait10Triple = ([CmdMove], "", Wait10)-      yellTriple = ([CmdMove], "", Yell)-      yellTripleNoHelp = ([CmdNoHelp], "", Yell)       moveXhairOr n cmd v = ByAimMode $ AimModeCmd { exploration = cmd v                                                    , aiming = MoveXhair v n }       bcmdList =@@ -60,7 +58,7 @@         ++ uCommands         ++ [ (K.mkKM "KP_Begin", waitTriple)            , (K.mkKM "C-KP_Begin", wait10Triple)-           , (K.mkKM "KP_5", yellTripleNoHelp)+           , (K.mkKM "KP_5", wait10Triple)            , (K.mkKM "C-KP_5", wait10Triple) ]         ++ (if | uVi ->                  [ (K.mkKM "period", waitTriple)@@ -68,7 +66,7 @@                | uLaptop ->                  [ (K.mkKM "i", waitTriple)                  , (K.mkKM "C-i", wait10Triple)-                 , (K.mkKM "I", yellTriple) ]+                 , (K.mkKM "I", wait10Triple) ]                | otherwise ->                  [])         ++ K.moveBinding uVi uLaptop
engine-src/Game/LambdaHack/Client/UI/DisplayAtomicM.hs view
@@ -8,7 +8,8 @@   , aidVerbMU, aidVerbMU0, aidVerbDuplicateMU   , itemVerbMU, itemAidVerbMU   , createActorUI, destroyActorUI, spotItem, moveActor, displaceActorUI-  , moveItemUI, quitFactionUI, displayGameOverLoot, displayGameOverAnalytics+  , moveItemUI, quitFactionUI+  , displayGameOverLoot, displayGameOverAnalytics   , discover, ppSfxMsg, strike #endif   ) where@@ -95,7 +96,7 @@     recordItemLid iid c     updateItemSlot c iid     case c of-      CActor aid store ->+      CActor aid store -> do         case store of           COrgan -> do             arItem <- getsState $ aspectRecordFromIid iid@@ -459,26 +460,14 @@ updateItemSlot :: MonadClientUI m => Container -> ItemId -> m () updateItemSlot c iid = do   arItem <- getsState $ aspectRecordFromIid iid+  ItemSlots itemSlots <- getsSession sslots   let slore = IA.loreFromContainer arItem c-      incrementPrefix l2 iid2 m = EM.insert l2 iid2 $-        case EM.lookup l2 m of-          Nothing -> m-          Just iidOld ->-            let lNew = SlotChar (slotPrefix l2 + 1) (slotChar l2)-            in incrementPrefix lNew iidOld m-  slots@(ItemSlots itemSlots) <- getsSession sslots-  case lookup iid $ map swap $ EM.assocs $ itemSlots EM.! slore of+      lSlots = itemSlots EM.! slore+  case lookup iid $ map swap $ EM.assocs lSlots of     Nothing -> do-      side <- getsClient sside-      mbody <- case c of-        CActor aid _ -> do-          b <- getsState $ getActorBody aid-          return $! if bfid b == side then Just b else Nothing-        _ -> return Nothing-      partySet <- getsState $ partyItemSet slore side mbody-      let l = assignSlot partySet slore slots-          newSlots =-            ItemSlots $ EM.adjust (incrementPrefix l iid) slore itemSlots+      let l = assignSlot lSlots+          f = EM.insert l iid+          newSlots = ItemSlots $ EM.adjust f slore itemSlots       modifySession $ \sess -> sess {sslots = newSlots}     Just _l -> return ()  -- slot already assigned @@ -648,7 +637,7 @@            let c = if not (bproj body) && iid == btrunk body                    then CTrunk (bfid body) (blid body) (bpos body)                    else CActor aid store-           void $ updateItemSlot c iid+           updateItemSlot c iid            recordItemLid iid c)         ((btrunk body, CEqp)  -- store will be overwritten, unless projectile          : filter ((/= btrunk body) . fst) (getCarriedIidCStore body))@@ -725,7 +714,7 @@   let slore = IA.loreFromContainer arItem c   case lookup iid $ map swap $ EM.assocs $ itemSlots EM.! slore of     Nothing -> do  -- never seen or would have a slot-      void $ updateItemSlot c iid+      updateItemSlot c iid       case c of         CFloor lid p -> do           sxhairOld <- getsSession sxhair@@ -837,6 +826,7 @@     tellGameClipPS     resetGameStart   mode <- getGameMode+  allNframes <- getsSession sallNframes   let startingPart = case toSt of         _ | horror -> Nothing  -- Ignore summoned actors' factions.         Just Status{stOutcome=Killed} -> Just "be eliminated"@@ -855,7 +845,7 @@         Just Status{stOutcome} -> lookup stOutcome $ mendMsg mode         Nothing -> Nothing       partingPart = case toSt of-        _ | fid /= side -> Nothing+        _ | fid /= side || allNframes == -1 -> Nothing         Just Status{stOutcome} -> lookup stOutcome genericEndMessages         Nothing -> Nothing   case startingPart of@@ -876,8 +866,28 @@       when go $ do         case middlePart of           Nothing -> return ()-          Just sp -> do-            msgAdd0 MsgPlot sp+          Just sp1 -> do+            factionD <- getsState sfactionD+            itemToF <- getsState $ flip itemToFull+            let getTrunkFull (_, b) = itemToF $ btrunk b+            ourTrunks <- getsState $ map getTrunkFull+                                     . fidActorNotProjGlobalAssocs side+            let smartFaction fact2 = fleaderMode (gplayer fact2) /= LeaderNull+                smartEnemy trunkFull =+                  any (smartFaction . snd)+                  $ filter (\(fid2, _) -> fid2 /= side)+                  $ possibleActorFactions (itemKind trunkFull) factionD+                smartEnemyOurs = filter smartEnemy ourTrunks+                uniqueActor trunkFull = IA.checkFlag Ability.Unique+                                        $ aspectRecordFull trunkFull+                smartUniqueEnemyCaptured = any uniqueActor smartEnemyOurs+                smartEnemyCaptured = not $ null smartEnemyOurs+                sp2 | smartUniqueEnemyCaptured =+                  "\nOh, wait, who is this, towering behind your escaping crew? This changes everything. For everybody. Everywhere. Forever. Did you plan for this? What was exactly the idea and who decided to carry it through?"+                    | smartEnemyCaptured =+                  "\nOh, wait, who is this, hunched among your escaping crew? Suddenly, this makes your crazy story credible. Suddenly, the door of knowledge opens again. How will you play that move?"+                    | otherwise = ""+            msgAdd0 MsgPlot $ sp1 <> sp2             void $ displaySpaceEsc ColorFull ""         case manalytics of           Nothing -> return ()@@ -947,7 +957,7 @@                     then "Non-positive count means none held but this many generated."                     else "")       examItem = displayItemLore itemBag 0 promptFun-  viewLoreItems False "GameOverLoot" lSlots itemBag prompt examItem+  viewLoreItems "GameOverLoot" lSlots itemBag prompt examItem  displayGameOverAnalytics :: MonadClientUI m                          => FactionAnalytics -> GenerationAnalytics@@ -986,7 +996,7 @@                     then "Non-positive count means none killed but this many reported."                     else "")       examItem = displayItemLore trunkBag 0 promptFun-  viewLoreItems False "GameOverAnalytics" lSlots trunkBag prompt examItem+  viewLoreItems "GameOverAnalytics" lSlots trunkBag prompt examItem  displayGameOverLore :: MonadClientUI m                     => SLore -> Bool -> GenerationAnalytics -> m K.KM@@ -1009,7 +1019,7 @@                makeSentence [ "you experienced the following variety of"                             , MU.CarWs total $ MU.Text (headingSLore slore) ]       examItem = displayItemLore generationBag 0 promptFun-  viewLoreItems False ("GameOverLore" ++ show slore)+  viewLoreItems ("GameOverLore" ++ show slore)                 slots generationBag prompt examItem  discover :: MonadClientUI m => Container -> ItemId -> m ()@@ -1220,14 +1230,10 @@         IK.Escape{} | isOurCharacter -> do           ours <- getsState $ fidActorNotProjGlobalAssocs side           when (length ours > 1) $ do-            -- TODO: only say farewell if nonstandard dominated actors-            -- in the team. Also react to the only surviving actor being such.-            let farewells = ", says its farewells"-                object = partActor bUI+            let object = partActor bUI             msgAdd MsgOutcome $               "The team joins" <+> makePhrase [object]-              <> ", forms a perimeter, repacks its belongings"-              <> farewells <+> "and leaves triumphant."+              <> ", forms a perimeter, repacks its belongings and leaves triumphant."         IK.Escape{} -> return ()         IK.Paralyze{} -> aidVerbMU MsgEffect aid "be paralyzed"         IK.ParalyzeInWater{} ->@@ -1272,7 +1278,8 @@               object = MU.Ws $ MU.Text $ detectToObject d           msgAdd MsgEffectMinor $             makeSentence [MU.SubjectVerbSg subject verb, object]-          unless (d == IK.DetectHidden) $  -- too common and too weak+          -- Don't make it modal if all info remains after no longer seen.+          unless (d `elem` [IK.DetectHidden, IK.DetectExit]) $             displayMore ColorFull ""         IK.SendFlying{} -> aidVerbMU MsgEffect aid "be sent flying"         IK.PushActor{} -> aidVerbMU MsgEffect aid "be pushed"@@ -1300,7 +1307,6 @@       Just (msgClass, msg) -> msgAdd msgClass msg       Nothing -> return ()   SfxRestart -> fadeOutOrIn True-  SfxSortSlots -> sortSlots   SfxCollideTile source pos -> do     COps{cotile} <- getsState scops     sb <- getsState $ getActorBody source@@ -1360,6 +1366,14 @@         let subject = partActor sbUI             verb = "can't keep track of everybody around, let alone summon anyone else"         return $ Just (MsgWarning, makeSentence [subject, verb])+  SfxSummonFailure aid -> do+    msbUI <- getsSession $ EM.lookup aid . sactorUI+    case msbUI of+      Nothing -> return Nothing+      Just sbUI -> do+        let subject = partActor sbUI+            verb = "fail to summon anything"+        return $ Just (MsgWarning, makeSentence [MU.SubjectVerbSg subject verb])   SfxLevelNoMore ->     return $ Just (MsgWarning, "No more levels in this direction.")   SfxLevelPushed ->
engine-src/Game/LambdaHack/Client/UI/DrawM.hs view
@@ -308,15 +308,13 @@               leaderColor = if isJust saimMode                             then Color.HighlightYellowAim                             else Color.HighlightYellow-              bg = case mleader of-                Just leader | aid == leader -> leaderColor-                _ -> if | bwatch == WSleep -> Color.HighlightGreen-                        | aid `ES.member` sselected -> Color.HighlightBlue-                        | dominated -> if bfid == side  -- dominated by us-                                       then Color.HighlightWhite-                                       else Color.HighlightMagenta-                        | bwatch == WSleep -> Color.HighlightGreen-                        | otherwise -> Color.HighlightNone+              bg = if | mleader == Just aid -> leaderColor+                      | bwatch == WSleep -> Color.HighlightGreen+                      | dominated -> if bfid == side  -- dominated by us+                                     then Color.HighlightWhite+                                     else Color.HighlightMagenta+                      | ES.member aid sselected -> Color.HighlightBlue+                      | otherwise -> Color.HighlightNone               fg | bfid /= side || bhp <= 0 = bcolor                  | otherwise =                 let (hpCheckWarning, calmCheckWarning) =@@ -712,9 +710,13 @@                       . inline actorAssocs (== side) drawnLevelId   let oursUI = map (\(aid, b) -> (aid, b, sactorUI EM.! aid)) ours       viewOurs (aid, Actor{bhp, bwatch}, ActorUI{bsymbol, bcolor}) =+        -- Sleep considered before being selected, because sleeping+        -- actors can't move, so selection is mostly irrelevant.+        -- Domination not considered at all, because map already shows it+        -- and so here is the only place where selection is conveyed.         let bg = if | mleader == Just aid -> Color.HighlightYellow-                    | ES.member aid selected -> Color.HighlightBlue                     | bwatch == WSleep -> Color.HighlightGreen+                    | ES.member aid selected -> Color.HighlightBlue                     | otherwise -> Color.HighlightNone             sattr = Color.Attr {Color.fg = bcolor, bg}         in Color.attrCharToW32 $ Color.AttrChar sattr
engine-src/Game/LambdaHack/Client/UI/Frontend/Curses.hs view
@@ -91,7 +91,7 @@             , (x, Color.AttrChar{acAttr=Color.Attr{..}, ..}) <- line             , let acAttr2 = case bg of                     Color.HighlightNone -> (fg, Color.Black)-                    Color.HighlightGreen -> (fg, Color.Black)+                    Color.HighlightGreen -> (fg, Color.Black)  -- too few bgs                     Color.HighlightBlue ->                       if fg /= Color.Blue                       then (fg, Color.Blue)
engine-src/Game/LambdaHack/Client/UI/Frontend/Gtk.hs view
@@ -51,7 +51,10 @@   -- Text attributes.   let emulateBox Color.Attr{..} = case bg of         Color.HighlightNone -> (fg, Color.Black)-        Color.HighlightGreen -> (fg, Color.Black)+        Color.HighlightGreen ->+          if fg /= Color.Green+          then (fg, Color.Green)+          else (fg, Color.BrBlack)         Color.HighlightBlue ->           if fg /= Color.Blue           then (fg, Color.Blue)@@ -66,7 +69,7 @@           if fg /= Color.Red           then (fg, Color.Red)           else (fg, Color.defFG)-        Color.HighlightYellow -> (Color.Black, Color.defFG)+        Color.HighlightYellow -> (Color.Black, Color.defFG)  -- no cursor         Color.HighlightYellowAim -> (Color.Black, Color.defFG)         Color.HighlightRedAim ->           if fg /= Color.Red
engine-src/Game/LambdaHack/Client/UI/Frontend/Vty.hs view
@@ -19,6 +19,7 @@ import qualified Game.LambdaHack.Client.UI.Key as K import           Game.LambdaHack.Common.Point import qualified Game.LambdaHack.Common.PointArray as PointArray+import           Game.LambdaHack.Content.TileKind (floorSymbol) import qualified Game.LambdaHack.Definition.Color as Color  -- | Session data maintained by the frontend.@@ -56,7 +57,7 @@   let img = foldr (<->) emptyImage             . map (foldr (<|>) emptyImage                      . map (\w -> char (setAttr $ Color.attrFromW32 w)-                                       (Color.charFromW32 w)))+                                       (squashChar $ Color.charFromW32 w)))             $ chunk $ PointArray.toListA singleFrame       pic1 = picForImage img       Point{..} = PointArray.maxIndexByA (comparing Color.bgFromW32) singleFrame@@ -86,7 +87,7 @@     KBegin        -> K.Begin     KCenter       -> K.Begin     KIns          -> K.Insert-    -- C-Home and C-End are the same in vty as Home and End+    -- S-KP_5 and C-KP_5 are still not correctly handled in vty     -- on some terminals so we have to use 1--9 for movement instead of     -- leader change.     (KChar c)@@ -114,7 +115,10 @@ --  else   let (fg1, bg1) = case bg of         Color.HighlightNone -> (fg, Color.Black)-        Color.HighlightGreen -> (fg, Color.Black)+        Color.HighlightGreen ->+          if fg /= Color.Green+          then (fg, Color.Green)+          else (fg, Color.BrBlack)         Color.HighlightBlue ->           if fg /= Color.Blue           then (fg, Color.Blue)@@ -129,7 +133,7 @@           if fg /= Color.Red           then (fg, Color.Red)           else (fg, Color.defFG)-        Color.HighlightYellow -> (fg, Color.Black)+        Color.HighlightYellow -> (fg, Color.Black)  -- cursor used instead         Color.HighlightYellowAim -> (Color.Black, Color.defFG)         Color.HighlightRedAim ->           if fg /= Color.Red@@ -138,6 +142,9 @@   in hack fg1 $ hack bg1 $        defAttr { attrForeColor = SetTo (aToc fg1)                , attrBackColor = SetTo (aToc bg1) }++squashChar :: Char -> Char+squashChar c = if c == floorSymbol then '.' else c  aToc :: Color.Color -> Color aToc Color.Black     = black
engine-src/Game/LambdaHack/Client/UI/HandleHelperM.hs view
@@ -1,7 +1,7 @@ -- | Helper functions for both inventory management and human commands. module Game.LambdaHack.Client.UI.HandleHelperM   ( FailError, showFailError, MError, mergeMError, FailOrCmd, failWith-  , failSer, failMsg, weaveJust, sortSlots+  , failSer, failMsg, weaveJust   , memberCycle, memberBack, partyAfterLeader, pickLeader, pickLeaderWithPointer   , itemOverlay, skillsOverlay, placesFromState, placeParts, placesOverlay   , pickNumber, lookAtItems, lookAtPosition@@ -30,7 +30,6 @@ import           Game.LambdaHack.Client.UI.Content.Screen import           Game.LambdaHack.Client.UI.ContentClientUI import           Game.LambdaHack.Client.UI.EffectDescription-import qualified Game.LambdaHack.Client.UI.HumanCmd as HumanCmd import           Game.LambdaHack.Client.UI.ItemDescription import           Game.LambdaHack.Client.UI.ItemSlot import qualified Game.LambdaHack.Client.UI.Key as K@@ -94,13 +93,6 @@ weaveJust (Left ferr) = Left $ Just ferr weaveJust (Right a) = Right a -sortSlots :: MonadClientUI m => m ()-sortSlots = do-  itemToF <- getsState $ flip itemToFull-  ItemSlots itemSlots <- getsSession sslots-  let newSlots = ItemSlots $ EM.map (sortSlotMap itemToF) itemSlots-  modifySession $ \sess -> sess {sslots = newSlots}- -- | Switches current member to the next on the level, if any, wrapping. memberCycle :: MonadClientUI m => Bool -> m MError memberCycle verbose = do@@ -613,23 +605,15 @@     _ -> error $ "" `showFailure` km  viewLoreItems :: MonadClientUI m-              => Bool -> String -> SingleItemSlots -> ItemBag -> Text+              => String -> SingleItemSlots -> ItemBag -> Text               -> (Int -> SingleItemSlots -> m Bool)               -> m K.KM-viewLoreItems enableSorting menuName lSlotsRaw trunkBag prompt examItem = do+viewLoreItems menuName lSlotsRaw trunkBag prompt examItem = do   CCUI{coscreen=ScreenContent{rheight}} <- getsSession sccui   arena <- getArenaUI-  revCmd <- revCmdMap   itemToF <- getsState $ flip itemToFull-  let caretKey = revCmd (K.KM K.NoModifier $ K.Char '^')-                        HumanCmd.SortSlots-      keysPre = [K.spaceKM, K.mkChar '/', K.mkChar '?', K.escKM]-                ++ [caretKey | enableSorting]-      -- Here, unlike for inventory items, slots are not sorted persistently-      -- and only for the single slot category.-      lSlots = if enableSorting-               then lSlotsRaw-               else sortSlotMap itemToF lSlotsRaw+  let keysPre = [K.spaceKM, K.mkChar '/', K.mkChar '?', K.escKM]+      lSlots = sortSlotMap itemToF lSlotsRaw   promptAdd0 prompt   io <- itemOverlay lSlots arena trunkBag   itemSlides <- overlayToSlideshow (rheight - 2) keysPre io@@ -642,17 +626,13 @@                             (findIndex (== slot) $ EM.keys lSlots)         go2 <- examItem ix0 lSlots         if go2-        then viewLoreItems enableSorting menuName lSlots-                           trunkBag prompt examItem+        then viewLoreItems menuName lSlots trunkBag prompt examItem         else return K.escKM   ekm <- displayChoiceScreen menuName ColorFull False itemSlides keysMain   case ekm of     Left km | km == K.spaceKM -> return km     Left km | km == K.mkChar '/' -> return km     Left km | km == K.mkChar '?' -> return km-    Left km | km == caretKey ->-      viewLoreItems False menuName (sortSlotMap itemToF lSlotsRaw)-                    trunkBag prompt examItem     Left km | km == K.escKM -> return km     Left K.KM{key=K.Char l} -> viewAtSlot $ SlotChar 0 l       -- other prefixes are not accessible via keys; tough luck; waste of effort@@ -678,7 +658,7 @@ spoilsBlurb :: Text -> Int -> Int -> Text spoilsBlurb currencyName total dungeonTotal =   if | dungeonTotal == 0 ->  "All your spoils are of the practical kind."-     | total == 0 -> "You haven't found any genuine treasure."+     | total == 0 -> "You haven't found any genuine treasure yet."      | otherwise -> makeSentence          [ "your spoils are worth"          , MU.CarAWs total $ MU.Text currencyName
engine-src/Game/LambdaHack/Client/UI/HandleHumanGlobalM.hs view
@@ -19,7 +19,7 @@   , mainMenuHuman, settingsMenuHuman, challengesMenuHuman   , gameScenarioIncr, gameDifficultyIncr, gameWolfToggle, gameFishToggle     -- * Global commands that never take time-  , gameRestartHuman, gameExitHuman, gameSaveHuman+  , gameRestartHuman, gameDropHuman, gameExitHuman, gameSaveHuman   , tacticHuman, automateHuman #ifdef EXPOSE_INTERNAL     -- * Internal operations@@ -491,7 +491,10 @@            promptAdd0 blurb            failSer AlterUnwalked        | not $ Tile.isModifiable coTileSpeedup t || canApplyEmbeds -> do-           -- Rather rare (charging embeds), so describe the tile.+           -- Rather rare (charging embeds or too low skill for embeds+           -- that are, e.g., `?`), so describe the tile.+           -- Unfortunately this includes cases when an actor can exploit+           -- signboard when hidden, but can't later on when revealed.            promptAdd0 blurb            failWith "unable to exploit the terrain"        | EM.member tpos $ lfloor lvl -> failSer AlterBlockItem@@ -501,7 +504,7 @@        | otherwise -> do  -- promising            verAlters <- verifyAlters (blid sb) tpos            case verAlters of-             Right() -> return $ Right $ ReqAlter tpos+             Right () -> return $ Right $ ReqAlter tpos              Left err -> return $ Left err            -- We don't use ReqMove, because we don't hit invisible actors,            -- e.g., hidden in a wall. If server performed an attack for free@@ -850,7 +853,7 @@           Left reqFail -> failSer reqFail           Right (pos, _) -> do             Benefit{benFling} <- getsClient $ (EM.! iid) . sdiscoBenefit-            go <- if benFling >= 0+            go <- if benFling > 0                   then displayYesNo ColorFull                          "The item appears beneficial. Do you really want to fling it?"                   else return True@@ -913,7 +916,7 @@              -- but price low, due to no destruction.              displayYesNo ColorFull                           "Applying this periodic item will produce only the first of its effects and moreover, because it's not durable, will destroy it. Are you sure?"-           | benApply <= 0 ->+           | benApply < 0 ->              displayYesNo ColorFull                           "The item appears harmful. Do you really want to apply it?"            | otherwise -> return True@@ -1002,7 +1005,7 @@                 tr : _ -> ttverb tr           verAlters <- verifyAlters (blid b) tpos           case verAlters of-            Right() -> do+            Right () -> do               let msg = makeSentence ["you", v, MU.Text pText]               msgAdd MsgDone msg               return $ Right $ ReqAlter tpos@@ -1033,22 +1036,25 @@   fact <- getsState $ (EM.! side) . sfactionD   if not (fcanEscape $ gplayer fact)   then failWith-        "This is the way out, but where would you go in this alien world?"+         "This is the way out, but where would you go in this alien world?"   else do-    go <- displayYesNo ColorFull "This is the way out. Really leave now?"-    if not go then failWith "game resumed"-    else do-      (_, total) <- getsState $ calculateTotal side-      dungeonTotal <- getsState sgold-      if total == 0 && dungeonTotal > 0 then do-        -- The player can back off at this step. We don't insist, because-        -- possibly the score formula doesn't reward treasure.-        go1 <- displaySpaceEsc ColorBW-          "Afraid of the challenge? Leaving so soon and without any treasure?"-        if not go1-        then failWith "here's your chance!"-        else return $ Right ()-      else return $ Right ()+    (_, total) <- getsState $ calculateTotal side+    dungeonTotal <- getsState sgold+    let prompt | dungeonTotal == 0 =+                 "You finally reached the way out. Really leave now?"+               | total == 0 =+                 "Afraid of the challenge? Leaving so soon and without any treasure? Are you sure?"+               | total < dungeonTotal =+                 "You finally found the way out, but still more valuables are rumoured to hide around here. Really leave already?"+               | otherwise =+                 "This is the way out and you collected all treasure there is to find. Really leave now?"+    -- The player can back off, but we never insist,+    -- because possibly the score formula doesn't reward treasure+    -- or he is focused on winning only.+    go <- displayYesNo ColorBW prompt+    if not go+    then failWith "here's your chance!"+    else return $ Right ()  -- | Guess and report why the bump command failed. guessAlter :: COps -> [TriggerTile] -> ContentId TileKind -> Text@@ -1519,6 +1525,16 @@   let f !acc _p _i !a = a : acc       campaignModes = ofoldlGroup' comode "campaign scenario" f []   in campaignModes !! (snxtScenario `mod` length campaignModes)++-- * GameDrop++gameDropHuman :: MonadClientUI m => m ReqUI+gameDropHuman = do+  modifySession $ \sess -> sess {sallNframes = -1}  -- hack, but we crash anyway+  promptAdd0 "Interrupt! Trashing the unsaved game. The program exits now."+  clientPrintUI "Interrupt! Trashing the unsaved game. The program exits now."+    -- this is not shown by vty frontend, but at least shown by sdl2 one+  return ReqUIGameDropAndExit  -- * GameExit 
engine-src/Game/LambdaHack/Client/UI/HandleHumanLocalM.hs view
@@ -6,7 +6,7 @@   ( -- * Meta commands     macroHuman     -- * Local commands-  , sortSlotsHuman, chooseItemHuman, chooseItemDialogMode+  , chooseItemHuman, chooseItemDialogMode   , chooseItemProjectHuman, chooseItemApplyHuman   , psuitReq, triggerSymbols, pickLeaderHuman, pickLeaderWithPointerHuman   , memberCycleHuman, memberBackHuman@@ -90,13 +90,6 @@ macroHuman kms = do   modifySession $ \sess -> sess {slastPlay = map K.mkKM kms ++ slastPlay sess}   msgAdd MsgMacro $ "Macro activated:" <+> T.pack (intercalate " " kms)---- * SortSlots--sortSlotsHuman :: MonadClientUI m => m ()-sortSlotsHuman = do-  sortSlots-  promptAdd "Items sorted by kind and rolled aspects."  -- * ChooseItem 
engine-src/Game/LambdaHack/Client/UI/HandleHumanM.hs view
@@ -102,12 +102,12 @@   GameScenarioIncr -> gameScenarioIncr >> mainMenuHuman cmdAction    GameRestart -> weaveJust <$> gameRestartHuman+  GameDrop -> weaveJust <$> fmap Right gameDropHuman   GameExit -> weaveJust <$> fmap Right gameExitHuman   GameSave -> weaveJust <$> fmap Right gameSaveHuman   Tactic -> weaveJust <$> tacticHuman   Automate -> weaveJust <$> automateHuman -  SortSlots -> addNoError sortSlotsHuman   ChooseItem dialogMode -> Left <$> chooseItemHuman dialogMode   ChooseItemProject ts -> Left <$> chooseItemProjectHuman ts   ChooseItemApply ts -> Left <$> chooseItemApplyHuman ts
engine-src/Game/LambdaHack/Client/UI/HumanCmd.hs view
@@ -137,12 +137,12 @@   | GameFishToggle   | GameScenarioIncr   | GameRestart+  | GameDrop   | GameExit   | GameSave   | Tactic   | Automate     -- Local. Below this line, commands do not notify the server.-  | SortSlots   | ChooseItem ItemDialogMode   | ChooseItemMenu ItemDialogMode   | ChooseItemProject [TriggerItem]
engine-src/Game/LambdaHack/Client/UI/InventoryM.hs view
@@ -240,7 +240,7 @@ transition psuit prompt promptGeneric permitMulitple cLegal            numPrefix cCur cRest itemDialogState = do   let recCall = transition psuit prompt promptGeneric permitMulitple cLegal-  ItemSlots itemSlots <- getsSession sslots+  ItemSlots itemSlotsPre <- getsSession sslots   leader <- getLeaderUI   body <- getsState $ getActorBody leader   bodyUI <- getsSession $ getActorUI leader@@ -253,21 +253,35 @@   mpsuit <- psuit  -- when throwing, this sets eps and checks xhair validity   psuitFun <- case mpsuit of     SuitsEverything -> return $ \_ _ -> True-    SuitsSomething f -> return f-      -- When throwing, this function takes missile range into accout.+    SuitsSomething f -> return f  -- When throwing, this function takes+                                  -- missile range into accout.+  -- This is the only place slots are sorted. As a side-effect,+  -- slots in inventories always agree with slots of item lore.+  -- Not so for organ menu, because many lore maps point there.+  -- Sorting in @updateItemSlot@ would not be enough, because, e.g.,+  -- identifying an item should change its slot position.+  lSlots <- case cCur of+    MOrgans -> do+      let newSlots = EM.adjust (sortSlotMap itemToF) SOrgan+                     $ EM.adjust (sortSlotMap itemToF) STrunk+                     $ EM.adjust (sortSlotMap itemToF) SCondition itemSlotsPre+      modifySession $ \sess -> sess {sslots = ItemSlots newSlots}+      return $! mergeItemSlots itemToF [ newSlots EM.! SOrgan+                                       , newSlots EM.! STrunk+                                       , newSlots EM.! SCondition ]+    MSkills -> return EM.empty+    MPlaces -> return EM.empty+    _ -> do+      let slore = IA.loreFromMode cCur+          newSlots = EM.adjust (sortSlotMap itemToF) slore itemSlotsPre+      modifySession $ \sess -> sess {sslots = ItemSlots newSlots}+      return $! newSlots EM.! slore   let getResult :: Either K.KM SlotChar -> [ItemId]                 -> ( Either Text ([ItemId], ItemBag, SingleItemSlots)                    , (ItemDialogMode, Either K.KM SlotChar) )       getResult ekm iids = (Right (iids, bagAll, bagItemSlotsAll), (cCur, ekm))       filterP iid = psuitFun (itemToF iid)       bagAllSuit = EM.filterWithKey filterP bagAll-      lSlots = case cCur of-        MOrgans -> mergeItemSlots itemToF [ itemSlots EM.! SOrgan-                                          , itemSlots EM.! STrunk-                                          , itemSlots EM.! SCondition ]-        MSkills -> EM.empty-        MPlaces -> EM.empty-        _ -> itemSlots EM.! IA.loreFromMode cCur       bagItemSlotsAll = EM.filter (`EM.member` bagAll) lSlots       -- Predicate for slot matching the current prefix, unless the prefix       -- is 0, in which case we display all slots, even if they require@@ -348,17 +362,6 @@                    recCall numPrefix cCurUpd cRestUpd itemDialogState                  Just{} -> return (Left "not a teammate", (cCur, ekm))                              -- don't inspect the error, it's expected-           })-        , let km = revCmd (K.KM K.NoModifier $ K.Char '^') SortSlots-          in (km, DefItemKey-           { defLabel = Right km-           , defCond = cCur /= MOrgans  -- auto-sorted each time-                       && cCur /= MSkills  -- artificial slots-                       && cCur /= MPlaces  -- artificial slots-                       && EM.size bagFiltered > 1  -- no feedback-           , defAction = \_ -> do-               sortSlots-               recCall numPrefix cCur cRest itemDialogState            })         , (K.escKM, DefItemKey            { defLabel = Right K.escKM
engine-src/Game/LambdaHack/Client/UI/ItemSlot.hs view
@@ -69,19 +69,16 @@   <> ")"  -- | Assigns a slot to an item, e.g., for inclusion in the inventory of a hero.-assignSlot :: ES.EnumSet ItemId -> SLore -> ItemSlots -> SlotChar-assignSlot partySet slore (ItemSlots itemSlots) =-  head $ freeLowPrefix ++ free- where-  lSlots = itemSlots EM.! slore-  maxPrefix = case EM.maxViewWithKey lSlots of-    Just ((lm, _), _) -> slotPrefix lm-    Nothing -> 0-  slotsUpTo k = concatMap (\n -> map (SlotChar n) allChars) [0..k]-  f l = maybe True (`ES.notMember` partySet) $ EM.lookup l lSlots-  free = filter f $ slotsUpTo (maxPrefix + 1)  -- suffices-  g l = l {slotPrefix = maxPrefix} `EM.notMember` lSlots-  freeLowPrefix = filter g free+-- At first, e.g., when item is spotted on the floor, the slot is+-- not user-friendly. After any player's item manipulation action,+-- slots are sorted and a fully human-readable slot is then assigned.+-- Only then the slot can be viewed by the player.+assignSlot :: SingleItemSlots -> SlotChar+assignSlot lSlots =+  let maxPrefix = case EM.maxViewWithKey lSlots of+        Just ((lm, _), _) -> slotPrefix lm+        Nothing -> 0+  in SlotChar (maxPrefix + 1) 'x'  partyItemSet :: SLore -> FactionId -> Maybe Actor -> State -> ES.EnumSet ItemId partyItemSet slore fid mbody s =
engine-src/Game/LambdaHack/Common/Faction.hs view
@@ -23,14 +23,14 @@ import qualified Data.IntMap.Strict as IM import           GHC.Generics (Generic) -import qualified Game.LambdaHack.Definition.Ability as Ability-import qualified Game.LambdaHack.Definition.Color as Color-import           Game.LambdaHack.Definition.Defs import           Game.LambdaHack.Common.Item import           Game.LambdaHack.Common.Types import           Game.LambdaHack.Content.ItemKind (ItemKind) import qualified Game.LambdaHack.Content.ItemKind as IK import           Game.LambdaHack.Content.ModeKind+import qualified Game.LambdaHack.Definition.Ability as Ability+import qualified Game.LambdaHack.Definition.Color as Color+import           Game.LambdaHack.Definition.Defs  -- | All factions in the game, indexed by faction identifier. type FactionDict = EM.EnumMap FactionId Faction@@ -171,13 +171,11 @@                              , cwolf = False                              , cfish = False } -possibleActorFactions :: ItemKind -> FactionDict -> [FactionId]+possibleActorFactions :: ItemKind -> FactionDict -> [(FactionId, Faction)] possibleActorFactions itemKind factionD =   let freqNames = map fst $ IK.ifreq itemKind       f (_, fact) = any (`elem` fgroups (gplayer fact)) freqNames       fidFactsRaw = filter f $ EM.assocs factionD-      fidFacts =-        if null fidFactsRaw-        then filter (isHorrorFact . snd) $ EM.assocs factionD  -- fall back-        else fidFactsRaw-  in map fst fidFacts+  in if null fidFactsRaw+     then filter (isHorrorFact . snd) $ EM.assocs factionD  -- fall back+     else fidFactsRaw
engine-src/Game/LambdaHack/Server/HandleEffectM.hs view
@@ -270,7 +270,9 @@     -- If the item activation is not periodic, but the item itself is,     -- only the first effect gets activated (and the item may be destroyed,     -- unlike with periodic activations).-    let effsManual = if not periodic && IA.checkFlag Ability.Periodic arItem+    let effsManual = if not periodic+                        && IA.checkFlag Ability.Periodic arItem+                        && not (IA.checkFlag Ability.Condition arItem)                      then take 1 effs  -- may be empty                      else effs     triggeredEffect <- itemEffectDisco useAllCopies kineticPerformed@@ -787,8 +789,12 @@       -- We put @source@ instead of @target@ and @power@ instead of dice       -- to make the message more accurate.       effect = IK.Summon grp $ Dice.intToDice power-      execSfx = execSfxAtomic $ SfxEffect (bfid sb) source effect 0       durable = IA.checkFlag Ability.Durable arItem+      warnBothActors warning =+       unless (bproj sb) $ do+         execSfxAtomic $ SfxMsgFid (bfid sb) warning+         when (source /= target) $+           execSfxAtomic $ SfxMsgFid (bfid tb) warning       deltaCalm = - xM 30   -- Verify Calm only at periodic activations or if the item is durable.   -- Otherwise summon uses up the item, which prevents summoning getting@@ -797,31 +803,21 @@   -- has a nasty summoning side-effect (the exploit still works on durables).   if | (periodic || durable) && not (bproj sb)        && (bcalm sb < - deltaCalm || not (calmEnough sb sMaxSk)) -> do-       unless (bproj sb) $ do-         execSfxAtomic $ SfxMsgFid (bfid sb) $ SfxSummonLackCalm source-         when (source /= target) $-           execSfxAtomic $ SfxMsgFid (bfid tb) $ SfxSummonLackCalm source+       warnBothActors $ SfxSummonLackCalm source        return UseId      | nFriends >= 20 -> do        -- We assume the actor tries to summon his teammates or allies.        -- As he repeats such summoning, he is going to bump into this limit.        -- If he summons others, see the next condition.-       unless (bproj sb) $ do-         execSfxAtomic $ SfxMsgFid (bfid sb) $ SfxSummonTooManyOwn source-         when (source /= target) $-           execSfxAtomic $ SfxMsgFid (bfid tb) $ SfxSummonTooManyOwn source+       warnBothActors $ SfxSummonTooManyOwn source        return UseId      | EM.size lbig >= 200 -> do  -- lower than the 300 limit for spawning        -- Even if the actor summons foes, he is prevented from exploiting it        -- too many times and stopping natural monster spawning on the level        -- (e.g., by filling the level with harmless foes).-       unless (bproj sb) $ do-         execSfxAtomic $ SfxMsgFid (bfid sb) $ SfxSummonTooManyAll source-         when (source /= target) $-           execSfxAtomic $ SfxMsgFid (bfid tb) $ SfxSummonTooManyAll source+       warnBothActors $ SfxSummonTooManyAll source        return UseId      | otherwise -> do-       execSfx        unless (bproj sb) $ updateCalm source deltaCalm        let validTile t = not $ Tile.isNoActor coTileSpeedup t            ps = nearbyFreePoints cops lvl validTile (bpos tb)@@ -844,7 +840,16 @@              mleader <- getsState $ gleader . (EM.! bfid b) . sfactionD              when (isNothing mleader) $ setFreshLeader (bfid b) aid              return True-       return $! if or bs then UseUp else UseId+       if or bs then do+         execSfxAtomic $ SfxEffect (bfid sb) source effect 0+         return UseUp+       else do+         -- We don't display detailed warnings when @addAnyActor@ fails,+         -- e.g., because the actor groups can't be generated on a given level.+         -- However, we at least don't claim any summoning happened+         -- and we offer a general summoning failure messages.+         warnBothActors $ SfxSummonFailure source+         return UseId  -- ** Ascend 
engine-src/Game/LambdaHack/Server/HandleRequestM.hs view
@@ -44,6 +44,7 @@ import           Game.LambdaHack.Common.Level import           Game.LambdaHack.Common.Misc import           Game.LambdaHack.Common.MonadStateRead+import           Game.LambdaHack.Common.Point import           Game.LambdaHack.Common.ReqFailure import           Game.LambdaHack.Common.State import qualified Game.LambdaHack.Common.Tile as Tile@@ -53,7 +54,6 @@ import qualified Game.LambdaHack.Content.ItemKind as IK import           Game.LambdaHack.Content.ModeKind import qualified Game.LambdaHack.Content.TileKind as TK-import           Game.LambdaHack.Common.Point import qualified Game.LambdaHack.Definition.Ability as Ability import           Game.LambdaHack.Definition.Defs import           Game.LambdaHack.Server.CommonM@@ -962,7 +962,8 @@                     oldSt                     (Just $ Status Camping (fromEnum $ blid b) Nothing)                     Nothing-  modifyServer $ \ser -> ser {sbreakLoop = True}+  modifyServer $ \ser -> ser { sbreakASAP = True+                             , sbreakLoop = True }  -- * ReqGameSaveAndExit @@ -975,7 +976,8 @@   execUpdAtomic $ UpdQuitFaction                     (bfid b)                     oldSt-                    (Just $ Status Camping (fromEnum $ blid b) Nothing) Nothing+                    (Just $ Status Camping (fromEnum $ blid b) Nothing)+                    Nothing   modifyServer $ \ser -> ser { sbreakASAP = True                              , swriteSave = True } 
engine-src/Game/LambdaHack/Server/PeriodicM.hs view
@@ -99,8 +99,8 @@       debugPossiblyPrint "Server: addAnyActor: trunk failed to roll"       return Nothing     Just (itemKnownRaw, (itemFullRaw, kit)) -> do-      fid <- rndToAction $ oneOf $-               possibleActorFactions (itemKind itemFullRaw) factionD+      (fid, _) <- rndToAction $ oneOf $+                    possibleActorFactions (itemKind itemFullRaw) factionD       pers <- getsServer sperFid       let allPers = ES.unions $ map (totalVisible . (EM.! lid))                     $ EM.elems $ EM.delete fid pers  -- expensive :(
engine-src/Game/LambdaHack/Server/StartM.hs view
@@ -35,6 +35,7 @@ import           Game.LambdaHack.Common.Level import           Game.LambdaHack.Common.Misc import           Game.LambdaHack.Common.MonadStateRead+import           Game.LambdaHack.Common.Point import           Game.LambdaHack.Common.State import qualified Game.LambdaHack.Common.Tile as Tile import           Game.LambdaHack.Common.Time@@ -43,7 +44,6 @@ import qualified Game.LambdaHack.Content.ItemKind as IK import           Game.LambdaHack.Content.ModeKind import qualified Game.LambdaHack.Core.Dice as Dice-import           Game.LambdaHack.Common.Point import           Game.LambdaHack.Core.Random import qualified Game.LambdaHack.Definition.Color as Color import           Game.LambdaHack.Definition.Defs@@ -115,7 +115,6 @@   populateDungeon   mapM_ (\fid -> mapM_ (updatePer fid) (EM.keys dungeon))         (EM.keys factionD)-  execSfxAtomic SfxSortSlots  -- For simplicity only spawnable actors are taken into account, not starting -- actors of any faction nor summonable actors.@@ -135,7 +134,7 @@             freq = pure (itemKindId, itemKind)         case possibleActorFactions itemKind factionD of           [] -> return Nothing-          fid : _ -> do+          (fid, _) : _ -> do             let c = CTrunk fid minLid originPoint                 jfid = Just fid             m2 <- rollItemAspect freq minLid