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 +31/−0
- GameDefinition/Content/ItemKindEmbed.hs +3/−3
- GameDefinition/Content/ModeKind.hs +1/−1
- GameDefinition/InGameHelp.txt +8/−9
- GameDefinition/Main.hs +4/−1
- GameDefinition/MoveKeys.txt +6/−6
- GameDefinition/PLAYING.md +10/−8
- GameDefinition/game-src/Client/UI/Content/Input.hs +4/−4
- LambdaHack.cabal +92/−32
- Makefile +4/−4
- engine-src/Game/LambdaHack/Atomic/CmdAtomic.hs +2/−3
- engine-src/Game/LambdaHack/Atomic/PosAtomicRead.hs +1/−2
- engine-src/Game/LambdaHack/Client/UI/Content/Input.hs +2/−4
- engine-src/Game/LambdaHack/Client/UI/DisplayAtomicM.hs +50/−36
- engine-src/Game/LambdaHack/Client/UI/DrawM.hs +12/−10
- engine-src/Game/LambdaHack/Client/UI/Frontend/Curses.hs +1/−1
- engine-src/Game/LambdaHack/Client/UI/Frontend/Gtk.hs +5/−2
- engine-src/Game/LambdaHack/Client/UI/Frontend/Vty.hs +11/−4
- engine-src/Game/LambdaHack/Client/UI/HandleHelperM.hs +7/−27
- engine-src/Game/LambdaHack/Client/UI/HandleHumanGlobalM.hs +37/−21
- engine-src/Game/LambdaHack/Client/UI/HandleHumanLocalM.hs +1/−8
- engine-src/Game/LambdaHack/Client/UI/HandleHumanM.hs +1/−1
- engine-src/Game/LambdaHack/Client/UI/HumanCmd.hs +1/−1
- engine-src/Game/LambdaHack/Client/UI/InventoryM.hs +24/−21
- engine-src/Game/LambdaHack/Client/UI/ItemSlot.hs +10/−13
- engine-src/Game/LambdaHack/Common/Faction.hs +7/−9
- engine-src/Game/LambdaHack/Server/HandleEffectM.hs +21/−16
- engine-src/Game/LambdaHack/Server/HandleRequestM.hs +5/−3
- engine-src/Game/LambdaHack/Server/PeriodicM.hs +2/−2
- engine-src/Game/LambdaHack/Server/StartM.hs +2/−3
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