packages feed

Allure 0.5.0.0 → 0.6.0.0

raw patch · 33 files changed

+5786/−3031 lines, 33 filesdep +asyncdep +randomdep +zlibdep ~LambdaHackdep ~basedep ~containersbinary-added

Dependencies added: async, random, zlib

Dependency ranges changed: LambdaHack, base, containers, enummapset-th, filepath, template-haskell, text

Files

Allure.cabal view
@@ -5,19 +5,23 @@ -- PVP summary:+-+------- breaking API changes --             | | +----- non-breaking API additions --             | | | +--- code changes with no API change-version:       0.5.0.0+version:       0.6.0.0 synopsis:      Near-future Sci-Fi roguelike and tactical squad game description:   Allure of the Stars                is a near-future Sci-Fi roguelike and tactical squad game.-               See the wiki for design notes and contribute.+               Try out the browser version of Allure of the Stars at+               <http://allureofthestars.com/play>+               (It runs fastest on Chrome. Keyboard commands and savefiles+               are supported only on recent enough versions of browsers.+               Mouse should work everywhere.)                .-               <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/campaign2.png>>+               <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/crawl-0.6.0.0-8x8xb.png>>                .                Please see the changelog file for recent improvements                and the issue tracker for short-term plans. Long term goals                are high replayability and auto-balancing through procedural                content generation and persistent content modification-               based on player behaviour.+               based on player behaviour. Contributions are welcome.                .                The game is written using the LambdaHack roguelike game engine                available at <http://hackage.haskell.org/package/LambdaHack>.@@ -25,10 +29,20 @@ bug-reports:   http://github.com/AllureOfTheStars/Allure/issues license:       AGPL-3 license-file:  LICENSE-tested-with:   GHC == 7.6, GHC == 7.8, GHC == 7.10-data-files:    GameDefinition/config.ui.default, GameDefinition/scores,-               GameDefinition/PLAYING.md, README.md, LICENSE, CREDITS,-               CHANGELOG.md+tested-with:   GHC >= 7.10 && <= 8.2+data-files:    GameDefinition/config.ui.default,+               GameDefinition/fonts/16x16x.fon,+               GameDefinition/fonts/8x8xb.fon,+               GameDefinition/fonts/8x8x.fon,+               GameDefinition/fonts/LICENSE.16x16x,+               GameDefinition/fonts/Fix15Mono-Bold.woff,+               GameDefinition/fonts/LICENSE.Fix15Mono-Bold,+               GameDefinition/PLAYING.md,+               GameDefinition/InGameHelp.txt,+               README.md,+               CHANGELOG.md,+               LICENSE,+               CREDITS extra-source-files: GameDefinition/MainMenu.ascii, Makefile author:        Andres Loeh, Mikolaj Konarski and others maintainer:    Mikolaj Konarski <mikolaj.konarski@funktory.com>@@ -40,17 +54,13 @@   type:               git   location:           git://github.com/AllureOfTheStars/Allure.git -flag release-  description:        prepare for a release (expose, optimize, etc.)-  default:            True-  manual:             True- executable Allure   hs-source-dirs:     GameDefinition   main-is:            Main.hs   other-modules:      Client.UI.Content.KeyKind,                       Content.CaveKind,                       Content.ItemKind,+                      Content.ItemKindEmbed,                       Content.ItemKindActor,                       Content.ItemKindOrgan,                       Content.ItemKindBlast,@@ -62,50 +72,69 @@                       Content.TileKind,                       TieKnot,                       Paths_Allure-  build-depends:      LambdaHack >= 0.5.0.0 && < 0.5.1.0,-                      template-haskell >= 2.6 && < 3,+  build-depends:      LambdaHack >= 0.6.0.0 && < 0.6.1.0,+                      template-haskell >= 2.6, -                      base       >= 4       && < 5,-                      containers >= 0.5.3.0 && < 1,-                      enummapset-th >= 0.6.0.0 && < 1,-                      filepath   >= 1.2.0.1 && < 2,-                      text       >= 0.11.2.3 && < 2+                      async      >= 2,+                      base       >= 4 && < 99,+                      containers >= 0.5.3.0,+                      enummapset-th >= 0.6.0.0,+                      filepath   >= 1.2.0.1,+                      random     >= 1.1,+                      text       >= 0.11.2.3    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings-                      BangPatterns, RecordWildCards, NamedFieldPuns+                      BangPatterns, RecordWildCards, NamedFieldPuns, MultiWayIf   other-extensions:   TemplateHaskell-  ghc-options:        -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -fwarn-unrecognised-pragmas-  ghc-options:        -fno-warn-auto-orphans -fno-warn-implicit-prelude-  ghc-options:        -fno-ignore-asserts -funbox-strict-fields-  ghc-options:        -threaded "-with-rtsopts=-C0.005" -rtsopts+  ghc-options:        -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-unrecognised-pragmas+  ghc-options:        -fno-warn-implicit-prelude -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively+  ghc-options:        -threaded -rtsopts -  if flag(release)-    ghc-options:      -O2 -fno-ignore-asserts "-with-rtsopts=-N1"--- TODO: -N+  if impl(ghcjs) {+-- This is the largest GHCJS_BUSY_YIELD value that does not cause dropped frames+-- on my machine with default --maxFps.+    cpp-options:      -DGHCJS_BUSY_YIELD=50+-- Minimize median lag at the cost of occasional huge lag when GC kicks in+-- (and some of the GCs fit into idle time, while the player ponders+-- or game is being saved):+    ghc-options:      "-with-rtsopts=-A99m"+  } else {+    build-depends:    zlib >= 0.5.3.1+-- The -A options makes it slightly faster, especially with short sessions:+    ghc-options:      "-with-rtsopts=-A99m -K1000K"+-- TODO: get back to -K1K when I can use pretty-1.1.3.4 (TH depends on an old one)+  }  test-suite test   type:               exitcode-stdio-1.0   hs-source-dirs:     GameDefinition, test   main-is:            test.hs   build-depends:      LambdaHack,-                      template-haskell >= 2.6 && < 3,+                      template-haskell >= 2.6, -                      base       >= 4       && < 5,-                      containers >= 0.5.3.0 && < 1,-                      enummapset-th >= 0.6.0.0 && < 1,-                      filepath   >= 1.2.0.1 && < 2,-                      text       >= 0.11.2.3 && < 2+                      base       >= 4 && < 99,+                      containers >= 0.5.3.0,+                      enummapset-th >= 0.6.0.0,+                      filepath   >= 1.2.0.1,+                      random     >= 1.1,+                      text       >= 0.11.2.3    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings-                      BangPatterns, RecordWildCards, NamedFieldPuns+                      BangPatterns, RecordWildCards, NamedFieldPuns, MultiWayIf   other-extensions:   TemplateHaskell-  ghc-options:        -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -fwarn-unrecognised-pragmas-  ghc-options:        -fno-warn-auto-orphans -fno-warn-implicit-prelude-  ghc-options:        -fno-ignore-asserts -funbox-strict-fields-  ghc-options:        -threaded "-with-rtsopts=-C0.005" -rtsopts+  ghc-options:        -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-unrecognised-pragmas+  ghc-options:        -fno-warn-implicit-prelude -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively+  ghc-options:        -threaded -rtsopts -  if flag(release)-    ghc-options:      -O2 -fno-ignore-asserts "-with-rtsopts=-N1"--- TODO: -N+  if impl(ghcjs) {+-- This is the largest GHCJS_BUSY_YIELD value that does not cause dropped frames+-- on my machine with default --maxFps.+    cpp-options:      -DGHCJS_BUSY_YIELD=50+    ghc-options:      "-with-rtsopts=-A99m"+  } else {+    build-depends:    zlib >= 0.5.3.1+    ghc-options:      "-with-rtsopts=-A99m -K1000K"+-- get back to -K1K when I can use pretty-1.1.3.4 (TH depends on an old one)+  }
CHANGELOG.md view
@@ -1,3 +1,57 @@+## [v0.6.0.0, aka 'Too much to tell'](https://github.com/AllureOfTheStars/Allure/compare/v0.5.0.0...v0.6.0.0)++- add and modify a lot of content: items, tiles, embedded items, scenarios+- improve AI: targeting, stealth, moving in groups, item use, fleeing, etc.+- make monsters more aggressive than animals+- tie scenarios into a loose, optional storyline+- add more level generators and more variety to room placement+- make stairs not walkable and use them by bumping+- align stair position on the levels they pass through+- introduce noctovision+- increase human vision to 12 so that normal speed missiles can be sidestepped+- tweak and document weapon damage calculation+- derive projectile damage mostly from their speed+- make heavy projectiles better vs armor but easier to sidestep+- improve hearing of unseen actions, actors and missiles impacts+- let some missiles lit up on impact+- make torches reusable flares and add blankets for dousing dynamic light+- add detection effects and use them in items and tiles+- make it possible to catch missiles, if not using weapons+- make it possible to wait 0.1 of a turn, at the cost of no bracing+- improve pathfinding, prefer less unknown, alterable and dark tiles on paths+- slow down actors when acting at the same time, for speed with large factions+- don't halve Calm at serious damage any more+- eliminate alternative FOV modes, for speed+- stop actors blocking FOV, for speed+- let actor move diagonally to and from doors, for speed+- improve blast (explosion) shapes visually and gameplay-wise+- add SDL2 frontend and deprecate GTK frontend+- add specialized square bitmap fonts and hack a scalable font+- use middle dot instead of period on the map (except in teletype frontend)+- add a browser frontend based on DOM, using ghcjs+- improve targeting UI, e.g., cycle among items on the map+- show an animation when actor teleports+- add character stats menu and stat description texts+- add item lore and organ lore menus+- add a command to sort item slots and perform the sort at startup+- add a single item manipulation menu and let it mark an item for later+- make history display a menu and improve display of individual messages+- display highscore dates according to the local timezone+- make the help screen a menu, execute actions directly from it+- rework the Main Menu+- rework special positions highlight in all frontends+- mark leader's target on the map (grey highlight)+- visually mark currently chosen menu item and grey out impossible items+- define mouse commands based on UI mode and screen area+- let the game be fully playable only with mouse, use mouse wheel+- pick menu items with mouse and with arrow keys+- add more sanity checks for content+- reorganize content in files to make rebasing on changed content easier+- rework keybinding definition machinery+- let clients, not the server, start frontends+- version savefiles and move them aside if versions don't match+- lots of bug fixes internal improvements and minor visual and text tweaks+ ## [v0.5.0.0, aka 'Halfway through space'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.101.0...v0.5.0.0)  - let AI put excess items in shared stash and use them out of shared stash
CREDITS view
@@ -4,3 +4,26 @@ Andres Loeh Mikolaj Konarski Krzysztof Pławski+Fonts 16x16x.fon, 8x8x.fon and 8x8xb.fon are are taken from+https://github.com/angband/angband, copyrighted by Leon Marrick,+Sheldon Simms III and Nick McConnell and released by them under+GNU GPL version 2. Any further modifications by authors of LambdaHack+are also released under GNU GPL version 2. The licence file is at+GameDefinition/fonts/LICENSE.16x16x++Font Fix15Mono-Bold.woff is a modified version of+https://github.com/mozilla/Fira/blob/master/ttf/FiraMono-Bold.ttf+that is copyright 2012-2015, The Mozilla Foundation and Telefonica S.A.+The modified font is released under the SIL Open Font License, as seen in+GameDefinition/fonts/LICENSE.Fix15Mono-Bold+Modifications were performed with font editor FontForge and are as follows:+* straighten and enlarge #, enlarge %, &, ', +, \,, -, :, ;, O, _, `+* centre a few other glyphs+* create a small 0x22c5+* shrink 0xb7 a bit+* extend all fonts by 150% and 150%+    (the extension resulted in an artifact in letter 'n',+     which was gleefully kept, and many other artifacts and distortions+     that should be fixed at some point)+* set width of space, nbsp and # glyphs to 1170+    (this is a hack to make DOM create square table cells)
GameDefinition/Client/UI/Content/KeyKind.hs view
@@ -1,212 +1,272 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | The default game key-command mapping to be used for UI. Can be overridden -- via macros in the config file.-module Client.UI.Content.KeyKind ( standardKeys ) where+module Client.UI.Content.KeyKind+  ( standardKeys+  ) where -import Control.Arrow (first)+import Prelude () -import qualified Game.LambdaHack.Client.Key as K+import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Client.UI.Content.KeyKind import Game.LambdaHack.Client.UI.HumanCmd import Game.LambdaHack.Common.Misc-import qualified Game.LambdaHack.Content.ItemKind as IK import qualified Game.LambdaHack.Content.TileKind as TK +-- | Description of default key-command bindings.+--+-- In addition to these commands, mouse and keys have a standard meaning+-- when navigating various menus. standardKeys :: KeyKind standardKeys = KeyKind-  { rhumanCommands = map (first K.mkKM)+  { rhumanCommands = map evalKeyDef $       -- All commands are defined here, except some movement and leader picking       -- commands. All commands are shown on help screens except debug commands       -- and macros with empty descriptions.       -- The order below determines the order on the help screens.-      -- Remember to put commands that show information (e.g., enter targeting+      -- Remember to put commands that show information (e.g., enter aiming       -- mode) first. -      -- Main Menu, which apart of these includes a few extra commands-      [ ("CTRL-x", ([CmdMenu], GameExit))-      , ("CTRL-r", ([CmdMenu], GameRestart "raid"))-      , ("CTRL-k", ([CmdMenu], GameRestart "skirmish"))-      , ("CTRL-m", ([CmdMenu], GameRestart "ambush"))-      , ("CTRL-b", ([CmdMenu], GameRestart "battle"))-      , ("CTRL-c", ([CmdMenu], GameRestart "campaign"))-      , ("CTRL-i", ([CmdDebug], GameRestart "battle survival"))-      , ("CTRL-f", ([CmdDebug], GameRestart "safari"))-      , ("CTRL-u", ([CmdDebug], GameRestart "safari survival"))-      , ("CTRL-e", ([CmdDebug], GameRestart "defense"))-      , ("CTRL-d", ([CmdMenu], GameDifficultyCycle))+      -- Main Menu+      [ ("c", ([CmdMainMenu], "enter challenges menu>", ChallengesMenu))+      , ("n", ([CmdMainMenu], "start new game", GameRestart))+      , ("x", ([CmdMainMenu], "save and exit", GameExit))+      , ("m", ([CmdMainMenu], "enter settings menu>", SettingsMenu))+      , ("a", ([CmdMainMenu], "automate faction", Automate))+      , ("?", ([CmdMainMenu], "see command Help", Help))+      , ("Escape", ([CmdMainMenu], "back to playing", Cancel)) -      -- Movement and terrain alteration-      , ("less", ([CmdMove, CmdMinimal], TriggerTile-           [ TriggerFeature { verb = "ascend"-                            , object = "a level"-                            , feature = TK.Cause (IK.Ascend 1) }-           , TriggerFeature { verb = "escape"-                            , object = "spaceship"-                            , feature = TK.Cause (IK.Escape 1) } ]))-      , ("CTRL-less", ([CmdMove], TriggerTile-           [ TriggerFeature { verb = "ascend"-                            , object = "10 levels"-                            , feature = TK.Cause (IK.Ascend 10) } ]))-      , ("greater", ([CmdMove, CmdMinimal], TriggerTile-           [ TriggerFeature { verb = "descend"-                            , object = "a level"-                            , feature = TK.Cause (IK.Ascend (-1)) }-           , TriggerFeature { verb = "escape"-                            , object = "spaceship"-                            , feature = TK.Cause (IK.Escape (-1)) } ]))-      , ("CTRL-greater", ([CmdMove], TriggerTile-           [ TriggerFeature { verb = "descend"-                            , object = "10 levels"-                            , feature = TK.Cause (IK.Ascend (-10)) } ]))-      , ("semicolon",-         ( [CmdMove]-         , Macro "go to crosshair for 100 steps"-                 ["CTRL-semicolon", "CTRL-period", "V"] ))-      , ("colon",-         ( [CmdMove]-         , Macro "run selected to crosshair for 100 steps"-                 ["CTRL-colon", "CTRL-period", "V"] ))-      , ("x",-         ( [CmdMove]-         , Macro "explore the closest unknown spot"-                 [ "CTRL-question"  -- no semicolon-                 , "CTRL-period", "V" ] ))-      , ("X",-         ( [CmdMove]-         , Macro "autoexplore 100 times"-                 ["'", "CTRL-question", "CTRL-period", "'", "V"] ))-      , ("CTRL-X",-         ( [CmdMove]-         , Macro "autoexplore 25 times"-                 ["'", "CTRL-question", "CTRL-period", "'", "CTRL-V"] ))-      , ("R", ([CmdMove], Macro "rest (wait 100 times)"-                                ["KP_Begin", "V"]))-      , ("CTRL-R", ([CmdMove], Macro "rest (wait 25 times)"-                                     ["KP_Begin", "CTRL-V"]))-      , ("c", ([CmdMove, CmdMinimal], AlterDir-           [ AlterFeature { verb = "close"-                          , object = "door"-                          , feature = TK.CloseTo "closed door" }-           ]))+      -- Item use, 1st part+      , ("g", addCmdCategory CmdMinimal $ grabItems "grab item(s)")+      , ("comma", grabItems "")+      , ("d", dropItems "drop item(s)")+      , ("period", dropItems "")+      , ("f", addCmdCategory CmdItemMenu $ projectA flingTs)+      , ("C-f", addCmdCategory CmdItemMenu+                $ replaceDesc "fling without aiming" $ projectI flingTs)+      , ("a", addCmdCategory CmdItemMenu $ applyI [ApplyItem+                { verb = "apply"+                , object = "consumable"+                , symbol = ' ' }])+      , ("C-a", addCmdCategory CmdItemMenu+                $ replaceDesc "apply and keep choice" $ applyIK [ApplyItem+                  { verb = "apply"+                  , object = "consumable"+                  , symbol = ' ' }]) -      -- Item use-      ---      -- For later:-      -- ApplyItem {verb = "eat", object = "food", symbol = ','}-      -- ApplyItem {verb = "apply", object = "emitter", symbol = '_'}-      -- ApplyItem {verb = "use", object = "tool", symbol = '~'}-      ---      , ("E", ([CmdItem, CmdMinimal], DescribeItem $ MStore CEqp))-      , ("P", ([CmdItem], DescribeItem $ MStore CInv))-      , ("S", ([CmdItem], DescribeItem $ MStore CSha))-      , ("A", ([CmdItem], DescribeItem MOwned))-      , ("G", ([CmdItem], DescribeItem $ MStore CGround))-      , ("@", ([CmdItem], DescribeItem $ MStore COrgan))-      , ("exclam", ([CmdItem], DescribeItem MStats))-      , ("g", ([CmdItem, CmdMinimal],-               MoveItem [CGround] CEqp (Just "get") "items" True))-      , ("d", ([CmdItem], MoveItem [CEqp, CInv, CSha] CGround-                                   Nothing "items" False))-      , ("e", ([CmdItem], MoveItem [CGround, CInv, CSha] CEqp-                                   Nothing "items" False))-      , ("p", ([CmdItem], MoveItem [CGround, CEqp, CSha] CInv-                                   Nothing "items into inventory"-                                   False))-      , ("s", ([CmdItem], MoveItem [CGround, CInv, CEqp] CSha-                                   Nothing "and share items" False))-      , ("a", ([CmdItem, CmdMinimal], Apply-           [ ApplyItem { verb = "apply"-                       , object = "consumable"-                       , symbol = ' ' }-           , ApplyItem { verb = "quaff"-                       , object = "drink"-                       , symbol = '!' }-           , ApplyItem { verb = "read"-                       , object = "chip"-                       , symbol = '?' }-           ]))-      , ("q", ([CmdItem], Apply [ApplyItem { verb = "quaff"-                                           , object = "drink"-                                           , symbol = '!' }]))-      , ("r", ([CmdItem], Apply [ApplyItem { verb = "read"-                                           , object = "chip"-                                           , symbol = '?' }]))-      , ("f", ([CmdItem, CmdMinimal], Project-           [ApplyItem { verb = "fling"-                      , object = "projectile"-                      , symbol = ' ' }]))-      , ("t", ([CmdItem], Project [ ApplyItem { verb = "throw"-                                              , object = "missile"-                                              , symbol = '}' }-                                  , ApplyItem { verb = "throw"-                                              , object = "missile"-                                              , symbol = '{' } ]))---      , ("z", ([CmdItem], Project [ApplyItem { verb = "zap"---                                             , object = "mechanism"---                                             , symbol = '-' }]))+      -- Terrain exploration and alteration+      , ("semicolon", ( [CmdMove]+                      , "go to x-hair for 25 steps"+                      , Macro ["C-semicolon", "C-/", "C-V"] ))+      , ("colon", ( [CmdMove]+                  , "run to x-hair collectively for 25 steps"+                  , Macro ["C-colon", "C-/", "C-V"] ))+      , ("x", ( [CmdMove]+              , "explore nearest unknown spot"+              , autoexploreCmd ))+      , ("X", ( [CmdMove]+              , "autoexplore 25 times"+              , autoexplore25Cmd ))+      , ("R", ([CmdMove], "rest (wait 25 times)", Macro ["KP_5", "C-V"]))+      , ("C-R", ( [CmdMove], "lurk (wait 0.1 turns 100 times)"+                , Macro ["C-KP_5", "V"] ))+      , ("c", ( [CmdMove, CmdMinimal]+              , descTs closeDoorTriggers+              , AlterDir closeDoorTriggers )) -      -- Targeting-      , ("KP_Multiply", ([CmdTgt], TgtEnemy))-      , ("backslash", ([CmdTgt], Macro "" ["KP_Multiply"]))-      , ("KP_Divide", ([CmdTgt], TgtFloor))-      , ("bar", ([CmdTgt], Macro "" ["KP_Divide"]))-      , ("plus", ([CmdTgt, CmdMinimal], EpsIncr True))-      , ("minus", ([CmdTgt], EpsIncr False))-      , ("CTRL-question", ([CmdTgt], CursorUnknown))-      , ("CTRL-I", ([CmdTgt], CursorItem))-      , ("CTRL-braceleft", ([CmdTgt], CursorStair True))-      , ("CTRL-braceright", ([CmdTgt], CursorStair False))-      , ("BackSpace", ([CmdTgt], TgtClear))+      -- Item use, continued+      , ("^", ( [CmdItem], "sort items by kind and stats", SortSlots))+      , ("p", moveItemTriple [CGround, CEqp, CSha] CInv+                             "item" False)+      , ("e", moveItemTriple [CGround, CInv, CSha] CEqp+                             "item" False)+      , ("s", moveItemTriple [CGround, CInv, CEqp] CSha+                             "and share item" False)+      , ("P", ( [CmdMinimal, CmdItem]+              , "manage item pack of the leader"+              , ChooseItemMenu (MStore CInv) ))+      , ("G", ( [CmdItem]+              , "manage items on the ground"+              , ChooseItemMenu (MStore CGround) ))+      , ("E", ( [CmdItem]+              , "manage equipment of the leader"+              , ChooseItemMenu (MStore CEqp) ))+      , ("S", ( [CmdItem]+              , "manage the shared party stash"+              , ChooseItemMenu (MStore CSha) ))+      , ("A", ( [CmdItem]+              , "manage all owned items"+              , ChooseItemMenu MOwned ))+      , ("@", ( [CmdItem]+              , "describe organs of the leader"+              , ChooseItemMenu (MStore COrgan) ))+      , ("#", ( [CmdItem]+              , "show stat summary of the leader"+              , ChooseItemMenu MStats ))+      , ("~", ( [CmdItem]+              , "display known lore"+              , ChooseItemMenu MLoreItem ))+      , ("q", addCmdCategory CmdItem $ applyI [ApplyItem+                { verb = "quaff"+                , object = "drink"+                , symbol = '!' }])+      , ("r", addCmdCategory CmdItem $ applyI [ApplyItem+                { verb = "read"+                , object = "chip"+                , symbol = '?' }]) -      -- Automation-      , ("equal", ([CmdAuto], SelectActor))-      , ("underscore", ([CmdAuto], SelectNone))-      , ("v", ([CmdAuto], Repeat 1))-      , ("V", ([CmdAuto], Repeat 100))-      , ("CTRL-v", ([CmdAuto], Repeat 1000))-      , ("CTRL-V", ([CmdAuto], Repeat 25))-      , ("apostrophe", ([CmdAuto], Record))-      , ("CTRL-T", ([CmdAuto], Tactic))-      , ("CTRL-A", ([CmdAuto], Automate))+      , ("t", addCmdCategory CmdItem $ projectA+                [ ApplyItem { verb = "throw"+                            , object = "missile"+                            , symbol = '{' }+                , ApplyItem { verb = "throw"+                            , object = "missile"+                            , symbol = '}' } ])+--      , ("z", projectA [ApplyItem { verb = "zap"+--                                  , object = "wand"+--                                  , symbol = '-' }]) +      -- Aiming+      , ("KP_Multiply", ( [CmdAim, CmdMinimal]+                        , "cycle x-hair among enemies", AimEnemy ))+          -- not really minimal, because flinging from Item Menu enters aiming+          -- mode, first screen mentions aiming mode not in fling context+      , ("!", ([CmdAim], "", AimEnemy))+      , ("KP_Divide", ([CmdAim], "cycle x-hair among items", AimItem))+      , ("/", ([CmdAim], "", AimItem))+      , ("\\", ([CmdAim], "cycle aiming modes", AimFloor))+      , ("+", ([CmdAim, CmdMinimal], "swerve the aiming line", EpsIncr True))+      , ("-", ([CmdAim], "unswerve the aiming line", EpsIncr False))+      , ("C-?", ( [CmdAim]+                , "set x-hair to nearest unknown spot"+                , XhairUnknown ))+      , ("C-I", ( [CmdAim]+                , "set x-hair to nearest item"+                , XhairItem ))+      , ("C-{", ( [CmdAim]+                , "set x-hair to nearest upstairs"+                , XhairStair True ))+      , ("C-}", ( [CmdAim]+                , "set x-hair to nearest downstairs"+                , XhairStair False ))+      , ("<", ([CmdAim], "move aiming one level higher" , AimAscend 1))+      , ("C-<", ( [CmdNoHelp], "move aiming 10 levels higher"+                , AimAscend 10) )+      , (">", ([CmdAim], "move aiming one level lower", AimAscend (-1)))+      , ("C->", ( [CmdNoHelp], "move aiming 10 levels lower"+                , AimAscend (-10)) )+      , ("BackSpace" , ( [CmdAim]+                     , "clear chosen item and target"+                     , ComposeUnlessError ItemClear TgtClear ))+      , ("Escape", ( [CmdAim, CmdMinimal]+                   , "cancel aiming/open Main Menu"+                   , ByAimMode {exploration = MainMenu, aiming = Cancel} ))+      , ("Return", ( [CmdAim, CmdMinimal]+                   , "accept target/open Help"+                   , ByAimMode {exploration = Help, aiming = Accept} ))+       -- Assorted-      , ("question", ([CmdMeta], Help))-      , ("D", ([CmdMeta, CmdMinimal], History))-      , ("T", ([CmdMeta, CmdMinimal], MarkSuspect))-      , ("Z", ([CmdMeta], MarkVision))-      , ("C", ([CmdMeta], MarkSmell))-      , ("Tab", ([CmdMeta], MemberCycle))-      , ("ISO_Left_Tab", ([CmdMeta, CmdMinimal], MemberBack))-      , ("space", ([CmdMeta], Clear))-      , ("Escape", ([CmdMeta, CmdMinimal], Cancel))-      , ("Return", ([CmdMeta, CmdTgt], Accept))+      , ("space", ( [CmdMinimal, CmdMeta]+                  , "clear messages/display history", Clear ))+      , ("?", ([CmdMeta], "display Help", Help))+      , ("F1", ([CmdMeta], "", Help))+      , ("Tab", ( [CmdMeta]+                , "cycle among party members on the level"+                , MemberCycle ))+      , ("BackTab", ( [CmdMeta, CmdMinimal]+                  , "cycle among all party members"+                  , MemberBack ))+      , ("=", ( [CmdMinimal, CmdMeta]+              , "select (or deselect) party member", SelectActor) )+      , ("_", ([CmdMeta], "deselect (or select) all on the level", SelectNone))+      , ("v", ([CmdMeta], "voice again the recorded commands", Repeat 1))+      , ("V", repeatTriple 100)+      , ("C-v", repeatTriple 1000)+      , ("C-V", repeatTriple 25)+      , ("'", ([CmdMeta], "start recording commands", Record))        -- Mouse-      , ("LeftButtonPress",-         ([CmdMouse], macroLeftButtonPress))-      , ("SHIFT-LeftButtonPress",-         ([CmdMouse], macroShiftLeftButtonPress))-      , ("MiddleButtonPress", ([CmdMouse], CursorPointerEnemy))-      , ("SHIFT-MiddleButtonPress", ([CmdMouse], CursorPointerFloor))-      , ("CTRL-MiddleButtonPress",-         ([CmdInternal], Macro "" ["SHIFT-MiddleButtonPress"]))-      , ("RightButtonPress", ([CmdMouse], TgtPointerEnemy))+      , ("LeftButtonRelease", mouseLMB)+      , ("RightButtonRelease", mouseRMB)+      , ("C-LeftButtonRelease", replaceDesc "" mouseRMB)  -- Mac convention+      , ( "C-RightButtonRelease"+        , ( [CmdMouse]+          , "open or close door"+          , AlterWithPointer $ closeDoorTriggers ++ openDoorTriggers ) )+      , ("MiddleButtonRelease", mouseMMB)+      , ("WheelNorth", ([CmdMouse], "swerve the aiming line", Macro ["+"]))+      , ("WheelSouth", ([CmdMouse], "unswerve the aiming line", Macro ["-"]))        -- Debug and others not to display in help screens-      , ("CTRL-S", ([CmdDebug], GameSave))-      , ("CTRL-semicolon", ([CmdInternal], MoveOnceToCursor))-      , ("CTRL-colon", ([CmdInternal], RunOnceToCursor))-      , ("CTRL-period", ([CmdInternal], ContinueToCursor))-      , ("CTRL-comma", ([CmdInternal], RunOnceAhead))-      , ("CTRL-LeftButtonPress",-         ([CmdInternal], Macro "" ["SHIFT-LeftButtonPress"]))-      , ("CTRL-MiddleButtonPress",-         ([CmdInternal], Macro "" ["SHIFT-MiddleButtonPress"]))-      , ("ALT-space", ([CmdInternal], StopIfTgtMode))-      , ("ALT-minus", ([CmdInternal], SelectWithPointer))-     ]+      , ("C-S", ([CmdDebug], "save game", GameSave))+      , ("C-semicolon", ( [CmdNoHelp]+                        , "move one step towards the x-hair"+                        , MoveOnceToXhair ))+      , ("C-colon", ( [CmdNoHelp]+                    , "run collectively one step towards the x-hair"+                    , RunOnceToXhair ))+      , ("C-/", ( [CmdNoHelp]+                , "continue towards the x-hair"+                , ContinueToXhair ))+      , ("C-comma", ([CmdNoHelp], "run once ahead", RunOnceAhead))+      , ("safe1", ( [CmdInternal]+                  , "go to pointer for 25 steps"+                  , goToCmd ))+      , ("safe2", ( [CmdInternal]+                  , "run to pointer collectively"+                  , runToAllCmd ))+      , ("safe3", ( [CmdInternal]+                  , "pick new leader on screen"+                  , PickLeaderWithPointer ))+      , ("safe4", ( [CmdInternal]+                  , "select party member on screen"+                  , SelectWithPointer ))+      , ("safe5", ( [CmdInternal]+                  , "set x-hair to enemy"+                  , AimPointerEnemy ))+      , ("safe6", ( [CmdInternal]+                  , "fling at enemy under pointer"+                  , aimFlingCmd ))+      , ("safe7", ( [CmdInternal]+                  , "open Main Menu"+                  , MainMenu ))+      , ("safe8", ( [CmdInternal]+                  , "cancel aiming"+                  , Cancel ))+      , ("safe9", ( [CmdInternal]+                  , "accept target"+                  , Accept ))+      , ("safe10", ( [CmdInternal]+                   , "wait a turn, bracing for impact"+                   , Wait ))+      , ("safe11", ( [CmdInternal]+                   , "wait 0.1 of a turn"+                   , Wait10 ))+      ]+      ++ map defaultHeroSelect [0..6]   }++closeDoorTriggers :: [Trigger]+closeDoorTriggers =+  [ AlterFeature { verb = "close"+                 , object = "door"+                 , feature = TK.CloseTo "closed door" }+  , AlterFeature { verb = "close"+                 , object = "door"+                 , feature = TK.CloseTo "closed door" }+  ]++openDoorTriggers :: [Trigger]+openDoorTriggers =+  [ AlterFeature { verb = "open"+                 , object = "door"+                 , feature = TK.OpenTo "open door" }+  , AlterFeature { verb = "open"+                 , object = "door"+                 , feature = TK.OpenTo "open door" }+  ]
GameDefinition/Content/CaveKind.hs view
@@ -1,11 +1,17 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Cave layouts.-module Content.CaveKind ( cdefs ) where+module Content.CaveKind+  ( cdefs+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude+ import Data.Ratio  import Game.LambdaHack.Common.ContentDef@@ -20,31 +26,33 @@   , getFreq = cfreq   , validateSingle = validateSingleCaveKind   , validateAll = validateAllCaveKind-  , content =-      [rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, rogueLit, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena]+  , content = contentFromList+      [rogue, rogue2, arena, arena2, laboratory, empty, noise, noise2, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1empty, emptyExit, raid, brawl, shootout, escape, zoo, ambush, battle, safari1, safari2, safari3]   }-rogue,        arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, rogueLit, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena :: CaveKind+rogue,        rogue2, arena, arena2, laboratory, empty, noise, noise2, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1empty, emptyExit, raid, brawl, shootout, escape, zoo, ambush, battle, safari1, safari2, safari3 :: CaveKind  rogue = CaveKind   { csymbol       = 'R'-  , cname         = "Storage area"-  , cfreq         = [("campaign random", 100), ("caveRogue", 1)]+  , cname         = "Insulated storage area"+  , cfreq         = [ ("default random", 100), ("deep random", 80)+                    , ("caveRogue", 1) ]   , cxsize        = fst normalLevelBound + 1   , cysize        = snd normalLevelBound + 1-  , cgrid         = DiceXY (3 * d 2) (d 2 + 2)-  , cminPlaceSize = DiceXY (2 * d 2 + 2) 4+  , cgrid         = DiceXY (3 * d 2) 4+  , cminPlaceSize = DiceXY (2 * d 2 + 4) 5   , cmaxPlaceSize = DiceXY 15 10   , cdarkChance   = d 54 + dl 20   , cnightChance  = 51  -- always night-  , cauxConnects  = 1%3+  , cauxConnects  = 1%2   , cmaxVoid      = 1%6-  , cminStairDist = 30-  , cdoorChance   = 1%2-  , copenChance   = 1%10-  , chidden       = 8-  , cactorCoeff   = 150  -- the maze requires time to explore-  , cactorFreq    = [("alien", 50), ("animal", 25), ("robot", 25)]-  , citemNum      = 10 * d 2+  , cminStairDist = 15+  , cextraStairs  = 1 + d 2+  , cdoorChance   = 3%4+  , copenChance   = 1%5+  , chidden       = 7+  , cactorCoeff   = 130  -- the maze requires time to explore+  , cactorFreq    = [("monster", 50), ("animal", 25), ("robot", 25)]+  , citemNum      = 5 * d 5   , citemFreq     = [("useful", 50), ("treasure", 50)]   , cplaceFreq    = [("rogue", 100)]   , cpassable     = False@@ -55,193 +63,370 @@   , couterFenceTile = "basic outer fence"   , clegendDarkTile = "legendDark"   , clegendLitTile  = "legendLit"+  , cescapeGroup    = Nothing+  , cstairFreq      = [("staircase lift", 100)]   }+rogue2 = rogue+  { cfreq         = [("deep random", 20)]+  , cname         = "Dark storage area"+  , cdarkChance   = 51  -- all rooms dark+  , cnightChance  = 0  -- always day+  } arena = rogue   { csymbol       = 'A'   , cname         = "Recreational deck"-  , cfreq         = [("campaign random", 50), ("caveArena", 1)]-  , cgrid         = DiceXY (2 * d 2) (2 * d 2)-  , cminPlaceSize = DiceXY (2 * d 2 + 3) 4-  , cdarkChance   = d 100 - dl 50-  -- Trails provide enough light for fun stealth. Light is not too deadly,-  -- because not many obstructions, so foes visible from far away.-  , cnightChance  = d 50 + dl 50-  , cmaxVoid      = 1%4-  , chidden       = 1000+  , cfreq         = [ ("default random", 40), ("deep random", 30)+                    , ("caveArena", 1) ]+  , cgrid         = DiceXY (2 + d 2) (d 3)+  , cminPlaceSize = DiceXY (2 * d 2 + 4) 6+  , cmaxPlaceSize = DiceXY 16 12+  , cdarkChance   = 49 + d 10  -- almost all rooms dark (1 in 10 lit)+  -- Light is not too deadly, because not many obstructions and so+  -- foes visible from far away and few foes have ranged combat.+  , cnightChance  = 0  -- always day+  , cauxConnects  = 1+  , cmaxVoid      = 1%8+  , cextraStairs  = d 3+  , chidden       = 0   , cactorCoeff   = 100-  , cactorFreq    = [("alien", 25), ("animal", 70), ("robot", 5)]-  , citemNum      = 9 * d 2  -- few rooms+  , cactorFreq    = [("monster", 25), ("animal", 70), ("robot", 5)]+  , citemNum      = 4 * d 5  -- few rooms+  , citemFreq     = [("useful", 20), ("treasure", 30), ("any scroll", 50)]+  , cplaceFreq    = [("arena", 100)]   , cpassable     = True-  , cdefTile      = "arenaSet"-  , cdarkCorTile  = "trailLit"  -- let trails give off light+  , cdefTile      = "arenaSetLit"   , clitCorTile   = "trailLit"   }+arena2 = arena+  { cname         = "Casino"+  , cfreq         = [("deep random", 10)]+  , cdarkChance   = 41 + d 10  -- almost all rooms lit (1 in 10 dark)+  -- Trails provide enough light for fun stealth.+  , cnightChance  = 51  -- always night+  , citemNum      = 6 * d 5  -- rare, so make it exciting+  , citemFreq     = [("useful", 30), ("treasure", 70)] -- lives up to the name+  , cdefTile      = "arenaSetDark"+  , cdarkCorTile  = "trailLit"  -- let trails give off light+  }+laboratory = arena2+  { csymbol       = 'L'+  , cname         = "Laboratory"+  , cfreq         = [("deep random", 20), ("caveLaboratory", 1)]+  , cgrid         = DiceXY (2 * d 2 + 7) 3+  , cminPlaceSize = DiceXY (3 * d 2 + 4) 5+  , cdarkChance   = d 54 + dl 20  -- most rooms lit, to compensate for corridors+  , cnightChance  = 0  -- always day+  , cauxConnects  = 1%10+  , cmaxVoid      = 1%10+  , cextraStairs  = d 2+  , cdoorChance   = 1+  , copenChance   = 1%2+  , chidden       = 7+  , citemNum      = 6 * d 5  -- reward difficulty+  , citemFreq     = [("useful", 20), ("treasure", 30), ("any vial", 50)]+  , cplaceFreq    = [("laboratory", 100)]+  , cpassable     = False+  , cdefTile      = "fillerWall"+  , clitCorTile   = "labTrailLit"+  , cstairFreq    = [("staircase lift", 100)]+  } empty = rogue   { csymbol       = 'E'   , cname         = "Construction site"-  , cfreq         = [("campaign random", 50), ("caveEmpty", 1)]-  , cgrid         = DiceXY (d 2 + 1) 1-  , cminPlaceSize = DiceXY 10 10-  , cmaxPlaceSize = DiceXY 24 15-  , cdarkChance   = d 80 + dl 80+  , cfreq         = [("deep random", 10), ("caveEmpty", 1)]+  , cgrid         = DiceXY 1 1+  , cminPlaceSize = DiceXY 12 12+  , cmaxPlaceSize = DiceXY 48 32  -- favour large rooms+  , cdarkChance   = d 100 + dl 100   , cnightChance  = 0  -- always day-  , cauxConnects  = 1-  , cmaxVoid      = 1%2-  , cminStairDist = 50-  , chidden       = 1000+  , cauxConnects  = 3%2+  , cminStairDist = 30+  , cmaxVoid      = 0  -- too few rooms to have void and fog common anyway+  , cextraStairs  = d 2+  , cdoorChance   = 0+  , copenChance   = 0+  , chidden       = 0   , cactorCoeff   = 80-  , cactorFreq    = [("alien", 25), ("animal", 5), ("robot", 70)]-  , citemNum      = 7 * d 2  -- few rooms+  , cactorFreq    = [("monster", 25), ("animal", 5), ("robot", 70)]+  , citemNum      = 4 * d 5  -- few rooms+  , cplaceFreq    = [("empty", 100)]   , cpassable     = True   , cdefTile      = "emptySet"   , cdarkCorTile  = "floorArenaDark"   , clitCorTile   = "floorArenaLit"+  , cstairFreq    = [("staircase", 50), ("staircase lift", 50)]   } noise = rogue   { csymbol       = 'N'-  , cname         = "Machine rooms"+  , cname         = "Flight hardware hub"   , cfreq         = [("caveNoise", 1)]-  , cgrid         = DiceXY (2 + d 2) 3-  , cminPlaceSize = DiceXY 12 5-  , cmaxPlaceSize = DiceXY 24 15-  , cdarkChance   = 0  -- few rooms, so all lit+  , cgrid         = DiceXY (2 + d 3) 3+  , cminPlaceSize = DiceXY 8 5+  , cmaxPlaceSize = DiceXY 20 10+  , cdarkChance   = 51   -- Light is deadly, because nowhere to hide and pillars enable spawning-  -- very close to heroes, so deep down light should be rare.-  , cnightChance  = dl 300-  , cauxConnects  = 0-  , cmaxVoid      = 0-  , chidden       = 1000+  -- very close to heroes.+  , cnightChance  = 0  -- harder variant, but looks cheerful+  , cauxConnects  = 1%10+  , cmaxVoid      = 1%100+  , cextraStairs  = d 4+  , cdoorChance   = 1  -- to enable the doorlessWall hack and have no lit tiles+  , chidden       = 0   , cactorCoeff   = 160  -- the maze requires time to explore-  , cactorFreq    = [("alien", 70), ("animal", 15), ("robot", 15)]-  , citemNum      = 12 * d 2  -- an incentive to explore the labyrinth+  , cactorFreq    = [("monster", 70), ("animal", 15), ("robot", 15)]+  , citemNum      = 6 * d 5  -- an incentive to explore the labyrinth   , cpassable     = True   , cplaceFreq    = [("noise", 100)]   , cdefTile      = "noiseSet"+  , couterFenceTile = "noise fence"  -- ensures no cut-off parts from collapsed   , cdarkCorTile  = "floorArenaDark"   , clitCorTile   = "floorArenaLit"   }-battle = rogue  -- few lights and many solids, to help the less numerous heroes+noise2 = noise+  { cname         = "Power distribution hub"+  , cfreq         = [("caveNoise2", 1)]+  , cnightChance  = 51  -- easier variant, but looks sinister+  , cplaceFreq    = [("noise", 1), ("mine", 99)]+  , cstairFreq    = [("gated staircase", 100)]+  }+bridge = rogue   { csymbol       = 'B'-  , cname         = "Ravaged spaceport"-  , cfreq         = [("caveBattle", 1)]-  , cgrid         = DiceXY (2 * d 2 + 1) 3-  , cminPlaceSize = DiceXY 4 4-  , cmaxPlaceSize = DiceXY 9 7-  , cdarkChance   = 0-  , cnightChance  = 51  -- always night-  , cmaxVoid      = 0-  , cdoorChance   = 2%10-  , copenChance   = 9%10-  , chidden       = 1000-  , cactorFreq    = []-  , citemNum      = 20 * d 2-  , citemFreq     = [("useful", 100), ("light source", 200)]-  , cplaceFreq    = [("battle", 50), ("rogue", 50)]-  , cpassable     = True-  , cdefTile      = "battleSet"-  , cdarkCorTile  = "trailLit"  -- let trails give off light-  , clitCorTile   = "trailLit"+  , cname         = "Captain's bridge"+  , cfreq         = [("caveBridge", 1)]+  , cdarkChance   = 0  -- all rooms lit, for a gentle start+  , cextraStairs  = 1+  , cactorFreq    = []  -- safe, nothing spawns+  , citemNum      = 8 * d 5  -- lure them in with loot+  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq rogue   }-skirmish = rogue  -- many random solid tiles, to break LOS, since it's a day+shallow2rogue = rogue+  { cfreq         = [("shallow random 2", 50)]+  , cactorCoeff   = cactorCoeff rogue `div` 2  -- more difficult+  , cactorFreq    = filter ((/= "monster") . fst) $ cactorFreq rogue+  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq rogue+  }+shallow2arena = arena+  { cfreq         = [("shallow random 2", 100)]+  , cactorCoeff   = cactorCoeff arena `div` 2+  , cactorFreq    = filter ((/= "monster") . fst) $ cactorFreq empty+  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq empty+  }+shallow2empty = empty+  { cfreq         = [("shallow random 2", 10)]+  , cactorCoeff   = cactorCoeff empty `div` 2+  , cactorFreq    = filter ((/= "monster") . fst) $ cactorFreq empty+  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq empty+  }+shallow1empty = shallow2empty  -- TODO: replace some rooms with oriels?+  { cname         = "Outermost deck"+  , cfreq         = [("outermost", 100)]+  , cactorCoeff   = 5  -- shallower than LH, so less immediate actors, so boost+  , cactorFreq    = [("animal", 4), ("robot", 1), ("immobile robot", 95)]+      -- The medbot faucets on lvl 1 act like HP resets. Needed to avoid+      -- cascading failure, if the particular starting conditions were+      -- very hard. Items are not reset, even if they are bad, which provides+      -- enough of a continuity. The faucets on lvl 1 are not OP and can't be+      -- abused, because they spawn less and less often and also HP doesn't+      -- effectively accumulate over max.+  , couterFenceTile = "oriels fence"+  }+emptyExit = empty+  { cname         = "Shuttle servicing area"+  , cfreq = [("caveEmptyExit", 1)]+  , cdarkCorTile  = "trailLit"  -- flavour+  , couterFenceTile = "noise fence"  -- for flavour+  , cescapeGroup = Just "escape spaceship down"+  }+raid = rogue   { csymbol       = 'S'+  , cname         = "Triton City sewers"+  , cfreq         = [("caveRaid", 1)]+  , cdarkChance   = 0  -- all rooms lit, for a gentle start+  , cmaxVoid      = 1%10+  , cactorCoeff   = 1000  -- deep level with no kit, so slow spawning+  , cactorFreq    = [("animal", 50), ("robot", 50)]+  , citemNum      = 6 * d 8  -- just one level, hard enemies, treasure+  , citemFreq     = [("useful", 33), ("gem", 33), ("currency", 33)]+  , cescapeGroup  = Just "escape up"+  }+brawl = rogue  -- many random solid tiles, to break LOS, since it's a day+               -- and this scenario is not focused on ranged combat;+               -- also, sanctuaries against missiles in shadow under trees+  { csymbol       = 'S'   , cname         = "Woodland biosphere"-  , cfreq         = [("caveSkirmish", 1)]-  , cgrid         = DiceXY (2 * d 2 + 2) (d 2 + 2)+  , cfreq         = [("caveBrawl", 1)]+  , cgrid         = DiceXY (2 * d 2 + 2) 3   , cminPlaceSize = DiceXY 3 3   , cmaxPlaceSize = DiceXY 7 5-  , cdarkChance   = 100+  , cdarkChance   = 51   , cnightChance  = 0   , cdoorChance   = 1   , copenChance   = 0-  , chidden       = 1000+  , cextraStairs  = 1+  , chidden       = 0   , cactorFreq    = []-  , citemNum      = 20 * d 2+  , citemNum      = 5 * d 8   , citemFreq     = [("useful", 100)]-  , cplaceFreq    = [("skirmish", 60), ("rogue", 40)]+  , cplaceFreq    = [("brawl", 60), ("rogue", 40)]   , cpassable     = True-  , cdefTile      = "skirmishSet"+  , cdefTile      = "brawlSetLit"   , cdarkCorTile  = "floorArenaLit"   , clitCorTile   = "floorArenaLit"   }-ambush = rogue  -- lots of lights, to give a chance to snipe+shootout = rogue  -- a scenario with strong missiles;+                  -- few solid tiles, but only translucent tiles or walkable+                  -- opaque tiles, to make scouting and sniping more interesting+                  -- and to avoid obstructing view too much, since this+                  -- scenario is about ranged combat at long range+  { csymbol       = 'S'+  , cname         = "Hydroponic farm"  -- still a neutral, offcial wording+  , cfreq         = [("caveShootout", 1)]+  , cgrid         = DiceXY (d 2 + 7) 3+  , cminPlaceSize = DiceXY 3 3+  , cmaxPlaceSize = DiceXY 3 4+  , cdarkChance   = 51+  , cnightChance  = 0+  , cdoorChance   = 1+  , copenChance   = 0+  , cextraStairs  = 1+  , chidden       = 0+  , cactorFreq    = []+  , citemNum      = 5 * d 16+                      -- less items in inventory, more to be picked up,+                      -- to reward explorer and aggressor and punish camper+  , citemFreq     = [ ("useful", 30)+                    , ("any arrow", 400), ("harpoon", 300)+                    , ("any vial", 60) ]+                      -- Many consumable buffs are needed in symmetric maps+                      -- so that aggresor prepares them in advance and camper+                      -- needs to waste initial turns to buff for the defence.+  , cplaceFreq    = [("shootout", 100)]+  , cpassable     = True+  , cdefTile      = "shootoutSetLit"+  , cdarkCorTile  = "floorArenaLit"+  , clitCorTile   = "floorArenaLit"+  }+escape = rogue  -- a scenario with weak missiles, because heroes don't depend+                -- on them; dark, so solid obstacles are to hide from missiles,+                -- not view; obstacles are not lit, to frustrate the AI;+                -- lots of small lights to cross, to have some risks+  { csymbol       = 'E'+  , cname         = "Red Collar Bros den"  -- tension rises; non-official name+  , cfreq         = [("caveEscape", 1)]+  , cgrid         = DiceXY -- (2 * d 2 + 3) 4  -- park, so lamps in lines+                           (2 * d 2 + 6) 3   -- for now, to fit larger places+  , cminPlaceSize = DiceXY 3 3+  , cmaxPlaceSize = DiceXY 9 9  -- bias towards larger lamp areas+  , cdarkChance   = 51  -- colonnade rooms should always be dark+  , cnightChance  = 51  -- always night+  , cauxConnects  = 3%2+  , cmaxVoid      = 1%20+  , cextraStairs  = 1+  , chidden       = 0+  , cactorFreq    = []+  , citemNum      = 5 * d 8+  , citemFreq     = [ ("useful", 30), ("treasure", 30), ("gem", 100)+                    , ("weak arrow", 500), ("harpoon", 400) ]+  , cplaceFreq    = [("park", 100)]+  , cpassable     = True+  , cdefTile      = "escapeSetDark"  -- different tiles, not burning yet+  , cdarkCorTile  = "trailLit"  -- let trails give off light+  , clitCorTile   = "trailLit"+  , cescapeGroup  = Just "escape outdoor down"+  }+zoo = rogue  -- few lights and many solids, to help the less numerous heroes+  { csymbol       = 'Z'+  , cname         = "Municipal zoo in flames"  -- non-official adjective+  , cfreq         = [("caveZoo", 1)]+  , cgrid         = DiceXY (2 * d 2 + 6) 3+  , cminPlaceSize = DiceXY 4 4+  , cmaxPlaceSize = DiceXY 12 12+  , cdarkChance   = 51  -- always dark rooms+  , cnightChance  = 51  -- always night+  , cauxConnects  = 1%4+  , cmaxVoid      = 1%20+  , cdoorChance   = 2%10+  , copenChance   = 9%10+  , cextraStairs  = 1+  , chidden       = 0+  , cactorFreq    = []+  , citemNum      = 7 * d 8+  , citemFreq     = [("useful", 100), ("light source", 1000)]+  , cplaceFreq    = [("zoo", 50)]+  , cpassable     = True+  , cdefTile      = "zooSet"+  , cdarkCorTile  = "trailLit"  -- let trails give off light+  , clitCorTile   = "trailLit"+  }+ambush = rogue  -- a scenario with strong missiles;+                -- dark, so solid obstacles are to hide from missiles,+                -- not view, and they are all lit, because stopped missiles+                -- are frustrating, while a few LOS-only obstacles are not lit;+                -- lots of small lights to cross, to give a chance to snipe;+                -- a crucial difference wrt shootout is that trajectories+                -- of missiles are usually not seen, so enemy can't be guessed;+                -- camping doesn't pay off, because enemies can sneak and only+                -- active scouting, throwing flares and shooting discovers them   { csymbol       = 'M'-  , cname         = "Public garden"+  , cname         = "Ravaged spaceport"  -- non-official adjective   , cfreq         = [("caveAmbush", 1)]-  , cgrid         = DiceXY (2 * d 2 + 3) (d 2 + 2)+  , cgrid         = DiceXY -- (2 * d 2 + 3) 4  -- spaceport, so lamps in lines+                           (2 * d 2 + 5) 3   -- for now, to fit larger places   , cminPlaceSize = DiceXY 3 3-  , cmaxPlaceSize = DiceXY 5 5-  , cdarkChance   = 0+  , cmaxPlaceSize = DiceXY 15 15  -- allow hangars+  , cdarkChance   = 51   , cnightChance  = 51  -- always night-  , cauxConnects  = 1-  , cdoorChance   = 1%10-  , copenChance   = 9%10-  , chidden       = 1000+  , cauxConnects  = 3%2+  , cmaxVoid      = 1%20+  , cextraStairs  = 1+  , chidden       = 0   , cactorFreq    = []-  , citemNum      = 22 * d 2-  , citemFreq     = [("useful", 100)]+  , citemNum      = 5 * d 8+  , citemFreq     = [("useful", 30), ("any arrow", 400), ("harpoon", 300)]   , cplaceFreq    = [("ambush", 100)]   , cpassable     = True   , cdefTile      = "ambushSet"   , cdarkCorTile  = "trailLit"  -- let trails give off light   , clitCorTile   = "trailLit"   }-safari1 = ambush {cfreq = [("caveSafari1", 1)]}-safari2 = battle {cfreq = [("caveSafari2", 1)]}-safari3 = skirmish {cfreq = [("caveSafari3", 1)]}-rogueLit = rogue-  { csymbol       = 'S'-  , cname         = "Triton City Sewers"-  , cfreq         = [("caveRogueLit", 1)]-  , cdarkChance   = 0-  , cmaxVoid      = 1%10-  , cactorCoeff   = 1000  -- deep level with no eqp, so slow spawning-  , cactorFreq    = [("animal", 50), ("robot", 50)]-  , citemNum      = 30 * d 2  -- just one level, hard enemies, treasure-  , citemFreq     = [("useful", 33), ("gem", 33), ("currency", 33)]-  , cdarkCorTile  = "emergency walkway"-  , clitCorTile   = "emergency walkway"-  }-bridge = rogueLit+battle = rogue  -- few lights and many solids, to help the less numerous heroes   { csymbol       = 'B'-  , cname         = "Captain's bridge"-  , cfreq         = [("caveBridge", 1)]-  , cgrid         = DiceXY (d 2 + 1) 2-  , cminPlaceSize = DiceXY 10 7-  , cmaxPlaceSize = DiceXY 40 14-  , cactorFreq    = []  -- safe, nothing spawns-  , citemNum      = 15 * d 2  -- lure them in with loot-  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq rogue-  }-shallow2rogue = rogue-  { cfreq         = [("shallow random 2", 50)]-  , cactorCoeff   = cactorCoeff rogue `div` 2-  , cactorFreq    = filter ((/= "alien") . fst) $ cactorFreq rogue-  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq rogue+  , cname         = "Burning public park"+  , cfreq         = [("caveBattle", 1)]+  , cgrid         = DiceXY (2 * d 2 + 1) 3+  , cminPlaceSize = DiceXY 4 4+  , cmaxPlaceSize = DiceXY 9 7+  , cdarkChance   = 0+  , cnightChance  = 51  -- always night+  , cauxConnects  = 1%4+  , cmaxVoid      = 1%20+  , cdoorChance   = 2%10+  , copenChance   = 9%10+  , cextraStairs  = 1+  , chidden       = 0+  , cactorFreq    = []+  , citemNum      = 5 * d 8+  , citemFreq     = [("useful", 100), ("light source", 200)]+  , cplaceFreq    = [("battle", 50), ("rogue", 50)]+  , cpassable     = True+  , cdefTile      = "battleSet"+  , cdarkCorTile  = "trailLit"  -- let trails give off light+  , clitCorTile   = "trailLit"+  , couterFenceTile = "noise fence"  -- ensures no cut-off parts from collapsed   }-shallow2arena = arena-  { cfreq         = [("shallow random 2", 100)]-  , cnightChance  = 0  -- safe and easy-  , cactorCoeff   = cactorCoeff arena `div` 2-  , cactorFreq    = filter ((/= "alien") . fst) $ cactorFreq empty-  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq empty+safari1 = brawl+  { cname = "Hunam habitat"+  , cfreq = [("caveSafari1", 1)]+  , cescapeGroup = Nothing+  , cstairFreq = [("staircase outdoor", 1)]   }-shallow2empty = empty-  { cfreq         = [("shallow random 2", 20)]-  , cactorFreq    = filter ((/= "alien") . fst) $ cactorFreq empty-  , cactorCoeff   = cactorCoeff empty `div` 2-  , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq empty+safari2 = ambush+  { cname = "Hunting grounds"+  , cfreq = [("caveSafari2", 1)]+  , cstairFreq = [("staircase outdoor", 1)]   }-shallow1arena = shallow2empty  -- TODO: replace some rooms with oriels?-  { cname         = "Outermost deck"-  , cfreq         = [("shallow random 1", 100)]-  , cminPlaceSize = DiceXY (2 * d 2 + 3) 3-  , cactorCoeff   = 3  -- mostly immobile actors anyway-  , cactorFreq    = [("animal", 8), ("robot", 2), ("immobile robot", 90)]-      -- The medbot faucets on lvl 1 act like HP resets. They are needed to avoid-      -- cascading failure, if the particular starting conditions were-      -- very hard. The items are not reset, even if the are bad, which provides-      -- enough of a continuity. The faucets on lvl 1 are not OP and can't be-      -- abused, because they spawn less and less often and they don't heal over-      -- max HP.-  , couterFenceTile = "oriels fence"+safari3 = zoo+  { cfreq = [("caveSafari3", 1)]+  , cescapeGroup = Just "escape outdoor down"+  , cstairFreq = [("staircase outdoor", 1)]   }
GameDefinition/Content/ItemKind.hs view
@@ -1,1031 +1,1278 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski--- This file is a part of the computer game Allure of the Stars--- and is released under the terms of the GNU Affero General Public License.--- For license and copyright information, see the file LICENSE.------ | Item and treasure definitions.-module Content.ItemKind ( cdefs ) where--import qualified Data.EnumMap.Strict as EM-import Data.List--import Content.ItemKindActor-import Content.ItemKindBlast-import Content.ItemKindOrgan-import Content.ItemKindTemporary-import Game.LambdaHack.Common.Ability-import Game.LambdaHack.Common.Color-import Game.LambdaHack.Common.ContentDef-import Game.LambdaHack.Common.Dice-import Game.LambdaHack.Common.Flavour-import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Content.ItemKind--cdefs :: ContentDef ItemKind-cdefs = ContentDef-  { getSymbol = isymbol-  , getName = iname-  , getFreq = ifreq-  , validateSingle = validateSingleItemKind-  , validateAll = validateAllItemKind-  , content = items ++ organs ++ blasts ++ actors ++ temporaries-  }--items :: [ItemKind]-items =-  [dart, dart200, paralizingProj, harpoon, net, needle, jumpingPole, sharpeningTool, seeingItem, light1, light2, light3, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, constructionHooter, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency]--dart,    dart200, paralizingProj, harpoon, net, needle, jumpingPole, sharpeningTool, seeingItem, light1, light2, light3, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, constructionHooter, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency :: ItemKind--necklace, ring, potion, flask, scroll, wand, gem :: ItemKind  -- generic templates---- * Item group symbols, from Angband and variants--symbolProjectile, _symbolLauncher, symbolLight, symbolTool, symbolGem, symbolGold, symbolNecklace, symbolRing, symbolPotion, symbolFlask, symbolScroll, symbolTorsoArmor, symbolMiscArmor, _symbolClothes, symbolShield, symbolPolearm, symbolEdged, symbolHafted, symbolWand, _symbolStaff, _symbolFood :: Char--symbolProjectile = '{'-_symbolLauncher  = '}'-symbolLight      = '~'-symbolTool       = '~'-symbolGem        = '*'-symbolGold       = '$'-symbolNecklace   = '"'-symbolRing       = '='-symbolPotion     = '!'  -- concoction, bottle, jar, vial, canister-symbolFlask      = '!'-symbolScroll     = '?'  -- book, note, tablet, remote, chip, card-symbolTorsoArmor = '['-symbolMiscArmor  = ']'-_symbolClothes   = '('-symbolShield     = ')'-symbolPolearm    = '/'-symbolEdged      = '|'-symbolHafted     = '\\'-symbolWand       = '-'  -- magical rod, transmitter, pistol, rifle-_symbolStaff     = '_'  -- scanner-_symbolFood      = ','  -- too easy to miss?---- * Thrown weapons--dart = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "steak knife"-  , ifreq    = [("useful", 100), ("any arrow", 100)]-  , iflavour = zipPlain [BrCyan]-  , icount   = 4 * d 3-  , irarity  = [(1, 10), (10, 20)]-  , iverbHit = "nick"-  , iweight  = 100-  , iaspects = [AddHurtRanged (d 3 + dl 6 |*| 20)]-  , ieffects = [Hurt (2 * d 1)]-  , ifeature = [toVelocity 75, Identified]  -- no fins, no special balance-  , idesc    = "Not particularly well balanced, but with a laser-sharpened titanium tip and blade."-  , ikit     = []-  }-dart200 = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "billiard ball"-  , ifreq    = [("useful", 100), ("any arrow", 50)]  -- TODO: until arrows added-  , iflavour = zipPlain [BrWhite]-  , icount   = 4 * d 3-  , irarity  = [(1, 20), (10, 10)]-  , iverbHit = "strike"-  , iweight  = 300-  , iaspects = [AddHurtRanged (d 3 + dl 6 |*| 20)]-  , ieffects = [Hurt (1 * d 1)]-  , ifeature = [toVelocity 150, Identified]-  , idesc    = "Ideal shape, size and weight for throwing."-  , ikit     = []-  }---- * Exotic thrown weapons--paralizingProj = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "can"-  , ifreq    = [("useful", 100), ("can of sticky foam", 1)]-  , iflavour = zipPlain [Magenta]-  , icount   = dl 3-  , irarity  = [(5, 5), (10, 20)]-  , iverbHit = "glue"-  , iweight  = 1500-  , iaspects = []-  , ieffects = [ NoEffect "of sticky foam", Paralyze (5 + d 7)-               , OnSmash (Explode "glue")]-  , ifeature = [toVelocity 50, Identified, Fragile]  -- unwieldy-  , idesc    = "A can of liquid, fast-setting, construction foam."-  , ikit     = []-  }-harpoon = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "harpoon"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [Brown]-  , icount   = dl 5-  , irarity  = [(5, 5), (10, 5)]-  , iverbHit = "hook"-  , iweight  = 4000-  , iaspects = [AddHurtRanged (d 2 + dl 5 |*| 20)]-  , ieffects = [Hurt (4 * d 1), PullActor (ThrowMod 200 50)]-  , ifeature = [Identified]-  , idesc    = "A display piece harking back to the Earth's oceanic tourism hayday. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying."-  , ikit     = []-  }-net = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "net"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [White]-  , icount   = dl 3-  , irarity  = [(3, 5), (10, 4)]-  , iverbHit = "entangle"-  , iweight  = 1000-  , iaspects = []-  , ieffects = [ toOrganGameTurn "slow 10" (3 + d 3)-               , DropItem CEqp "torso armor" False ]-  , ifeature = [Identified]-  , idesc    = "A large synthetic fibre net with weights affixed along the edges. Entangles armor and restricts movement."-  , ikit     = []-  }-needle = ItemKind-  { isymbol  = symbolProjectile-  , iname    = "needle"-  , ifreq    = [("needle", 1)]  -- special-  , iflavour = zipPlain [BrBlue]-  , icount   = 9 * d 3-  , irarity  = [(1, 1)]-  , iverbHit = "prick"-  , iweight  = 1-  , iaspects = [AddHurtRanged (d 3 + dl 3 |*| 10)]-  , ieffects = [Hurt (1 * d 1)]-  , ifeature = [toVelocity 200, Fragile]-  , idesc    = "The hypodermic needle part of a micro-syringe. Without the payload, it flies far and penetrates deeply, causing intense pain on movement."-  , ikit     = []-  }---- * Assorted tools--jumpingPole = ItemKind-  { isymbol  = symbolTool-  , iname    = "jumping pole"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [White]-  , icount   = 1-  , irarity  = [(1, 2)]-  , iverbHit = "prod"-  , iweight  = 10000-  , iaspects = [Timeout $ d 2 + 2 - dl 2 |*| 10]-  , ieffects = [Recharging (toOrganActorTurn "fast 20" 1)]-  , ifeature = [Durable, Applicable, Identified]-  , idesc    = "Makes you vulnerable at take-off, but then you are free like a bird."-  , ikit     = []-  }-sharpeningTool = ItemKind-  { isymbol  = symbolTool-  , iname    = "honing steel"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [Blue]-  , icount   = 1-  , irarity  = [(10, 10)]-  , iverbHit = "smack"-  , iweight  = 400-  , iaspects = [AddHurtMelee $ d 10 |*| 3]-  , ieffects = []-  , ifeature = [EqpSlot EqpSlotAddHurtMelee "", Identified]-  , idesc    = "Originally used for realigning the bent or buckled edges of kitchen knives in the local bars. Now it saves lives by letting you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop."-  , ikit     = []-  }-seeingItem = ItemKind-  { isymbol  = '%'-  , iname    = "visual sensor"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [Red]-  , icount   = 1-  , irarity  = [(1, 1)]-  , iverbHit = "gaze at"-  , iweight  = 500-  , iaspects = [ AddSight 10, AddMaxCalm 60, AddLight 2-               , Periodic, Timeout $ 1 + d 2 ]-  , ieffects = [ Recharging (toOrganNone "poisoned")-               , Recharging (Summon [("mobile robot", 1)] 1) ]-  , ifeature = [Identified]-  , idesc    = "A functioning visual sensor torn out from some giant robot. The circuitry is too big to serve just the basic signal processing. Watch out for the sharp edges and the seeping coolant liquid."-  , ikit     = []-  }--- * Lights--light1 = ItemKind-  { isymbol  = symbolLight-  , iname    = "candle"-  , ifreq    = [("useful", 100), ("light source", 100)]-  , iflavour = zipPlain [Brown]-  , icount   = d 2-  , irarity  = [(1, 10)]-  , iverbHit = "scorch"-  , iweight  = 500-  , iaspects = [ AddLight 3-               , AddSight (-2) ]-  , ieffects = [Burn 2]-  , ifeature = [ toVelocity 50  -- easy to break when throwing-               , Fragile, EqpSlot EqpSlotAddLight "", Identified ]-  , idesc    = "A smoking, thick candle with an unsteady fire."-  , ikit     = []-  }-light2 = ItemKind-  { isymbol  = symbolLight-  , iname    = "oil lamp"-  , ifreq    = [("useful", 100), ("light source", 100)]-  , iflavour = zipPlain [BrYellow]-  , icount   = 1-  , irarity  = [(6, 7)]-  , iverbHit = "burn"-  , iweight  = 1000-  , iaspects = [AddLight 3, AddSight (-1)]-  , ieffects = [Burn 3, Paralyze 3, OnSmash (Explode "burning oil 3")]-  , ifeature = [ toVelocity 70  -- hard not to spill the oil while throwing-               , Fragile, EqpSlot EqpSlotAddLight "", Identified ]-  , idesc    = "A sizable glass lamp filled with plant oil feeding a wick."-  , ikit     = []-  }-light3 = ItemKind-  { isymbol  = symbolLight-  , iname    = "crank spotlight"-  , ifreq    = [("useful", 100), ("light source", 100)]-  , iflavour = zipPlain [BrWhite]-  , icount   = 1-  , irarity  = [(10, 5)]-  , iverbHit = "snag"-  , iweight  = 2400-  , iaspects = [AddLight 4, AddArmorRanged $ - d 3]  -- noise and busy hands-  , ieffects = []-  , ifeature = [ EqpSlot EqpSlotAddLight "", Identified ]-  , idesc    = "Powerful, wide-beam spotlight, powered by a hand-crank. Requires noisy two-handed recharging every few minutes."-  , ikit     = []-  }---- * Periodic jewelry--gorget = ItemKind-  { isymbol  = symbolNecklace-  , iname    = "Old Gorget"-  , ifreq    = [("useful", 100)]-  , iflavour = zipFancy [BrCyan]-  , icount   = 1-  , irarity  = [(4, 3), (10, 3)]  -- weak, shallow-  , iverbHit = "whip"-  , iweight  = 30-  , iaspects = [ Unique-               , Periodic-               , Timeout $ 1 + d 2-               , AddArmorMelee $ 2 + d 3-               , AddArmorRanged $ 2 + d 3 ]-  , ieffects = [Recharging (RefillCalm 1)]-  , ifeature = [ Durable, Precious, EqpSlot EqpSlotPeriodic ""-               , Identified, toVelocity 50 ]  -- not dense enough-  , idesc    = "Highly ornamental, cold, large, steel medallion on a chain. Unlikely to offer much protection as an armor piece, but the old, worn engraving reassures you."-  , ikit     = []-  }-necklace = ItemKind-  { isymbol  = symbolNecklace-  , iname    = "necklace"-  , ifreq    = [("useful", 100)]-  , iflavour = zipFancy stdCol ++ zipPlain brightCol-  , icount   = 1-  , irarity  = [(10, 2)]-  , iverbHit = "whip"-  , iweight  = 30-  , iaspects = [Periodic]-  , ieffects = []-  , ifeature = [ Precious, EqpSlot EqpSlotPeriodic ""-               , toVelocity 50 ]  -- not dense enough-  , idesc    = "Tingling, rattling chain of flat encrusted links. Eccentric millionaires are known to hide their highly personalized body augmentation packs in such large jewelry pieces."-  , ikit     = []-  }-necklace1 = necklace-  { ifreq    = [("treasure", 100)]-  , irarity  = [(3, 0), (4, 1), (10, 2)]  -- prevents camping on lvl 3-  , iaspects = [Unique, Timeout $ d 3 + 4 - dl 3 |*| 10]-               ++ iaspects necklace-  , ieffects = [NoEffect "of Trickle Life", Recharging (RefillHP 1)]-  , ifeature = Durable : ifeature necklace-  }-necklace2 = necklace-  { ifreq    = [("treasure", 100)]  -- just too nasty to call it useful-  , irarity  = [(1, 1)]-  , iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 10) : iaspects necklace-  , ieffects = [ Recharging Impress-               , Recharging (DropItem COrgan "temporary conditions" True)-               , Recharging (Summon [("mobile animal", 1)] $ 1 + dl 2)-               , Recharging (Explode "waste") ]-  }-necklace3 = necklace-  { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 10) : iaspects necklace-  , ieffects = [Recharging (Paralyze $ 5 + d 5 + dl 5)]-  }-necklace4 = necklace-  { iaspects = (Timeout $ d 4 + 4 - dl 4 |*| 2) : iaspects necklace-  , ieffects = [Recharging (Teleport $ d 2 * 3)]-  }-necklace5 = necklace-  { iaspects = (Timeout $ d 3 + 4 - dl 3 |*| 10) : iaspects necklace-  , ieffects = [Recharging (Teleport $ 14 + d 3 * 3)]-  }-necklace6 = necklace-  { iaspects = (Timeout $ d 4 |*| 10) : iaspects necklace-  , ieffects = [Recharging (PushActor (ThrowMod 100 50))]-  }-necklace7 = necklace  -- TODO: teach AI to wear only for fight-  { ifreq    = [("treasure", 100)]-  , iaspects = [ Unique, AddMaxHP $ 10 + d 10-               , AddArmorMelee 20, AddArmorRanged 20-               , Timeout $ d 2 + 5 - dl 3 ]-               ++ iaspects necklace-  , ieffects = [ NoEffect "of Overdrive"-               , Recharging (InsertMove $ 1 + d 2)-               , Recharging (RefillHP (-1))-               , Recharging (RefillCalm (-1)) ]-  , ifeature = Durable : ifeature necklace-  }-necklace8 = necklace-  { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 5) : iaspects necklace-  , ieffects = [Recharging $ Explode "spark"]-  }-necklace9 = necklace-  { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 5) : iaspects necklace-  , ieffects = [Recharging $ Explode "fragrance"]-  }---- * Non-periodic jewelry--sightSharpening = ItemKind-  { isymbol  = symbolRing-  , iname    = "Autozoom Contact Lens"-  , ifreq    = [("treasure", 100)]-  , iflavour = zipPlain [White]-  , icount   = 1-  , irarity  = [(7, 3), (10, 3)]  -- medium weak, medium shallow-  , iverbHit = "rap"-  , iweight  = 50-  , iaspects = [Unique, AddSight $ 1 + d 2, AddHurtMelee $ d 2 |*| 3]-  , ieffects = []-  , ifeature = [ Precious, Identified, Durable-               , EqpSlot EqpSlotAddSight "" ]-  , idesc    = "Zooms on any movement, distant or close. Requires some getting used to. Never needs to be taken off."-  , ikit     = []-  }--- Don't add standard effects to rings, because they go in and out--- of eqp and so activating them would require UI tedium: looking for--- them in eqp and inv or even activating a wrong item via letter by mistake.-ring = ItemKind-  { isymbol  = symbolRing-  , iname    = "ring"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain stdCol ++ zipFancy darkCol-  , icount   = 1-  , irarity  = [(10, 3)]-  , iverbHit = "knock"-  , iweight  = 15-  , iaspects = []-  , ieffects = [Explode "blast 20"]-  , ifeature = [Precious, Identified]-  , idesc    = "A sturdy ring with a softly shining eye. If it contains a body booster unit, beware of the side-effects."-  , ikit     = []-  }-ring1 = ring-  { irarity  = [(10, 2)]-  , iaspects = [AddSpeed $ 1 + d 2, AddMaxHP $ dl 7 - 7 - d 7]-  , ieffects = [Explode "distortion"]  -- strong magic-  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddSpeed ""]-  }-ring2 = ring-  { irarity  = [(10, 5)]-  , iaspects = [AddMaxHP $ 10 + dl 10, AddMaxCalm $ dl 5 - 20 - d 5]-  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxHP ""]-  }-ring3 = ring-  { irarity  = [(10, 5)]-  , iaspects = [AddMaxCalm $ 29 + dl 10]-  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxCalm ""]-  , idesc    = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."-  }-ring4 = ring-  { irarity  = [(3, 3), (10, 5)]-  , iaspects = [AddHurtMelee $ d 5 + dl 5 |*| 3, AddMaxHP $ dl 3 - 5 - d 3]-  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddHurtMelee ""]-  }-ring5 = ring  -- by the time it's found, probably no space in eqp-  { irarity  = [(5, 0), (10, 2)]-  , iaspects = [AddLight $ d 2]-  , ieffects = [Explode "distortion"]  -- strong magic-  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddLight ""]-  , idesc    = "A sturdy ring with a large, shining stone."-  }-ring6 = ring-  { ifreq    = [("treasure", 100)]-  , irarity  = [(10, 2)]-  , iaspects = [ Unique, AddSpeed $ 3 + d 4-               , AddMaxCalm $ - 20 - d 20, AddMaxHP $ - 20 - d 20 ]-  , ieffects = [NoEffect "of Rush"]  -- no explosion, because Durable-  , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddSpeed ""]-  }-ring7 = ring-  { ifreq    = [("useful", 100), ("ring of opportunity sniper", 1) ]-  , irarity  = [(1, 1)]-  , iaspects = [AddSkills $ EM.fromList [(AbProject, 8)]]-  , ieffects = [ NoEffect "of opportunity sniper"-               , Explode "distortion" ]  -- strong magic-  , ifeature = ifeature ring ++ [EqpSlot (EqpSlotAddSkills AbProject) ""]-  }-ring8 = ring-  { ifreq    = [("useful", 1), ("ring of opportunity grenadier", 1) ]-  , irarity  = [(1, 1)]-  , iaspects = [AddSkills $ EM.fromList [(AbProject, 11)]]-  , ieffects = [ NoEffect "of opportunity grenadier"-               , Explode "distortion" ]  -- strong magic-  , ifeature = ifeature ring ++ [EqpSlot (EqpSlotAddSkills AbProject) ""]-  }---- * Ordinary exploding consumables, often intended to be thrown--potion = ItemKind-  { isymbol  = symbolPotion-  , iname    = "vial"-  , ifreq    = [("useful", 100)]-  , iflavour = zipLiquid brightCol ++ zipPlain brightCol ++ zipFancy brightCol-  , icount   = 1-  , irarity  = [(1, 12), (10, 9)]-  , iverbHit = "splash"-  , iweight  = 200-  , iaspects = []-  , ieffects = []-  , ifeature = [ toVelocity 50  -- oily, bad grip-               , Applicable, Fragile ]-  , idesc    = "A vial of bright, frothing concoction."  -- purely natural; no nano, no alien tech-  , ikit     = []-  }-potion1 = potion-  { ieffects = [ NoEffect "of rose water", Impress, RefillCalm (-3)-               , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ]-  }-potion2 = potion-  { ifreq    = [("treasure", 100)]-  , irarity  = [(6, 10), (10, 10)]-  , iaspects = [Unique]-  , ieffects = [ NoEffect "of Attraction", Impress, OverfillCalm (-20)-               , OnSmash (Explode "pheromone") ]-  }-potion3 = potion-  { irarity  = [(1, 10)]-  , ieffects = [ RefillHP 5, DropItem COrgan "poisoned" True-               , OnSmash (Explode "healing mist") ]-  }-potion4 = potion-  { irarity  = [(10, 10)]-  , ieffects = [ RefillHP 10, DropItem COrgan "poisoned" True-               , OnSmash (Explode "healing mist 2") ]-  }-potion5 = potion-  { ieffects = [ OneOf [ OverfillHP 10, OverfillHP 5, Burn 5-                       , toOrganActorTurn "strengthened" (20 + d 5) ]-               , OnSmash (OneOf [ Explode "healing mist"-                                , Explode "wounding mist"-                                , Explode "fragrance"-                                , Explode "smelly droplet"-                                , Explode "blast 10" ]) ]-  }-potion6 = potion-  { irarity  = [(3, 3), (10, 6)]-  , ieffects = [ Impress-               , OneOf [ OverfillCalm (-60)-                       , OverfillHP 20, OverfillHP 10, Burn 10-                       , toOrganActorTurn "fast 20" (20 + d 5) ]-               , OnSmash (OneOf [ Explode "healing mist 2"-                                , Explode "calming mist"-                                , Explode "distressing odor"-                                , Explode "eye drop"-                                , Explode "blast 20" ]) ]-  }-potion7 = potion-  { irarity  = [(1, 15), (10, 5)]-  , ieffects = [ DropItem COrgan "poisoned" True-               , OnSmash (Explode "antidote mist") ]-  }-potion8 = potion-  { irarity  = [(1, 5), (10, 15)]-  , ieffects = [ DropItem COrgan "temporary conditions" True-               , OnSmash (Explode "blast 10") ]-  }-potion9 = potion-  { ifreq    = [("treasure", 100)]-  , irarity  = [(10, 5)]-  , iaspects = [Unique]-  , ieffects = [ NoEffect "of Love", OverfillHP 60-               , Impress, OverfillCalm (-60)-               , OnSmash (Explode "healing mist 2")-               , OnSmash (Explode "pheromone") ]-  }---- * Exploding consumables with temporary aspects, can be thrown--- TODO: dip projectiles in those--- TODO: add flavour and realism as in, e.g., "flask of whiskey",--- which is more flavourful and believable than "flask of strength"--flask = ItemKind-  { isymbol  = symbolFlask-  , iname    = "flask"-  , ifreq    = [("useful", 100), ("flask", 100)]-  , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol-  , icount   = 1-  , irarity  = [(1, 9), (10, 6)]-  , iverbHit = "splash"-  , iweight  = 500-  , iaspects = []-  , ieffects = []-  , ifeature = [ toVelocity 50  -- oily, bad grip-               , Applicable, Fragile ]-  , idesc    = "A flask of oily liquid of a suspect color."-  , ikit     = []-  }-flask1 = flask-  { irarity  = [(10, 5)]-  , ieffects = [ NoEffect "of strength brew"-               , toOrganActorTurn "strengthened" (20 + d 5)-               , toOrganNone "regenerating"-               , OnSmash (Explode "strength mist") ]-  }-flask2 = flask-  { ieffects = [ NoEffect "of weakness brew"-               , toOrganGameTurn "weakened" (20 + d 5)-               , OnSmash (Explode "weakness mist") ]-  }-flask3 = flask-  { ieffects = [ NoEffect "of protecting balm"-               , toOrganActorTurn "protected" (20 + d 5)-               , OnSmash (Explode "protecting balm") ]-  }-flask4 = flask-  { ieffects = [ NoEffect "of red paint"-               , toOrganGameTurn "painted red" (20 + d 5)-               , OnSmash (Explode "red paint") ]-  }-flask5 = flask-  { irarity  = [(10, 5)]-  , ieffects = [ NoEffect "of haste brew"-               , toOrganActorTurn "fast 20" (20 + d 5)-               , OnSmash (Explode "haste spray") ]-  }-flask6 = flask-  { ieffects = [ NoEffect "of lethargy brew"-               , toOrganGameTurn "slow 10" (20 + d 5)-               , toOrganNone "regenerating"-               , RefillCalm 3-               , OnSmash (Explode "slowness spray") ]-  }-flask7 = flask  -- sight can be reduced from Calm, drunk, etc.-  { irarity  = [(10, 7)]-  , ieffects = [ NoEffect "of eye drops"-               , toOrganActorTurn "far-sighted" (20 + d 5)-               , OnSmash (Explode "blast 10") ]-  }-flask8 = flask-  { irarity  = [(10, 3)]-  , ieffects = [ NoEffect "of smelly concoction"-               , toOrganActorTurn "keen-smelling" (20 + d 5)-               , OnSmash (Explode "blast 10") ]-  }-flask9 = flask-  { ieffects = [ NoEffect "of bait cocktail"-               , toOrganActorTurn "drunk" (5 + d 5)-               , OnSmash (Summon [("mobile animal", 1)] $ 1 + dl 2)-               , OnSmash (Explode "waste") ]-  }-flask10 = flask-  { ieffects = [ NoEffect "of whiskey"-               , toOrganActorTurn "drunk" (20 + d 5)-               , Impress, Burn 2, RefillHP 4-               , OnSmash (Explode "whiskey spray") ]-  }-flask11 = flask-  { irarity  = [(1, 20), (10, 10)]-  , ieffects = [ NoEffect "of regeneration brew"-               , toOrganNone "regenerating"-               , OnSmash (Explode "healing mist") ]-  }-flask12 = flask  -- but not flask of Calm depletion, since Calm reduced often-  { ieffects = [ NoEffect "of poison"-               , toOrganNone "poisoned"-               , OnSmash (Explode "wounding mist") ]-  }-flask13 = flask-  { irarity  = [(10, 5)]-  , ieffects = [ NoEffect "of slow resistance"-               , toOrganNone "slow resistant"-               , OnSmash (Explode "anti-slow mist") ]-  }-flask14 = flask-  { irarity  = [(10, 5)]-  , ieffects = [ NoEffect "of poison resistance"-               , toOrganNone "poison resistant"-               , OnSmash (Explode "antidote mist") ]-  }---- * Non-exploding consumables, not specifically designed for throwing--constructionHooter = scroll-  { iname    = "construction hooter"-  , ifreq    = [("useful", 1), ("construction hooter", 1)]  -- extremely rare-  , iflavour = zipPlain [BrRed]-  , irarity  = [(1, 1)]-  , iaspects = []-  , ieffects = [Summon [("construction robot", 1)] $ 1 + dl 2]-  , ifeature = ifeature scroll ++ [Identified]-  , idesc    = "The single-use electronic overdrive hooter that construction robots use to warn about danger and call help in extreme emergency."-  , ikit     = []-  }-scroll = ItemKind-  { isymbol  = symbolScroll-  , iname    = "chip"-  , ifreq    = [("useful", 100), ("any scroll", 100)]-  , iflavour = zipFancy stdCol ++ zipPlain darkCol  -- arcane and old-  , icount   = 1-  , irarity  = [(1, 15), (10, 12)]-  , iverbHit = "thump"-  , iweight  = 20-  , iaspects = []-  , ieffects = []-  , ifeature = [ toVelocity 25  -- too little-               , Applicable ]-  , idesc    = "A generic, diposable chip, capable of a one-time holo-display. Some of these also contain a one-time password authorizing a particular spaceship's infrastructure transition. It is unknown how the infrastructure might respond after so many years."-  , ikit     = []-  }-scroll1 = scroll-  { ifreq    = [("treasure", 100)]-  , irarity  = [(5, 10), (10, 10)]  -- mixed blessing, so available early-  , iaspects = [Unique]-  , ieffects = [ NoEffect "of Reckless Beacon"-               , CallFriend 1, Summon standardSummon (2 + d 2) ]-  }-scroll2 = scroll-  { irarity  = []-  , ieffects = []-  }-scroll3 = scroll-  { irarity  = [(1, 5), (10, 3)]-  , ieffects = [Ascend 1]-  }-scroll4 = scroll-  { ieffects = [OneOf [ Teleport 5, RefillCalm 5, RefillCalm (-5)-                      , InsertMove 5, Paralyze 10 ]]-  }-scroll5 = scroll-  { irarity  = [(10, 15)]-  , ieffects = [ Impress-               , OneOf [ Teleport 20, Ascend (-1), Ascend 1-                       , Summon standardSummon 2, CallFriend 1-                       , RefillCalm 5, OverfillCalm (-60)-                       , CreateItem CGround "useful" TimerNone ] ]-  }-scroll6 = scroll-  { ieffects = [Teleport 5]-  }-scroll7 = scroll-  { ieffects = [Teleport 20]-  }-scroll8 = scroll-  { irarity  = [(10, 3)]-  , ieffects = [InsertMove $ 1 + d 2 + dl 2]-  }-scroll9 = scroll  -- TODO: remove Calm when server can tell if anything IDed-  { irarity  = [(1, 15), (10, 10)]-  , ieffects = [ NoEffect "of scientific explanation"-               , Identify, OverfillCalm 3 ]-  }-scroll10 = scroll  -- TODO: firecracker only if an item really polymorphed?-                   -- But currently server can't tell.-  { irarity  = [(10, 10)]-  , ieffects = [ NoEffect "molecular reconfiguration"-               , PolyItem, Explode "firecracker 7" ]-  }-scroll11 = scroll-  { ifreq    = [("treasure", 100)]-  , irarity  = [(6, 10), (10, 10)]-  , iaspects = [Unique]-  , ieffects = [NoEffect "of Prisoner Release", CallFriend 1]-  }--standardSummon :: Freqs ItemKind-standardSummon = [ ("mobile alien", 20)-                 , ("mobile animal", 50)-                 , ("mobile robot", 30) ]---- * Armor--armorLeather = ItemKind-  { isymbol  = symbolTorsoArmor-  , iname    = "spacesuit breastplate"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [Brown]-  , icount   = 1-  , irarity  = [(1, 9), (10, 3)]-  , iverbHit = "thud"-  , iweight  = 7000-  , iaspects = [ AddHurtMelee (-3)-               , AddArmorMelee $ 1 + d 2 + dl 2 |*| 5-               , AddArmorRanged $ 1 + d 2 + dl 2 |*| 5 ]-  , ieffects = []-  , ifeature = [ toVelocity 30  -- unwieldy to throw and blunt-               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]-  , idesc    = "A hard-shell torso segment cut from a disposed off spacesuit."-  , ikit     = []-  }-armorMail = armorLeather-  { iname    = "bulletproof vest"-  , iflavour = zipPlain [Cyan]-  , irarity  = [(6, 9), (10, 3)]-  , iweight  = 12000-  , iaspects = [ AddHurtMelee (-3)-               , AddArmorMelee $ 2 + d 2 + dl 3 |*| 5-               , AddArmorRanged $ 2 + d 2 + dl 3 |*| 5 ]-  , idesc    = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow."-  }-gloveFencing = ItemKind-  { isymbol  = symbolMiscArmor-  , iname    = "construction glove"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [BrYellow]-  , icount   = 1-  , irarity  = [(5, 9), (10, 9)]-  , iverbHit = "flap"-  , iweight  = 100-  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) |*| 3-               , AddArmorRanged $ d 2 |*| 5 ]-  , ieffects = []-  , ifeature = [ toVelocity 30  -- flaps and flutters-               , Durable, EqpSlot EqpSlotAddArmorRanged "", Identified ]-  , idesc    = "A flexible construction glove from rough leather ensuring a good grip. Also, quite effective in deflecting or even catching slow projectiles."-  , ikit     = []-  }-gloveGauntlet = gloveFencing-  { iname    = "spacesuit glove"-  , iflavour = zipPlain [BrCyan]-  , irarity  = [(1, 9), (10, 3)]-  , iweight  = 300-  , iaspects = [ AddArmorMelee $ 1 + dl 2 |*| 5-               , AddArmorRanged $ 1 + dl 2 |*| 5 ]-  , idesc    = "A piece of a hull maintenance spacesuit, padded and reinforced with carbon fibre."-  }-gloveJousting = gloveFencing-  { iname    = "Welding Handgear"-  , iflavour = zipFancy [BrRed]-  , irarity  = [(1, 3), (10, 3)]-  , iweight  = 500-  , iaspects = [ Unique-               , AddHurtMelee $ dl 4 - 6 |*| 3-               , AddArmorMelee $ 2 + dl 2 |*| 5-               , AddArmorRanged $ 2 + dl 2 |*| 5 ]-  , idesc    = "Rigid, bulky handgear embedding a welding equipment, complete with an affixed small shield and a darkened visor. Awe-inspiring."-  }---- * Shields---- Shield doesn't protect against ranged attacks to prevent--- micromanagement: walking with shield, melee without.-buckler = ItemKind-  { isymbol  = symbolShield-  , iname    = "buckler"-  , ifreq    = [("useful", 100)]-  , iflavour = zipPlain [Blue]-  , icount   = 1-  , irarity  = [(4, 6)]-  , iverbHit = "bash"-  , iweight  = 2000-  , iaspects = [ AddArmorMelee 40-               , AddHurtMelee (-30)-               , Timeout $ d 3 + 3 - dl 3 |*| 2 ]-  , ieffects = [ Hurt (1 * d 1)  -- to display xdy everywhre in Hurt-               , Recharging (PushActor (ThrowMod 200 50)) ]-  , ifeature = [ toVelocity 40  -- unwieldy to throw-               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]-  , idesc    = "Heavy and unwieldy arm protection made from an outer airlock panel. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with."-  , ikit     = []-  }-shield = buckler-  { iname    = "shield"-  , irarity  = [(8, 3)]-  , iflavour = zipPlain [Green]-  , iweight  = 3000-  , iaspects = [ AddArmorMelee 80-               , AddHurtMelee (-70)-               , Timeout $ d 6 + 6 - dl 6 |*| 2 ]-  , ieffects = [Hurt (1 * d 1), Recharging (PushActor (ThrowMod 400 50))]-  , ifeature = [ toVelocity 30  -- unwieldy to throw-               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]-  , idesc    = "Large and unwieldy rectangle made of anti-meteorite ceramic sheet. Absorbs a percentage of melee damage, both dealt and sustained. Too heavy to intercept projectiles with."-  }---- * Weapons--dagger = ItemKind-  { isymbol  = symbolEdged-  , iname    = "cleaver"-  , ifreq    = [("useful", 100), ("starting weapon", 100)]-  , iflavour = zipPlain [BrCyan]-  , icount   = 1-  , irarity  = [(1, 20)]-  , iverbHit = "stab"-  , iweight  = 1000-  , iaspects = [ AddHurtMelee $ d 3 + dl 3 |*| 3-               , AddArmorMelee $ d 2 |*| 5-               , AddHurtRanged (-60) ]  -- as powerful as a dart-  , ieffects = [Hurt (6 * d 1)]-  , ifeature = [ toVelocity 40  -- ensuring it hits with the tip costs speed-               , Durable, EqpSlot EqpSlotWeapon "", Identified ]-  , idesc    = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."-  , ikit     = []-  }-daggerDropBestWeapon = dagger-  { iname    = "Double Dagger"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(1, 2), (10, 4)]-  -- The timeout has to be small, so that the player can count on the effect-  -- occuring consistently in any longer fight. Otherwise, the effect will be-  -- absent in some important fights, leading to the feeling of bad luck,-  -- but will manifest sometimes in fights where it doesn't matter,-  -- leading to the feeling of wasted power.-  -- If the effect is very powerful and so the timeout has to be significant,-  -- let's make it really large, for the effect to occur only once in a fight:-  -- as soon as the item is equipped, or just on the first strike.-  , iaspects = [Unique, Timeout $ d 3 + 4 - dl 3 |*| 2]-  , ieffects = ieffects dagger-               ++ [Recharging DropBestWeapon, Recharging $ RefillCalm (-3)]-  , idesc    = "A knife with a forked blade that a focused fencer can use to catch and twist an opponent's weapon occasionally."-  }-hammer = ItemKind-  { isymbol  = symbolHafted-  , iname    = "demolition hammer"-  , ifreq    = [("useful", 100), ("starting weapon", 100)]-  , iflavour = zipPlain [BrMagenta]-  , icount   = 1-  , irarity  = [(5, 15)]-  , iverbHit = "club"-  , iweight  = 1500-  , iaspects = [ AddHurtMelee $ d 2 + dl 2 |*| 3-               , AddHurtRanged (-80) ]  -- as powerful as a dart-  , ieffects = [Hurt (8 * d 1)]-  , ifeature = [ toVelocity 20  -- ensuring it hits with the sharp tip costs-               , Durable, EqpSlot EqpSlotWeapon "", Identified ]-  , idesc    = "A hammer on a long handle used for construction work. It may not cause grave wounds, but neither does it ricochet or glance off armor. Great sidearm for opportunistic blows against armored foes."-  , ikit     = []-  }-hammerParalyze = hammer-  { iname    = "Concussion Hammer"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(5, 2), (10, 4)]-  , iaspects = [Unique, Timeout $ d 2 + 3 - dl 2 |*| 2]-  , ieffects = ieffects hammer ++ [Recharging $ Paralyze 5]-  }-hammerSpark = hammer-  { iname    = "Grand Smithhammer"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(5, 2), (10, 4)]-  , iaspects = [Unique, Timeout $ d 4 + 4 - dl 4 |*| 2]-  , ieffects = ieffects hammer ++ [Recharging $ Explode "spark"]-  }-sword = ItemKind-  { isymbol  = symbolPolearm-  , iname    = "sharpened pipe"-  , ifreq    = [("useful", 100), ("starting weapon", 100)]-  , iflavour = zipPlain [BrBlue]-  , icount   = 1-  , irarity  = [(4, 1), (5, 15)]-  , iverbHit = "slash"-  , iweight  = 2000-  , iaspects = []-  , ieffects = [Hurt (10 * d 1)]-  , ifeature = [ toVelocity 5  -- ensuring it hits with the tip costs speed-               , Durable, EqpSlot EqpSlotWeapon "", Identified ]-  , idesc    = "A makeshift weapon of simple design, but great potential. Hard to master, though."-  , ikit     = []-  }-swordImpress = sword-  { isymbol  = symbolEdged-  , iname    = "Master's Sword"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(5, 1), (10, 4)]-  , iaspects = [Unique, Timeout $ d 4 + 5 - dl 4 |*| 2]-  , ieffects = ieffects sword ++ [Recharging Impress]-  , idesc    = "An old, dull, but well-balance blade, lending itself to impressive shows of fencing skill."-  }-swordNullify = sword-  { isymbol  = symbolEdged-  , iname    = "Gutting Sword"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(5, 1), (10, 4)]-  , iaspects = [Unique, Timeout $ d 4 + 5 - dl 4 |*| 2]-  , ieffects = ieffects sword-               ++ [ Recharging $ DropItem COrgan "temporary conditions" True-                  , Recharging $ RefillHP (-2) ]-  , idesc    = "Cold, thin, ancient blade that pierces deeply and sends its victim into abrupt, sobering shock."-  }-halberd = ItemKind-  { isymbol  = symbolPolearm-  , iname    = "pole cleaver"-  , ifreq    = [("useful", 100), ("starting weapon", 1)]-  , iflavour = zipPlain [BrYellow]-  , icount   = 1-  , irarity  = [(7, 1), (10, 10)]-  , iverbHit = "impale"-  , iweight  = 3000-  , iaspects = [AddArmorMelee $ 1 + dl 3 |*| 5]-  , ieffects = [Hurt (12 * d 1)]-  , ifeature = [ toVelocity 5  -- not balanced-               , Durable, EqpSlot EqpSlotWeapon "", Identified ]-  , idesc    = "An improvised but deadly weapon made of a long, sharp kitchen knife glued and bound to a long pole."-  , ikit     = []-  }-halberdPushActor = halberd-  { iname    = "Swiss Halberd"-  , ifreq    = [("treasure", 20)]-  , irarity  = [(7, 1), (10, 4)]-  , iaspects = [Unique, Timeout $ d 5 + 5 - dl 5 |*| 2]-  , ieffects = ieffects halberd ++ [Recharging (PushActor (ThrowMod 400 25))]-  , idesc    = "A perfect replica made for a reenactor troupe, missing only some sharpening. Versatile, with great reach and leverage. Foes are held at a distance."-  }---- * Wands--wand = ItemKind-  { isymbol  = symbolWand-  , iname    = "injector"-  , ifreq    = [("useful", 100)]-  , iflavour = zipFancy brightCol-  , icount   = 1-  , irarity  = []  -- TODO: add charges, etc.-  , iverbHit = "club"-  , iweight  = 300-  , iaspects = [AddLight 1, AddSpeed (-1)]  -- pulsing with power, distracts-  , ieffects = []-  , ifeature = [ toVelocity 125  -- sufficiently advanced tech-               , Applicable, Durable ]-  , idesc    = "Buzzing with dazzling light that shines even through appendages that handle it."-  , ikit     = []-  }-wand1 = wand-  { ieffects = []  -- TODO: emit a cone of sound shrapnel that makes enemy cover his ears and so drop '{'-  }-wand2 = wand-  { ieffects = []-  }---- * Treasure--gem = ItemKind-  { isymbol  = symbolGem-  , iname    = "gem"-  , ifreq    = [("treasure", 100), ("gem", 100)]-  , iflavour = zipPlain $ delete BrYellow brightCol  -- natural, so not fancy-  , icount   = 1-  , irarity  = []-  , iverbHit = "tap"-  , iweight  = 50-  , iaspects = [AddLight 1, AddSpeed (-1)]-                 -- reflects strongly, distracts; so it glows in the dark,-                 -- is visible on dark floor, but not too tempting to wear-  , ieffects = []-  , ifeature = [Precious]-  , idesc    = "Precious, though useless. Worth around 100 gold grains."-  , ikit     = []-  }-gem1 = gem-  { irarity  = [(3 * 10/12, 0), (10, 12)]-  }-gem2 = gem-  { irarity  = [(5 * 10/12, 0), (10, 14)]-  }-gem3 = gem-  { irarity  = [(7 * 10/12, 0), (10, 16)]-  }-gem4 = gem-  { iname    = "stimpack"-  , iflavour = zipPlain [BrYellow]-  , irarity  = [(1, 40), (10, 40)]-  , iaspects = []-  , ieffects = [NoEffect "of youth", OverfillCalm 5, OverfillHP 15]-  , ifeature = [Identified, Applicable, Precious]  -- TODO: only heal humans-  , idesc    = "Calms, heals, invigorates and rejuvenates at the same time. No side-effects. As valuable as precious gems, at 100 gold grains each."-  }-currency = ItemKind-  { isymbol  = symbolGold-  , iname    = "gold grain"-  , ifreq    = [("treasure", 100), ("currency", 100)]-  , iflavour = zipPlain [BrYellow]-  , icount   = 10 + d 20 + dl 20-  , irarity  = [(1, 25), (10, 10)]-  , iverbHit = "tap"-  , iweight  = 1-  , iaspects = []-  , ieffects = []-  , ifeature = [Identified, Precious]-  , idesc    = "Reliably valuable in every civilized place."+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+-- | Item and treasure definitions.+module Content.ItemKind+  ( cdefs, items, otherItemContent+  ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import Content.ItemKindActor+import Content.ItemKindBlast+import Content.ItemKindEmbed+import Content.ItemKindOrgan+import Content.ItemKindTemporary+import Game.LambdaHack.Common.Ability+import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.ItemKind++cdefs :: ContentDef ItemKind+cdefs = ContentDef+  { getSymbol = isymbol+  , getName = iname+  , getFreq = ifreq+  , validateSingle = validateSingleItemKind+  , validateAll = validateAllItemKind+  , content = contentFromList []  -- filled out later on+  }++otherItemContent :: [ItemKind]+otherItemContent = embeds ++ actors ++ organs ++ blasts ++ temporaries++items :: [ItemKind]+items =+  [sandstoneRock, dart, spike, slingStone, slingBullet, paralizingProj, harpoon, net, light1, light2, light3, blanket, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency]+  -- Allure-specific+  ++ [needle, constructionHooter]++sandstoneRock,    dart, spike, slingStone, slingBullet, paralizingProj, harpoon, net, light1, light2, light3, blanket, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency :: ItemKind+-- Allure-specific+needle, constructionHooter :: ItemKind++necklace, ring, potion, flask, scroll, wand, gem :: ItemKind  -- generic templates++-- * Item group symbols, from Angband and variants++symbolProjectile, _symbolLauncher, symbolLight, symbolTool, symbolGem, symbolGold, symbolNecklace, symbolRing, symbolPotion, symbolFlask, symbolScroll, symbolTorsoArmor, symbolMiscArmor, _symbolClothes, symbolShield, symbolPolearm, symbolEdged, symbolHafted, symbolWand, _symbolStaff, _symbolFood :: Char++symbolProjectile = '{'+_symbolLauncher  = '}'+symbolLight      = '('+symbolTool       = ')'+symbolGem        = '*'+symbolGold       = '$'+symbolNecklace   = '"'+symbolRing       = '='+symbolPotion     = '!'  -- concoction, bottle, jar, vial, canister+symbolFlask      = '!'+symbolScroll     = '?'  -- book, note, tablet, remote, chip, card+symbolTorsoArmor = '['+symbolMiscArmor  = '['+_symbolClothes   = '['+symbolShield     = ']'+symbolPolearm    = '/'+symbolEdged      = '|'+symbolHafted     = '\\'+symbolWand       = '-'  -- magical rod, transmitter, pistol, rifle+_symbolStaff     = '_'  -- scanner+_symbolFood      = ','  -- distinct from floor, because middle dots used++-- * Thrown weapons++sandstoneRock = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "ceramic foam splinter"+  , ifreq    = [("sandstone rock", 1), ("weak arrow", 10)]+  , iflavour = zipPlain [Green]+  , icount   = 1 * d 2+  , irarity  = [(1, 50), (10, 1)]+  , iverbHit = "hit"+  , iweight  = 300+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-16 |*| 5)]+  , ieffects = []+  , ifeature = [toVelocity 70, Fragile, Identified]  -- not dense, irregular+  , idesc    = "A light, irregular lump of ceramic foam used in construction."+  , ikit     = []+  }+dart = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "billiard ball"+  , ifreq    = [("useful", 100), ("any arrow", 50), ("weak arrow", 50)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 4 * d 3+  , irarity  = [(1, 20), (10, 10)]+  , iverbHit = "strike"+  , iweight  = 170+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-14 + d 2 + dl 4 |*| 5)]  -- only leather-piercing+  , ieffects = []+  , ifeature = [Identified]+  , idesc    = "Ideal shape, size and weight for throwing."+  , ikit     = []+  }+spike = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "steak knife"+  , ifreq    = [("useful", 100), ("any arrow", 50), ("weak arrow", 50)]+  , iflavour = zipPlain [Cyan]+  , icount   = 4 * d 3+  , irarity  = [(1, 10), (10, 20)]+  , iverbHit = "nick"+  , iweight  = 100+  , idamage  = toDmg $ 2 * d 1+  , iaspects = [AddHurtMelee (-10 + d 2 + dl 4 |*| 5)]  -- heavy vs armor+  , ieffects = [ Explode "single spark"  -- when hitting enemy+               , OnSmash (Explode "single spark") ]  -- at wall hit+  , ifeature = [toVelocity 70, Identified]  -- hitting with tip costs speed+  , idesc    = "Not particularly well balanced, but with a laser-sharpened titanium tip and blade."+  , ikit     = []+  }+slingStone = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "steel hex nut"+  , ifreq    = [("useful", 5), ("any arrow", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 3 * d 3+  , irarity  = [(1, 1), (10, 20)]+  , iverbHit = "hit"+  , iweight  = 200+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-10 + d 2 + dl 4 |*| 5)]  -- heavy vs armor+  , ieffects = [ Explode "single spark"  -- when hitting enemy+               , OnSmash (Explode "single spark") ]  -- at wall hit+  , ifeature = [toVelocity 150, Identified]+  , idesc    = "A large hexagonal fastening nut, securely lodging in the pouch of a makeshift string and cloth sling due to its angular shape."+  , ikit     = []+  }+slingBullet = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "bearing ball"+  , ifreq    = [("useful", 5), ("any arrow", 100)]+  , iflavour = zipPlain [White]+  , icount   = 6 * d 3+  , irarity  = [(1, 1), (10, 15)]+  , iverbHit = "hit"+  , iweight  = 28+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-17 + d 2 + dl 4 |*| 5)]  -- not armor-piercing+  , ieffects = []+  , ifeature = [toVelocity 200, Identified]+  , idesc    = "Small but heavy bearing ball. Due to its size and shape, it securely fits in the makeshift sling's pouch and doesn't snag when released."+  , ikit     = []+  }++-- * Exotic thrown weapons++-- Identified, because shape (and name) says it all. Detailed stats id by use.+paralizingProj = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "can"+  , ifreq    = [("useful", 100), ("can of sticky foam", 1)]+  , iflavour = zipPlain [Magenta]+  , icount   = dl 3+  , irarity  = [(5, 5), (10, 20)]+  , iverbHit = "glue"+  , iweight  = 1000+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-14 |*| 5)]+  , ieffects = [ ELabel "of sticky foam", Paralyze (10 + d 12)+               , OnSmash (Explode "glue") ]+  , ifeature = [toVelocity 70, Identified, Lobable, Fragile]  -- unwieldy+  , idesc    = "A can of liquid, fast-setting construction foam."+  , ikit     = []+  }+harpoon = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "harpoon"+  , ifreq    = [("useful", 100), ("harpoon", 100)]+  , iflavour = zipPlain [Brown]+  , icount   = dl 5+  , irarity  = [(5, 5), (10, 5)]+  , iverbHit = "hook"+  , iweight  = 750+  , idamage  = [(99, 5 * d 1), (1, 10 * d 1)]+  , iaspects = [AddHurtMelee (-10 + d 2 + dl 4 |*| 5)]+  , ieffects = [PullActor (ThrowMod 200 50)]+  , ifeature = [Identified]+  , idesc    = "A display piece harking back to the Earth's oceanic tourism hayday. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying."+  , ikit     = []+  }+net = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "net"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [White]+  , icount   = dl 3+  , irarity  = [(3, 5), (10, 4)]+  , iverbHit = "entangle"+  , iweight  = 1000+  , idamage  = toDmg $ 2 * d 1+  , iaspects = [AddHurtMelee (-14 |*| 5)]+  , ieffects = [ toOrganGameTurn "slowed" (3 + d 3)+               , DropItem maxBound 1 CEqp "torso armor" ]+  , ifeature = [Identified]+  , idesc    = "A large synthetic fibre net with weights affixed along the edges. Entangles armor and restricts movement."+  , ikit     = []+  }++-- * Lights++light1 = ItemKind+  { isymbol  = symbolLight+  , iname    = "torch"+  , ifreq    = [("useful", 100), ("light source", 100), ("wooden torch", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = d 2+  , irarity  = [(1, 10)]+  , iverbHit = "scorch"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = [ AddShine 3       -- not only flashes, but also sparks,+               , AddSight (-2) ]  -- so unused by AI due to the mixed blessing+  , ieffects = [Burn 1, EqpSlot EqpSlotLightSource]+  , ifeature = [Lobable, Identified, Equipable]  -- not Fragile; reusable flare+  , idesc    = "A torch improvised with cloth soaked in tar on a stick."+  , ikit     = []+  }+light2 = ItemKind+  { isymbol  = symbolLight+  , iname    = "oil lamp"+  , ifreq    = [("useful", 100), ("light source", 100)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(6, 7)]+  , iverbHit = "burn"+  , iweight  = 1500+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddShine 3, AddSight (-1)]+  , ieffects = [ Burn 1, Paralyze 6, OnSmash (Explode "burning oil 3")+               , EqpSlot EqpSlotLightSource ]+  , ifeature = [Lobable, Fragile, Identified, Equipable]+  , idesc    = "A sizable restaurant glass lamp filled with plant oil feeding a wick."+  , ikit     = []+  }+light3 = ItemKind+  { isymbol  = symbolLight+  , iname    = "crank spotlight"+  , ifreq    = [("useful", 100), ("light source", 100)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 1+  , irarity  = [(10, 5)]+  , iverbHit = "snag"+  , iweight  = 3000+  , idamage  = toDmg 0+  , iaspects = [AddShine 4, AddArmorRanged $ - d 3]  -- noise and distraction+  , ieffects = [EqpSlot EqpSlotLightSource]+  , ifeature = [Identified, Equipable]+  , idesc    = "Powerful, wide-beam spotlight, powered by a hand-crank. Requires noisy two-handed recharging every few minutes."+  , ikit     = []+  }+blanket = ItemKind+  { isymbol  = symbolLight+  , iname    = "mineral fibre blanket"+  , ifreq    = [("useful", 100), ("light source", 100), ("blanket", 1)]+  , iflavour = zipPlain [BrBlack]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "swoosh"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = [ AddShine (-10)  -- douses torch, lamp and lantern in one action+               , AddArmorMelee 1, AddMaxCalm 2 ]+  , ieffects = []+  , ifeature = [Lobable, Identified, Equipable]  -- not Fragile; reusable douse+  , idesc    = ""+  , ikit     = []+  }++-- * Exploding consumables, often intended to be thrown.++-- Not identified, because they are perfect for the id-by-use fun,+-- due to effects. They are fragile and upon hitting the ground explode+-- for effects roughly corresponding to their normal effects.+-- Whether to hit with them or explode them close to the tartget+-- is intended to be an interesting tactical decision.+--+-- Flasks are often not natural; maths, magic, distillery.+-- In reality, they just cover all temporary effects, which in turn matches+-- all aspects.+--+-- No flask nor temporary organ of Calm depletion, since Calm reduced often.+flask = ItemKind+  { isymbol  = symbolFlask+  , iname    = "flask"+  , ifreq    = [("useful", 100), ("flask", 100), ("any vial", 100)]+  , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol+               ++ zipLiquid brightCol+  , icount   = 1+  , irarity  = [(1, 7), (10, 4)]+  , iverbHit = "splash"+  , iweight  = 500+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = []+  , ifeature = [Applicable, Lobable, Fragile, toVelocity 50]  -- oily, bad grip+  , idesc    = "A flask of oily liquid of a suspect color. Something seems to be moving inside."+  , ikit     = []+  }+flask1 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of strength renewal brew"+               , toOrganActorTurn "strengthened" (20 + d 5)+               , toOrganNone "regenerating"+               , OnSmash (Explode "dense shower") ]+  }+flask2 = flask+  { ieffects = [ ELabel "of weakness brew"+               , toOrganGameTurn "weakened" (20 + d 5)+               , OnSmash (Explode "sparse shower") ]+  }+flask3 = flask+  { ieffects = [ ELabel "of melee protective balm"+               , toOrganActorTurn "protected from melee" (20 + d 5)+               , OnSmash (Explode "melee protective balm") ]+  }+flask4 = flask+  { ieffects = [ ELabel "of ranged protective balm"+               , toOrganActorTurn "protected from ranged" (20 + d 5)+               , OnSmash (Explode "ranged protective balm") ]+  }+flask5 = flask+  { ieffects = [ ELabel "of red paint"+               , toOrganGameTurn "painted red" (20 + d 5)+               , OnSmash (Explode "red paint") ]+  }+flask6 = flask+  { irarity  = [(10, 9)]+  , ieffects = [ ELabel "of resolution"+               , toOrganActorTurn "resolute" (200 + d 50)+                   -- long, for scouting and has to recharge+               , OnSmash (Explode "resolution dust") ]+  }+flask7 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of haste brew"+               , toOrganActorTurn "hasted" (20 + d 5)+               , OnSmash (Explode "blast 20")+               , OnSmash (Explode "haste spray") ]+  }+flask8 = flask+  { irarity  = [(1, 14), (10, 4)]+  , ieffects = [ ELabel "of lethargy brew"+               , toOrganGameTurn "slowed" (20 + d 5)+               , toOrganNone "regenerating", toOrganNone "regenerating"  -- x2+               , RefillCalm 5+               , OnSmash (Explode "slowness mist") ]+  }+flask9 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of eye drops"+               , toOrganActorTurn "far-sighted" (40 + d 10)+               , OnSmash (Explode "eye drop") ]+  }+flask10 = flask+  { irarity  = [(10, 2)]+  , ieffects = [ ELabel "of smelly concoction"+               , toOrganActorTurn "keen-smelling" (40 + d 10)+               , DetectActor 5+               , OnSmash (Explode "smelly droplet") ]+  }+flask11 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of cat tears"+               , toOrganActorTurn "shiny-eyed" (40 + d 10)+               , OnSmash (Explode "eye shine") ]+  }+flask12 = flask+  { irarity  = [(1, 14), (10, 10)]+  , ieffects = [ ELabel "of whiskey"+               , toOrganActorTurn "drunk" (20 + d 5)+               , Burn 1, RefillHP 3+               , OnSmash (Explode "whiskey spray") ]+  }+flask13 = flask+  { ieffects = [ ELabel "of bait cocktail"+               , toOrganActorTurn "drunk" (20 + d 5)+               , Burn 1, RefillHP 3+               , Summon "mobile animal" 1+               , OnSmash (Summon "mobile animal" 1)+               , OnSmash Impress+               , OnSmash (Explode "waste") ]+  }+-- The player has full control over throwing the flask at his party,+-- so he can milk the explosion, so it has to be much weaker, so a weak+-- healing effect is enough. OTOH, throwing a harmful flask at many enemies+-- at once is not easy to arrange, so these explostions can stay powerful.+flask14 = flask+  { irarity  = [(1, 4), (10, 14)]+  , ieffects = [ ELabel "of regeneration brew"+               , toOrganNone "regenerating", toOrganNone "regenerating"  -- x2+               , OnSmash (Explode "healing mist") ]+  }+flask15 = flask+  { ieffects = [ ELabel "of poison"+               , toOrganNone "poisoned", toOrganNone "poisoned"  -- x2+               , OnSmash (Explode "poison cloud") ]+  }+flask16 = flask+  { irarity  = [(1, 14), (10, 4)]+  , ieffects = [ ELabel "of weak poison"+               , toOrganNone "poisoned"+               , OnSmash (Explode "poison cloud") ]+  }+flask17 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of slow resistance"+               , toOrganNone "slow resistant"+               , OnSmash (Explode "blast 10")+               , OnSmash (Explode "anti-slow mist") ]+  }+flask18 = flask+  { irarity  = [(10, 4)]+  , ieffects = [ ELabel "of poison resistance"+               , toOrganNone "poison resistant"+               , OnSmash (Explode "antidote mist") ]+  }+flask19 = flask+  { ieffects = [ ELabel "of blindness"+               , toOrganGameTurn "blind" (40 + d 10)+               , OnSmash (Explode "iron filing") ]+  }+flask20 = flask+  { ieffects = [ ELabel "of calamity"+               , toOrganNone "poisoned"+               , toOrganGameTurn "weakened" (20 + d 5)+               , toOrganGameTurn "painted red" (20 + d 5)+               , OnSmash (Explode "poison cloud") ]+  }++-- Potions are often natura. Various configurations of effects.+-- A different class of effects is on scrolls and/or mechanical items.+-- Some are shared.++potion = ItemKind+  { isymbol  = symbolPotion+  , iname    = "vial"+  , ifreq    = [("useful", 100), ("potion", 100), ("any vial", 100)]+  , iflavour = zipLiquid brightCol ++ zipPlain brightCol ++ zipFancy brightCol+  , icount   = 1+  , irarity  = [(1, 10), (10, 7)]+  , iverbHit = "splash"+  , iweight  = 200+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = []+  , ifeature = [Applicable, Lobable, Fragile, toVelocity 50]  -- oily, bad grip+  , idesc    = "A vial of bright, frothing concoction. The best that nature has to offer."+  , ikit     = []+  }+potion1 = potion+  { ieffects = [ ELabel "of rose water", Impress, RefillCalm (-5)+               , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ]+  }+potion2 = potion+  { ifreq    = [("treasure", 100)]+  , irarity  = [(6, 9), (10, 9)]+  , ieffects = [ Unique, ELabel "of Attraction", Impress, RefillCalm (-20)+               , OnSmash (Explode "pheromone") ]+  }+potion3 = potion+  { ieffects = [ RefillHP 5, DropItem 1 maxBound COrgan "poisoned"+               , OnSmash (Explode "healing mist") ]+  }+potion4 = potion+  { irarity  = [(1, 7), (10, 10)]+  , ieffects = [ RefillHP 10, DropItem 1 maxBound COrgan "poisoned"+               , OnSmash (Explode "healing mist 2") ]+  }+potion5 = potion+  { ieffects = [ OneOf [ RefillHP 10, RefillHP 5, Burn 5+                       , toOrganActorTurn "strengthened" (20 + d 5) ]+               , OnSmash (OneOf [ Explode "dense shower"+                                , Explode "sparse shower"+                                , Explode "melee protective balm"+                                , Explode "ranged protective balm"+                                , Explode "red paint"+                                , Explode "blast 10" ]) ]+  }+potion6 = potion+  { irarity  = [(3, 2), (10, 5)]+  , ieffects = [ Impress+               , OneOf [ RefillCalm (-60)+                       , RefillHP 20, RefillHP 10, Burn 10+                       , toOrganActorTurn "hasted" (20 + d 5) ]+               , OnSmash (OneOf [ Explode "healing mist 2"+                                , Explode "wounding mist"+                                , Explode "distressing odor"+                                , Explode "haste spray"+                                , Explode "slowness mist"+                                , Explode "fragrance"+                                , Explode "blast 20" ]) ]+  }+potion7 = potion+  { irarity  = [(1, 11), (10, 4)]+  , ieffects = [ DropItem 1 maxBound COrgan "poisoned"+               , OnSmash (Explode "antidote mist") ]+  }+potion8 = potion+  { irarity  = [(1, 9)]+  , ieffects = [ DropItem 1 maxBound COrgan "temporary condition"+               , OnSmash (Explode "blast 10") ]+  }+potion9 = potion+  { irarity  = [(10, 9)]+  , ieffects = [ DropItem maxBound maxBound COrgan "temporary condition"+               , OnSmash (Explode "blast 20") ]+  }+potion10 = potion+  { ifreq    = [("treasure", 100)]+  , irarity  = [(10, 4)]+  , ieffects = [ Unique, ELabel "of Love", RefillHP 60+               , Impress, RefillCalm (-60)+               , OnSmash (Explode "healing mist 2")+               , OnSmash (Explode "pheromone") ]+  }++-- * Non-exploding consumables, not specifically designed for throwing++scroll = ItemKind+  { isymbol  = symbolScroll+  , iname    = "chip"+  , ifreq    = [("useful", 100), ("any scroll", 100)]+  , iflavour = zipFancy stdCol ++ zipPlain darkCol  -- arcane and old+  , icount   = 1+  , irarity  = [(1, 14), (10, 11)]+  , iverbHit = "thump"+  , iweight  = 20+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = []+  , ifeature = [ toVelocity 30  -- too small+               , Applicable ]+  , idesc    = "A generic, diposable chip, capable of a one-time holo-display. Some of these also contain a one-time password authorizing a particular spaceship's infrastructure transition. It is unknown how the infrastructure might respond after so many years."+  , ikit     = []+  }+scroll1 = scroll+  { ifreq    = [("treasure", 100)]+  , irarity  = [(5, 9), (10, 9)]  -- mixed blessing, so available early+  , ieffects = [ Unique, ELabel "of Reckless Beacon"+               , Summon "hero" 1, Summon "mobile animal" (2 + d 2) ]+  }+scroll2 = scroll+  { irarity  = [(1, 2)]+  , ieffects = [ ELabel "of greed", Teleport 20, DetectItem 10+               , RefillCalm (-100) ]+  }+scroll3 = scroll+  { irarity  = [(1, 4), (10, 2)]+  , ieffects = [Ascend True]+  }+scroll4 = scroll+  { ieffects = [OneOf [ Teleport 5, RefillCalm 5, InsertMove 5+                      , DetectActor 10, DetectItem 10 ]]+  }+scroll5 = scroll+  { irarity  = [(10, 14)]+  , ieffects = [ Impress+               , OneOf [ Teleport 20, Ascend False, Ascend True+                       , Summon "hero" 1, Summon "mobile animal" 2+                       , Detect 20, RefillCalm (-100)+                       , CreateItem CGround "useful" TimerNone ] ]+  }+scroll6 = scroll+  { ieffects = [Teleport 5]+  }+scroll7 = scroll+  { ieffects = [Teleport 20]+  }+scroll8 = scroll+  { irarity  = [(10, 2)]+  , ieffects = [InsertMove $ 1 + d 2 + dl 2]+  }+scroll9 = scroll+  { ieffects = [ELabel "of scientific explanation", Identify]+  }+scroll10 = scroll+  { irarity  = [(10, 20)]+  , ieffects = [ ELabel "molecular reconfiguration"+               , PolyItem, Explode "firecracker 7" ]+  }+scroll11 = scroll+  { ifreq    = [("treasure", 100)]+  , irarity  = [(6, 9), (10, 9)]+  , ieffects = [Unique, ELabel "of Prisoner Release", Summon "hero" 1]+  }+scroll12 = scroll+  { irarity  = [(1, 9), (10, 4)]+  , ieffects = [DetectHidden 10]+  }+scroll13 = scroll+  { ieffects = [ELabel "of acute hearing", DetectActor 7]+  }++-- * Assorted tools++jumpingPole = ItemKind+  { isymbol  = symbolTool+  , iname    = "jumping pole"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [White]+  , icount   = 1+  , irarity  = [(1, 2)]+  , iverbHit = "prod"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = [Timeout $ d 2 + 2 - dl 2 |*| 10]+  , ieffects = [Recharging (toOrganActorTurn "hasted" 1)]+  , ifeature = [Durable, Applicable, Identified]+  , idesc    = "Makes you vulnerable at take-off, but then you are free like a bird."+  , ikit     = []+  }+sharpeningTool = ItemKind+  { isymbol  = symbolTool+  , iname    = "honing steel"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 1+  , irarity  = [(10, 10)]+  , iverbHit = "smack"+  , iweight  = 400+  , idamage  = toDmg 0+  , iaspects = [AddHurtMelee $ d 10 |*| 3]+  , ieffects = [EqpSlot EqpSlotAddHurtMelee]+  , ifeature = [Identified, Equipable]+  , idesc    = "Originally used for realigning the bent or buckled edges of kitchen knives in the local bars. Now it saves lives by letting you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop."+  , ikit     = []+  }+seeingItem = ItemKind+  { isymbol  = '%'+  , iname    = "visual sensor"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [Red]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "gaze at"+  , iweight  = 500+  , idamage  = toDmg 0+  , iaspects = [ AddSight 10, AddMaxCalm 30, AddShine 2+               , Timeout $ 1 + d 2 ]+  , ieffects = [ Periodic+               , Recharging (toOrganNone "poisoned")+               , Recharging (Summon "mobile robot" 1) ]+  , ifeature = [Identified]+  , idesc    = "A functioning visual sensor torn out from some sizable robot. The circuitry seem too large for basic signal processing alone. Watch out for the sharp edges and the seeping coolant liquid."+  , ikit     = []+  }+motionScanner = ItemKind+  { isymbol  = symbolTool+  , iname    = "handhelp sonar"+  , ifreq    = [("useful", 100), ("add nocto 1", 20)]+  , iflavour = zipPlain [Green]+  , icount   = 1+  , irarity  = [(6, 2), (10, 2)]+  , iverbHit = "ping"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = [ AddNocto 1+               , AddArmorMelee (dl 5 - 10), AddArmorRanged (dl 5 - 10) ]+  , ieffects = [EqpSlot EqpSlotMiscBonus]+  , ifeature = [Identified, Equipable]+  , idesc    = "Handheld underwater echolocator overdriven to scan dark corridors at the cost of emitting loud pings."+  , ikit     = []+  }++-- * Periodic jewelry++gorget = ItemKind+  { isymbol  = symbolNecklace+  , iname    = "Old Gorget"+  , ifreq    = [("useful", 25), ("treasure", 25)]+  , iflavour = zipFancy [BrCyan]+  , icount   = 1+  , irarity  = [(4, 3), (10, 3)]  -- weak, shallow+  , iverbHit = "whip"+  , iweight  = 30+  , idamage  = toDmg 0+  , iaspects = [ Timeout $ 1 + d 2+               , AddArmorMelee $ 2 + d 3+               , AddArmorRanged $ d 3 ]+  , ieffects = [ Unique, Periodic+               , Recharging (RefillCalm 1), EqpSlot EqpSlotMiscBonus ]+  , ifeature = [Durable, Precious, Identified, Equipable]+  , idesc    = "Highly ornamental, cold, large, steel medallion on a chain. Unlikely to offer much protection as an armor piece, but the old, worn engraving reassures you."+  , ikit     = []+  }+-- Not idenfified, because the id by use, e.g., via periodic activations. Fun.+necklace = ItemKind+  { isymbol  = symbolNecklace+  , iname    = "necklace"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy stdCol ++ zipPlain brightCol+  , icount   = 1+  , irarity  = [(10, 2)]+  , iverbHit = "whip"+  , iweight  = 30+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Periodic]+  , ifeature = [Precious, toVelocity 50, Equipable]  -- not dense enough+  , idesc    = "Tingling, rattling chain of flat encrusted links. Eccentric millionaires are known to hide their highly personalized body augmentation packs in such large jewelry pieces."+  , ikit     = []+  }+necklace1 = necklace+  { ifreq    = [("treasure", 100)]+  , irarity  = [(3, 0), (4, 1), (10, 2)]  -- prevents camping on lvl 3+  , iaspects = [Timeout $ d 3 + 4 - dl 3 |*| 10]+  , ieffects = [ Unique, ELabel "of Trickle Life", EqpSlot EqpSlotMiscBonus+               , Recharging (RefillHP 1) ]+               ++ ieffects necklace+  , ifeature = Durable : ifeature necklace+  }+necklace2 = necklace+  { ifreq    = [("treasure", 100)]  -- just too nasty to call it useful+  , irarity  = [(1, 1)]+  , iaspects = [Timeout $ d 3 + 3 - dl 3 |*| 10]+  , ieffects = [ Recharging (Summon "mobile animal" $ 1 + dl 2)+               , Recharging (Explode "waste")+               , Recharging Impress+               , Recharging (DropItem 1 maxBound COrgan "temporary condition") ]+               ++ ieffects necklace+  }+necklace3 = necklace+  { iaspects = [Timeout $ d 3 + 4 - dl 3 |*| 5]+  , ieffects = [ ELabel "of fearful listening"+               , Recharging (DetectActor 10)+               , Recharging (RefillCalm (-20)) ]+               ++ ieffects necklace+  }+necklace4 = necklace+  { iaspects = [Timeout $ d 4 + 4 - dl 4 |*| 2]+  , ieffects = [Recharging (Teleport $ d 2 * 3)]+               ++ ieffects necklace+  }+necklace5 = necklace+  { iaspects = [Timeout $ d 3 + 4 - dl 3 |*| 10]+  , ieffects = [ ELabel "of escape"+               , Recharging (Teleport $ 14 + d 3 * 3)+               , Recharging (DetectExit 20)+               , Recharging (RefillHP (-2)) ]  -- prevent micromanagement+               ++ ieffects necklace+  }+necklace6 = necklace+  { iaspects = [Timeout $ d 3 + 1 |*| 2]+  , ieffects = [Recharging (PushActor (ThrowMod 100 50))]+               ++ ieffects necklace+  }+necklace7 = necklace+  { ifreq    = [("treasure", 100)]+  , iaspects = [ AddMaxHP $ 10 + d 10+               , AddArmorMelee 20, AddArmorRanged 10+               , Timeout $ d 2 + 5 - dl 3 ]+  , ieffects = [ Unique, ELabel "of Overdrive", EqpSlot EqpSlotAddSpeed+               , Recharging (InsertMove $ 1 + d 2)+               , Recharging (RefillHP (-1))+               , Recharging (RefillCalm (-1)) ]  -- fake "hears something" :)+               ++ ieffects necklace+  , ifeature = Durable : ifeature necklace+  }+necklace8 = necklace+  { iaspects = [Timeout $ d 3 + 3 - dl 3 |*| 5]+  , ieffects = [Recharging $ Explode "spark"]+               ++ ieffects necklace+  }+necklace9 = necklace+  { iaspects = [Timeout $ d 3 + 3 - dl 3 |*| 5]+  , ieffects = [Recharging $ Explode "fragrance"]+               ++ ieffects necklace+  }++-- * Non-periodic jewelry++imageItensifier = ItemKind+  { isymbol  = symbolRing+  , iname    = "noctovisor"+  , ifreq    = [("treasure", 100), ("add nocto 1", 80)]+  , iflavour = zipFancy [BrGreen]+  , icount   = 1+  , irarity  = [(7, 2), (10, 2)]+  , iverbHit = "rattle"+  , iweight  = 700+  , idamage  = toDmg 0+  , iaspects = [AddNocto 1, AddSight (-1), AddArmorMelee $ 1 + dl 3 |*| 3]+  , ieffects = [EqpSlot EqpSlotMiscBonus]+  , ifeature = [Precious, Identified, Durable, Equipable]+  , idesc    = "Sturdy antique night vision goggles of unknown origin. Wired to run on modern micro-cells."+  , ikit     = []+  }+sightSharpening = ItemKind+  { isymbol  = symbolRing+  , iname    = "Autozoom Contact Lens"+  , ifreq    = [("treasure", 10), ("add sight", 1)]  -- not unique, so very rare+  , iflavour = zipPlain [White]+  , icount   = 1+  , irarity  = [(7, 1), (10, 5)]+  , iverbHit = "rap"+  , iweight  = 50+  , idamage  = toDmg 0+  , iaspects = [AddSight $ 1 + d 2, AddHurtMelee $ d 2 |*| 3]+  , ieffects = [EqpSlot EqpSlotAddSight]+  , ifeature = [Precious, Identified, Durable, Equipable]+  , idesc    = "Zooms on any movement, distant or close. Requires some getting used to. Never needs to be taken off."+  , ikit     = []+  }+-- Don't add standard effects to rings, because they go in and out+-- of eqp and so activating them would require UI tedium: looking for+-- them in eqp and inv or even activating a wrong item by mistake.+--+-- However, rings have the explosion effect.+-- They explode on use (and throw), for the fun of hitting everything+-- around without the risk of being hit. In case of teleportation explosion+-- this can also be used to immediately teleport close friends, as opposed+-- to throwing the ring, which takes time.+--+-- Rings should have @Identified@, so that they fully identify upon picking up.+-- Effects of many of them are seen in character sheet, so it would be silly+-- not to identify them. Necklaces provide the fun of id-by-use, because they+-- have effects and when they are triggered, they id.+ring = ItemKind+  { isymbol  = symbolRing+  , iname    = "ring"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain stdCol ++ zipFancy darkCol+  , icount   = 1+  , irarity  = [(10, 3)]+  , iverbHit = "knock"+  , iweight  = 15+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = []+  , ifeature = [Precious, Identified, Equipable]+  , idesc    = "A sturdy ring with a softly shining eye. If it contains a body booster unit, beware of the side-effects."+  , ikit     = []+  }+ring1 = ring+  { irarity  = [(10, 2)]+  , iaspects = [AddSpeed $ 1 + d 2, AddMaxHP $ dl 7 - 7 - d 7]+  , ieffects = [ Explode "distortion"  -- high power+               , EqpSlot EqpSlotAddSpeed ]+  }+ring2 = ring+  { irarity  = [(10, 5)]+  , iaspects = [AddMaxHP $ 10 + dl 10, AddMaxCalm $ dl 5 - 20 - d 5]+  , ieffects = [Explode "blast 20", EqpSlot EqpSlotAddMaxHP]+  }+ring3 = ring+  { irarity  = [(10, 5)]+  , iaspects = [AddMaxCalm $ 29 + dl 10]+  , ieffects = [Explode "blast 20", EqpSlot EqpSlotMiscBonus]+  , idesc    = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."+  }+ring4 = ring+  { irarity  = [(3, 3), (10, 5)]+  , iaspects = [AddHurtMelee $ d 5 + dl 5 |*| 3, AddMaxHP $ dl 3 - 5 - d 3]+  , ieffects = [Explode "blast 20", EqpSlot EqpSlotAddHurtMelee]+  }+ring5 = ring  -- by the time it's found, probably no space in eqp+  { irarity  = [(5, 0), (10, 2)]+  , iaspects = [AddShine $ d 2]+  , ieffects = [ Explode "distortion"  -- high power+               , EqpSlot EqpSlotLightSource ]+  , idesc    = "A sturdy ring with a large, shining stone."+  }+ring6 = ring+  { ifreq    = [("treasure", 100)]+  , irarity  = [(10, 2)]+  , iaspects = [ AddSpeed $ 3 + d 4+               , AddMaxCalm $ - 20 - d 20, AddMaxHP $ - 20 - d 20 ]+  , ieffects = [ Unique, ELabel "of Rush"  -- no explosion, because Durable+               , EqpSlot EqpSlotAddSpeed ]+  , ifeature = Durable : ifeature ring+  }+ring7 = ring+  { ifreq    = [("useful", 10), ("ring of opportunity sniper", 1) ]+  , irarity  = [(10, 5)]+  , iaspects = [AddAbility AbProject 8]+  , ieffects = [ ELabel "of opportunity sniper"+               , Explode "distortion"  -- high power+               , EqpSlot EqpSlotAbProject ]+  }+ring8 = ring+  { ifreq    = [("useful", 1), ("ring of opportunity grenadier", 1) ]+  , irarity  = [(1, 1)]+  , iaspects = [AddAbility AbProject 11]+  , ieffects = [ ELabel "of opportunity grenadier"+               , Explode "distortion"  -- high power+               , EqpSlot EqpSlotAbProject ]+  }++-- * Armor++armorLeather = ItemKind+  { isymbol  = symbolTorsoArmor+  , iname    = "spacesuit breastplate"+  , ifreq    = [("useful", 100), ("torso armor", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 1+  , irarity  = [(1, 9), (10, 3)]+  , iverbHit = "thud"+  , iweight  = 7000+  , idamage  = toDmg 0+  , iaspects = [ AddHurtMelee (-2)+               , AddArmorMelee $ 1 + d 2 + dl 2 |*| 5+               , AddArmorRanged $ dl 3 |*| 3 ]+  , ieffects = [EqpSlot EqpSlotAddArmorMelee]+  , ifeature = [Durable, Identified, Equipable]+  , idesc    = "A hard-shell torso segment cut from a disposed off spacesuit."+  , ikit     = []+  }+armorMail = armorLeather+  { iname    = "bulletproof vest"+  , ifreq    = [("useful", 100), ("torso armor", 1), ("armor ranged", 50) ]+  , iflavour = zipPlain [Cyan]+  , irarity  = [(6, 9), (10, 3)]+  , iweight  = 12000+  , idamage  = toDmg 0+  , iaspects = [ AddHurtMelee (-3)+               , AddArmorMelee $ 1 + d 2 + dl 2 |*| 5+               , AddArmorRanged $ 2 + d 2 + dl 3 |*| 3 ]+  , ieffects = [EqpSlot EqpSlotAddArmorRanged]+  , ifeature = [Durable, Identified, Equipable]+  , idesc    = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow."+  }+gloveFencing = ItemKind+  { isymbol  = symbolMiscArmor+  , iname    = "construction glove"+  , ifreq    = [("useful", 100), ("armor ranged", 50)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(5, 9), (10, 9)]+  , iverbHit = "flap"+  , iweight  = 100+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [ AddHurtMelee $ d 2 + dl 7 |*| 3+               , AddArmorRanged $ dl 2 |*| 3 ]+  , ieffects = [EqpSlot EqpSlotAddHurtMelee]+  , ifeature = [ toVelocity 50  -- flaps and flutters+               , Durable, Identified, Equipable ]+  , idesc    = "A flexible construction glove from rough leather ensuring a good grip. Also, quite effective in deflecting or even catching slow projectiles."+  , ikit     = []+  }+gloveGauntlet = gloveFencing+  { iname    = "spacesuit glove"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [BrCyan]+  , irarity  = [(1, 9), (10, 3)]+  , iweight  = 300+  , idamage  = toDmg $ 2 * d 1+  , iaspects = [ AddArmorMelee $ 2 + dl 2 |*| 5+               , AddArmorRanged $ dl 1 |*| 3 ]+  , ieffects = [EqpSlot EqpSlotAddArmorMelee]+  , idesc    = "A piece of a hull maintenance spacesuit, padded and reinforced with carbon fibre."+  }+gloveJousting = gloveFencing+  { iname    = "Welding Handgear"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy [BrRed]+  , irarity  = [(1, 3), (10, 3)]+  , iweight  = 500+  , idamage  = toDmg $ 4 * d 1+  , iaspects = [ AddHurtMelee $ dl 4 - 6 |*| 3+               , AddArmorMelee $ 2 + d 2 + dl 2 |*| 5+               , AddArmorRanged $ dl 2 |*| 3 ]+  , ieffects = [Unique, EqpSlot EqpSlotAddArmorMelee]+  , idesc    = "Rigid, bulky handgear embedding a welding equipment, complete with an affixed small shield and a darkened visor. Awe-inspiring."+  }++-- * Shields++-- Shield doesn't protect against ranged attacks to prevent+-- micromanagement: walking with shield, melee without.+-- Note that AI will pick them up but never wear and will use them at most+-- as a way to push itself (but they won't recharge, not being in eqp).+-- Being @Meleeable@ they will not be use as weapons either.+-- This is OK, using shields smartly is totally beyond AI.+buckler = ItemKind+  { isymbol  = symbolShield+  , iname    = "buckler"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 1+  , irarity  = [(4, 6)]+  , iverbHit = "bash"+  , iweight  = 2000+  , idamage  = [(96, 2 * d 1), (3, 4 * d 1), (1, 8 * d 1)]+  , iaspects = [ AddArmorMelee 40  -- not enough to compensate; won't be in eqp+               , AddHurtMelee (-30)  -- too harmful; won't be wielded as weapon+               , Timeout $ d 3 + 3 - dl 3 |*| 2 ]+  , ieffects = [ Recharging (PushActor (ThrowMod 200 50))+               , EqpSlot EqpSlotAddArmorMelee ]+  , ifeature = [ toVelocity 50  -- unwieldy to throw+               , Durable, Identified, Meleeable ]+  , idesc    = "Heavy and unwieldy arm protection made from an outer airlock panel. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with."+  , ikit     = []+  }+shield = buckler+  { iname    = "shield"+  , irarity  = [(8, 3)]+  , iflavour = zipPlain [Green]+  , iweight  = 3000+  , idamage  = [(96, 4 * d 1), (3, 8 * d 1), (1, 16 * d 1)]+  , iaspects = [ AddArmorMelee 80  -- not enough to compensate; won't be in eqp+               , AddHurtMelee (-70)  -- too harmful; won't be wielded as weapon+               , Timeout $ d 6 + 6 - dl 6 |*| 2 ]+  , ieffects = [ Recharging (PushActor (ThrowMod 400 50))+               , EqpSlot EqpSlotAddArmorMelee ]+  , ifeature = [ toVelocity 50  -- unwieldy to throw+               , Durable, Identified, Meleeable ]+  , idesc    = "Large and unwieldy rectangle made of anti-meteorite ceramic sheet. Absorbs a percentage of melee damage, both dealt and sustained. Too heavy to intercept projectiles with."+  }++-- * Weapons++dagger = ItemKind+  { isymbol  = symbolEdged+  , iname    = "cleaver"+  , ifreq    = [("useful", 100), ("starting weapon", 100)]+  , iflavour = zipPlain [BrCyan]+  , icount   = 1+  , irarity  = [(1, 40), (5, 1)]+  , iverbHit = "stab"+  , iweight  = 1000+  , idamage  = toDmg $ 6 * d 1+  , iaspects = [ AddHurtMelee $ d 3 + dl 3 |*| 3+               , AddArmorMelee $ d 2 |*| 5 ]+  , ieffects = [EqpSlot EqpSlotWeapon]+  , ifeature = [ toVelocity 40  -- ensuring it hits with the tip costs speed+               , Durable, Identified, Meleeable ]+  , idesc    = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."+  , ikit     = []+  }+daggerDropBestWeapon = dagger+  { iname    = "Double Dagger"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(1, 2), (10, 4)]+  -- The timeout has to be small, so that the player can count on the effect+  -- occuring consistently in any longer fight. Otherwise, the effect will be+  -- absent in some important fights, leading to the feeling of bad luck,+  -- but will manifest sometimes in fights where it doesn't matter,+  -- leading to the feeling of wasted power.+  -- If the effect is very powerful and so the timeout has to be significant,+  -- let's make it really large, for the effect to occur only once in a fight:+  -- as soon as the item is equipped, or just on the first strike.+  , iaspects = iaspects dagger ++ [Timeout $ d 3 + 4 - dl 3 |*| 2]+  , ieffects = ieffects dagger+               ++ [ Unique+                  , Recharging DropBestWeapon, Recharging $ RefillCalm (-3) ]+  , idesc    = "A knife with a forked blade that a focused fencer can use to catch and twist an opponent's weapon occasionally."+  }+hammer = ItemKind+  { isymbol  = symbolHafted+  , iname    = "demolition hammer"+  , ifreq    = [("useful", 100), ("starting weapon", 100)]+  , iflavour = zipFancy [BrMagenta]  -- avoid "pink"+  , icount   = 1+  , irarity  = [(3 * 10/12, 3), (5, 20), (8, 1)]+                 -- don't make it too common on lvl 3+  , iverbHit = "club"+  , iweight  = 1600+  , idamage  = [(96, 8 * d 1), (3, 12 * d 1), (1, 16 * d 1)]+  , iaspects = [AddHurtMelee $ d 2 + dl 2 |*| 3]+  , ieffects = [EqpSlot EqpSlotWeapon]+  , ifeature = [ toVelocity 40  -- ensuring it hits with the tip costs speed+               , Durable, Identified, Meleeable ]+  , idesc    = "A hammer on a long handle used for construction work. It may not cause grave wounds, but neither does it ricochet or glance off armor. Great sidearm for opportunistic blows against armored foes."+  , ikit     = []+  }+hammerParalyze = hammer+  { iname    = "Concussion Hammer"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(5, 2), (10, 4)]+  , idamage  = toDmg $ 8 * d 1+  , iaspects = iaspects hammer ++ [Timeout $ d 2 + 3 - dl 2 |*| 2]+  , ieffects = ieffects hammer ++ [Unique, Recharging $ Paralyze 10]+  }+hammerSpark = hammer+  { iname    = "Grand Smithhammer"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(5, 2), (10, 4)]+  , idamage  = toDmg $ 8 * d 1+  , iaspects = iaspects hammer ++ [Timeout $ d 4 + 4 - dl 4 |*| 2]+  , ieffects = ieffects hammer ++ [Unique, Recharging $ Explode "spark"]+  }+sword = ItemKind+  { isymbol  = symbolPolearm+  , iname    = "sharpened pipe"+  , ifreq    = [("useful", 100), ("starting weapon", 10)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 1+  , irarity  = [(4, 1), (5, 15)]+  , iverbHit = "slash"+  , iweight  = 2000+  , idamage  = toDmg $ 10 * d 1+  , iaspects = []+  , ieffects = [EqpSlot EqpSlotWeapon]+  , ifeature = [ toVelocity 40  -- ensuring it hits with the tip costs speed+               , Durable, Identified, Meleeable ]+  , idesc    = "A makeshift weapon of simple design, but great potential. Hard to master, though."+  , ikit     = []+  }+swordImpress = sword+  { isymbol  = symbolEdged+  , iname    = "Master's Sword"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(5, 1), (10, 4)]+  , iaspects = [Timeout $ d 4 + 5 - dl 4 |*| 2]+  , ieffects = ieffects sword+               ++ [Unique, Recharging Impress, Recharging (DetectActor 3)]+  }+swordNullify = sword+  { isymbol  = symbolEdged+  , iname    = "Gutting Sword"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(5, 1), (10, 4)]+  , iaspects = [Timeout $ d 4 + 5 - dl 4 |*| 2]+  , ieffects = ieffects sword+               ++ [ Unique+                  , Recharging $ DropItem 1 maxBound COrgan+                                          "temporary condition"+                  , Recharging $ RefillCalm (-10) ]+  }+halberd = ItemKind+  { isymbol  = symbolPolearm+  , iname    = "pole cleaver"+  , ifreq    = [("useful", 100), ("starting weapon", 20)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(8, 1), (9, 40)]+  , iverbHit = "impale"+  , iweight  = 3000+  , idamage  = [(96, 12 * d 1), (3, 18 * d 1), (1, 24 * d 1)]+  , iaspects = [ AddHurtMelee (-20)  -- just benign enough to be used+               , AddArmorMelee $ 1 + dl 3 |*| 5 ]+  , ieffects = [EqpSlot EqpSlotWeapon]+  , ifeature = [ toVelocity 20  -- not balanced+               , Durable, Identified, Meleeable ]+  , idesc    = "An improvised but deadly weapon made of a long, sharp kitchen knife glued and bound to a long pole."+  , ikit     = []+  }+halberdPushActor = halberd+  { iname    = "Swiss Halberd"+  , ifreq    = [("treasure", 20)]+  , irarity  = [(8, 1), (9, 20)]+  , idamage  = toDmg $ 12 * d 1+  , iaspects = iaspects halberd ++ [Timeout $ d 5 + 5 - dl 5 |*| 2]+  , ieffects = ieffects halberd+               ++ [Unique, Recharging (PushActor (ThrowMod 400 25))]+  , idesc    = "A perfect replica made for a reenactor troupe, missing only some sharpening. Versatile, with great reach and leverage. Foes are held at a distance."+  }++-- * Wands++wand = ItemKind+  { isymbol  = symbolWand+  , iname    = "injector"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy brightCol+  , icount   = 1+  , irarity  = []+  , iverbHit = "club"+  , iweight  = 300+  , idamage  = toDmg 0+  , iaspects = [AddShine 1, AddSpeed (-1)]  -- pulsing with power, distracts+  , ieffects = []+  , ifeature = [ toVelocity 125  -- sufficiently advanced tech+               , Applicable, Durable ]+  , idesc    = "Buzzing with dazzling light that shines even through appendages that handle it."+  , ikit     = []+  }+wand1 = wand+  { ieffects = []  -- will be: emit a cone of sound shrapnel that makes enemy cover his ears and so drop '|' and '{'+  }+wand2 = wand+  { ieffects = []+  }++-- * Treasure++gem = ItemKind+  { isymbol  = symbolGem+  , iname    = "gem"+  , ifreq    = [("treasure", 100), ("gem", 100)]+  , iflavour = zipPlain $ delete BrYellow brightCol  -- natural, so not fancy+  , icount   = 1+  , irarity  = []+  , iverbHit = "tap"+  , iweight  = 50+  , idamage  = toDmg 0+  , iaspects = [AddShine 1, AddSpeed (-1)]+                 -- reflects strongly, distracts; so it glows in the dark,+                 -- is visible on dark floor, but not too tempting to wear+  , ieffects = []+  , ifeature = [Precious]  -- no @Identified@ and no effects, so never ided+  , idesc    = "Precious, though useless. Worth around 100 gold grains."+  , ikit     = []+  }+gem1 = gem+  { irarity  = [(3 * 10/12, 0), (10, 12)]+  }+gem2 = gem+  { irarity  = [(5 * 10/12, 0), (10, 14)]+  }+gem3 = gem+  { irarity  = [(7 * 10/12, 0), (10, 16)]+  }+gem4 = gem+  { iname    = "stimpack"+  , iflavour = zipPlain [BrYellow]+  , irarity  = [(1, 40), (10, 40)]+  , iaspects = []+  , ieffects = [ELabel "of youth", RefillCalm 5, RefillHP 15]+  , ifeature = [Identified, Applicable, Precious]+  , idesc    = "Calms, heals, invigorates and rejuvenates at the same time. No side-effects. As valuable as precious gems, at 100 gold grains each."+  }+currency = ItemKind+  { isymbol  = symbolGold+  , iname    = "gold grain"+  , ifreq    = [("treasure", 100), ("currency", 100)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 10 + d 20 + dl 20+  , irarity  = [(1, 25), (10, 10)]+  , iverbHit = "tap"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = []+  , ifeature = [Identified, Precious]+  , idesc    = "Reliably valuable in every civilized place."+  , ikit     = []+  }++-- * Allure-specific++needle = ItemKind+  { isymbol  = symbolProjectile+  , iname    = "needle"+  , ifreq    = [("needle", 1)]  -- special; TODO: fast when fired, not thrown+  , iflavour = zipPlain [BrBlue]+  , icount   = 9 * d 3+  , irarity  = [(1, 1)]+  , iverbHit = "prick"+  , iweight  = 3+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee (-10 |*| 5)]+  , ieffects = []+  , ifeature = [toVelocity 70, Fragile]+  , idesc    = "A long hypodermic needle ending in a dried out micro-syringe. It's too light to throw hard, but it penetrates deeply, causing intense pain on movement."+  , ikit     = []+  }+constructionHooter = scroll+  { iname    = "construction hooter"+  , ifreq    = [("useful", 1), ("construction hooter", 1)]  -- extremely rare+  , iflavour = zipPlain [BrRed]+  , irarity  = [(1, 1)]+  , iaspects = []+  , ieffects = [Summon "construction robot" $ 1 + dl 2]+  , ifeature = Identified : ifeature scroll+  , idesc    = "The single-use electronic overdrive hooter that construction robots use to warn about danger and call help in extreme emergency."   , ikit     = []   }
GameDefinition/Content/ItemKindActor.hs view
@@ -1,13 +1,17 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Actor (or rather actor body trunk) definitions.-module Content.ItemKindActor ( actors ) where+module Content.ItemKindActor+  ( actors+  ) where -import qualified Data.EnumMap.Strict as EM+import Prelude () +import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Flavour@@ -16,29 +20,34 @@  actors :: [ItemKind] actors =-  [warrior, warrior2, warrior3, warrior4, soldier, sniper, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot]+  [warrior, warrior2, warrior3, warrior4, warrior5, scout, ranger, escapist, ambusher, soldier, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush]+  -- Allure-specific+  ++ [razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot] -warrior,    warrior2, warrior3, warrior4, soldier, sniper, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot :: ItemKind+warrior,    warrior2, warrior3, warrior4, warrior5, scout, ranger, escapist, ambusher, soldier, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush :: ItemKind+-- Allure-specific+razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot :: ItemKind  -- * Hunams  warrior = ItemKind   { isymbol  = '@'-  , iname    = "mercenary"  -- modified if in hero faction-  , ifreq    = [("hero", 100), ("civilian", 100), ("mobile", 1)]-  , iflavour = zipPlain [BrBlack]  -- modified if in hero faction+  , iname    = "mercenary"  -- modified if initial actors in hero faction+  , ifreq    = [("hero", 100), ("mobile", 1)]+  , iflavour = zipPlain [BrWhite]   , icount   = 1   , irarity  = [(1, 5)]   , iverbHit = "thud"   , iweight  = 80000+  , idamage  = toDmg 0   , iaspects = [ AddMaxHP 80  -- partially from clothes and assumed first aid-                              -- also possibly from artificial skin-               , AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ]+               , AddMaxCalm 70, AddSpeed 20, AddNocto 2+               , AddAbility AbProject 2, AddAbility AbApply 1+               , AddAbility AbAlter 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("fist", COrgan), ("foot", COrgan), ("eye 5", COrgan)+  , ikit     = [ ("fist", COrgan), ("foot", COrgan), ("eye 6", COrgan)                , ("sapient brain", COrgan) ]   } warrior2 = warrior@@ -47,26 +56,51 @@   { iname    = "engineer" } warrior4 = warrior   { iname    = "doctor" }+warrior5 = warrior+  { iname    = "hacker" } -soldier = warrior-  { iname    = "soldier"-  , ifreq    = [("soldier", 100), ("mobile", 1)]-  , ikit     = ikit warrior ++ [("starting weapon", CEqp)]+scout = warrior+  { iname    = "scout"+  , ifreq    = [("scout hero", 100), ("mobile", 1)]+  , ikit     = ikit warrior+               ++ [ ("add sight", CEqp)+                  , ("armor ranged", CEqp)+                  , ("add nocto 1", CInv) ]   }-sniper = warrior-  { iname    = "sniper"-  , ifreq    = [("sniper", 100), ("mobile", 1)]+ranger = warrior+  { iname    = "ranger"+  , ifreq    = [("ranger hero", 100), ("mobile", 1)]+  , ikit     = ikit warrior ++ [("weak arrow", CInv), ("armor ranged", CEqp)]+  }+escapist = warrior+  { iname    = "escapist"+  , ifreq    = [("escapist hero", 100), ("mobile", 1)]   , ikit     = ikit warrior+               ++ [ ("add sight", CEqp)+                  , ("weak arrow", CInv)  -- mostly for probing+                  , ("armor ranged", CEqp)+                  , ("flask", CInv)+                  , ("light source", CInv)+                  , ("blanket", CInv) ]+  }+ambusher = warrior+  { iname    = "ambusher"+  , ifreq    = [("ambusher hero", 100), ("mobile", 1)]+  , ikit     = ikit warrior  -- dark and numerous, so more kit without exploring                ++ [ ("ring of opportunity sniper", CEqp)-                  , ("any arrow", CSha), ("any arrow", CInv)-                  , ("any arrow", CInv), ("any arrow", CInv)-                  , ("flask", CInv), ("light source", CSha)-                  , ("light source", CInv), ("light source", CInv) ]+                  , ("light source", CEqp), ("wooden torch", CInv)+                  , ("weak arrow", CInv), ("any arrow", CSha), ("flask", CSha) ]   }+soldier = warrior+  { iname    = "soldier"+  , ifreq    = [("soldier hero", 100), ("mobile", 1)]+  , ikit     = ikit warrior ++ [("starting weapon", CEqp)]+  }  civilian = warrior   { iname    = "clerk"-  , ifreq    = [("civilian", 100), ("mobile", 1)] }+  , ifreq    = [("civilian", 100), ("mobile", 1)]+  , iflavour = zipPlain [BrBlack] } civilian2 = civilian   { iname    = "hairdresser" } civilian3 = civilian@@ -78,100 +112,116 @@  -- * Aliens +-- They have bright colours, because they are not natural.+ eye = ItemKind   { isymbol  = 'w'   , iname    = "beckoning walker"-  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , ifreq    = [ ("monster", 100), ("mobile", 1)+               , ("mobile monster", 100), ("scout monster", 10) ]   , iflavour = zipFancy [BrRed]   , icount   = 1   , irarity  = [(4, 6), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 70, AddSpeed 20, AddNocto 2+               , AddAggression 1+               , AddAbility AbProject 2, AddAbility AbApply 1+               , AddAbility AbAlter 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Walks with a stately dignity. You read death in the slow beckoning gestures of its revolting upper appendages."   , ikit     = [ ("foot", COrgan), ("tentacle", COrgan)-               , ("eye 5", COrgan)+               , ("eye 6", COrgan)                , ("sapient brain", COrgan) ]   } fastEye = ItemKind   { isymbol  = 'b'   , iname    = "crawling biter"-  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , ifreq    = [ ("monster", 100), ("mobile", 1)+               , ("mobile monster", 100), ("scout monster", 60) ]   , iflavour = zipFancy [BrBlue]   , icount   = 1   , irarity  = [(4, 3), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 5, AddMaxCalm 60, AddSpeed 30 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 5, AddMaxCalm 70, AddSpeed 30, AddNocto 2+               , AddAggression 1+               , AddAbility AbAlter 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "It bites as blindingly fast as it runs. Or rolls? Or crawls? Also, cuts and pierces."   , ikit     = [ ("tentacle", COrgan), ("jaw", COrgan)-               , ("eye 4", COrgan), ("speed gland 10", COrgan)+               , ("eye 3", COrgan), ("speed gland 10", COrgan)                , ("sapient brain", COrgan) ]   } nose = ItemKind  -- depends solely on smell   { isymbol  = 'h'   , iname    = "tentacled horror"-  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , ifreq    = [("monster", 100), ("mobile", 1), ("mobile monster", 100)]   , iflavour = zipFancy [BrGreen]   , icount   = 1   , irarity  = [(4, 5), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 18-               , AddSkills $ EM.fromList [(AbProject, -1)] ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 16, AddNocto 2+               , AddAggression 1+               , AddAbility AbProject (-1), AddAbility AbAlter 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A blind, slimy mass of clawing, stinging and burning. You'd think it's powerless, but as soon as it touches your trembling body, it's always one step ahead."   , ikit     = [ ("nostril", COrgan), ("small claw", COrgan)                , ("tentacle", COrgan), ("tentacle", COrgan)-               , ("thorn", COrgan), ("sting", COrgan)+               , ("thorn", COrgan), ("venom tooth", COrgan)                , ("sapient brain", COrgan) ]   } elbow = ItemKind   { isymbol  = 's'   , iname    = "creepy shooter"-  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , ifreq    = [ ("monster", 100), ("mobile", 1)+               , ("mobile monster", 100), ("scout monster", 30) ]   , iflavour = zipFancy [BrMagenta]   , icount   = 1   , irarity  = [(6, 1), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 12, AddMaxCalm 90, AddSpeed 21-               , AddSkills-                 $ EM.fromList [(AbProject, 2), (AbApply, 1), (AbMelee, -1)] ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 12, AddMaxCalm 80, AddSpeed 21, AddNocto 2+               , AddAbility AbProject 2, AddAbility AbApply 1+               , AddAbility AbAlter 2, AddAbility AbMelee (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "It moves in sudden jerks and never makes a noise. Speaks in hard objects hurled at deadly speeds."   , ikit     = [ ("speed gland 4", COrgan)-               , ("eye 7", COrgan)+               , ("eye 8", COrgan)                , ("any arrow", CSha), ("any arrow", CInv)-               , ("any arrow", CInv), ("any arrow", CInv)+               , ("weak arrow", CInv), ("weak arrow", CInv)                , ("sapient brain", COrgan) ]   } torsor = ItemKind   { isymbol  = 'M'   , iname    = "The Maker of Contact"-  , ifreq    = [("alien", 100), ("mobile", 1)]+  , ifreq    = [("monster", 100), ("mobile", 1)]   , iflavour = zipFancy [BrCyan]   , icount   = 1-  , irarity  = [(11 * 10/12, 0), (10, 1000)]  -- unique+  , irarity  = [(11 * 10/12, 0), (12 * 10/12, 1000)]  -- unique   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ Unique, AddMaxHP 300, AddMaxCalm 100, AddSpeed 6-               , AddSkills $ EM.fromList-                   [(AbProject, 2), (AbApply, 1), (AbTrigger, -1)] ]-                   -- can't switch levels, a miniboss-  , ieffects = []+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 300, AddMaxCalm 100, AddSpeed 6, AddNocto 2+               , AddAggression 3+               , AddAbility AbProject 2, AddAbility AbApply 1+               , AddAbility AbAlter (-1) ]  -- can't switch levels, the boss+  , ieffects = [Unique]   , ifeature = [Durable, Identified]   , idesc    = "The mind, the heart behind it all. Warmth and sympathy pour out through the graceful undulation of tentacles, sharp claws, snapping jaw, grinding teeth and tensing fangs."-  , ikit     = [ ("tentacle", COrgan), ("claw", COrgan), ("large jaw", COrgan)-               , ("venom tooth", COrgan), ("venom fang", COrgan)-               , ("eye 5", COrgan), ("speed gland 4", COrgan)+  , ikit     = [ ("tentacle", COrgan), ("hooked claw", COrgan)+               , ("large jaw", COrgan)+               , ("sting", COrgan), ("venom fang", COrgan)+               , ("eye 6", COrgan), ("speed gland 4", COrgan)                , ("gem", CInv), ("gem", CInv), ("gem", CInv), ("gem", CInv)                , ("sapient brain", COrgan) ]   }@@ -181,163 +231,181 @@ -- They need rather strong melee, because they don't use items. -- Unless/until they level up. +-- They have dull colors, except for yellow, because there is no dull variant.+ goldenJackal = ItemKind  -- basically a much smaller and slower hyena   { isymbol  = 'j'   , iname    = "golden jackal"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 50)]+  , ifreq    = [ ("animal", 100), ("mobile", 1), ("mobile animal", 100)+               , ("scavenger", 50) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(1, 5)]+  , irarity  = [(1, 3)]   , iverbHit = "thud"   , iweight  = 13000-  , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 22 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 12, AddMaxCalm 70, AddSpeed 24, AddNocto 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("small jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan)+  , ikit     = [ ("small jaw", COrgan), ("eye 6", COrgan), ("nostril", COrgan)                , ("animal brain", COrgan) ]   } griffonVulture = ItemKind   { isymbol  = 'v'   , iname    = "griffon vulture"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 30)]+  , ifreq    = [ ("animal", 100), ("mobile", 1), ("mobile animal", 100)+               , ("scavenger", 30) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1   , irarity  = [(1, 5)]   , iverbHit = "thud"   , iweight  = 13000-  , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.singleton AbAlter (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 12, AddMaxCalm 80, AddSpeed 22, AddNocto 2+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors+      -- Animals don't have leader, usually, so even if only one of level,+      -- it pays the communication overhead, so the speed is higher to get+      -- them on par with human leaders moving solo. Random double moves,+      -- on either side, are just too frustrating.   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("screeching beak", COrgan)  -- in reality it grunts and hisses-               , ("small claw", COrgan), ("eye 6", COrgan)+               , ("small claw", COrgan), ("eye 7", COrgan)                , ("animal brain", COrgan) ]   } skunk = ItemKind   { isymbol  = 's'   , iname    = "hog-nosed skunk"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [White]   , icount   = 1   , irarity  = [(1, 5), (10, 3)]   , iverbHit = "thud"   , iweight  = 4000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20-               , AddSkills $ EM.singleton AbAlter (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 22, AddNocto 2+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("scent gland", COrgan)                , ("small claw", COrgan), ("snout", COrgan)-               , ("nostril", COrgan), ("eye 2", COrgan)+               , ("nostril", COrgan), ("eye 3", COrgan)                , ("animal brain", COrgan) ]   } armadillo = ItemKind   { isymbol  = 'a'   , iname    = "giant armadillo"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1   , irarity  = [(1, 5)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 30, AddSpeed 17-               , AddSkills $ EM.singleton AbAlter (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 30, AddSpeed 20, AddNocto 2+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("claw", COrgan), ("snout", COrgan), ("armored skin", COrgan)-               , ("nostril", COrgan), ("eye 2", COrgan)-               , ("animal brain", COrgan) ]+  , ikit     = [ ("hooked claw", COrgan), ("snout", COrgan)+               , ("armored skin", COrgan), ("nostril", COrgan)+               , ("eye 3", COrgan), ("animal brain", COrgan) ]   } gilaMonster = ItemKind   { isymbol  = 'g'   , iname    = "Gila monster"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(2, 5), (10, 3)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 15-               , AddSkills $ EM.singleton AbAlter (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 12, AddMaxCalm 50, AddSpeed 18, AddNocto 2+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("venom tooth", COrgan), ("small claw", COrgan)-               , ("eye 2", COrgan), ("nostril", COrgan)+               , ("eye 3", COrgan), ("nostril", COrgan)                , ("animal brain", COrgan) ]   } rattlesnake = ItemKind   { isymbol  = 's'   , iname    = "rattlesnake"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1   , irarity  = [(4, 1), (10, 7)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 25, AddMaxCalm 60, AddSpeed 15-               , AddSkills $ EM.singleton AbAlter (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 25, AddMaxCalm 60, AddSpeed 16, AddNocto 2+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("venom fang", COrgan)-               , ("eye 3", COrgan), ("nostril", COrgan)+               , ("eye 4", COrgan), ("nostril", COrgan)                , ("animal brain", COrgan) ]   } komodoDragon = ItemKind  -- bad hearing; regeneration makes it very powerful   { isymbol  = 'k'   , iname    = "Komodo dragon"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(7, 0), (10, 10)]+  , irarity  = [(9, 0), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 16 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 18, AddNocto 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("large tail", COrgan), ("jaw", COrgan), ("claw", COrgan)-               , ("speed gland 4", COrgan), ("armored skin", COrgan)-               , ("eye 2", COrgan), ("nostril", COrgan)-               , ("animal brain", COrgan) ]+  , ikit     = [ ("large tail", COrgan), ("jaw", COrgan)+               , ("hooked claw", COrgan), ("speed gland 4", COrgan)+               , ("armored skin", COrgan), ("eye 3", COrgan)+               , ("nostril", COrgan), ("animal brain", COrgan) ]   } hyena = ItemKind   { isymbol  = 'h'   , iname    = "spotted hyena"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 20)]+  , ifreq    = [ ("animal", 100), ("mobile", 1), ("mobile animal", 100)+               , ("scavenger", 20) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1   , irarity  = [(4, 1), (10, 8)]   , iverbHit = "thud"   , iweight  = 60000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 30 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 70, AddSpeed 32, AddNocto 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan)+  , ikit     = [ ("jaw", COrgan), ("eye 6", COrgan), ("nostril", COrgan)                , ("animal brain", COrgan) ]   } alligator = ItemKind   { isymbol  = 'a'   , iname    = "alligator"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(6, 1), (10, 9)]+  , irarity  = [(8, 1), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 15 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 41, AddMaxCalm 70, AddSpeed 18, AddNocto 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("large jaw", COrgan), ("large tail", COrgan)                , ("small claw", COrgan)-               , ("armored skin", COrgan), ("eye 5", COrgan)+               , ("armored skin", COrgan), ("eye 6", COrgan)                , ("animal brain", COrgan) ]   } rhinoceros = ItemKind@@ -349,10 +417,11 @@   , irarity  = [(1 * 10/12, 1000000), (2 * 10/12, 0)]  -- unique   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ Unique, AddMaxHP 90, AddMaxCalm 60, AddSpeed 25-               , AddSkills $ EM.singleton AbTrigger (-1) ]-                   -- can't switch levels, a miniboss-  , ieffects = []+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 90, AddMaxCalm 60, AddSpeed 27, AddNocto 2+               , AddAggression 2+               , AddAbility AbAlter (-1) ]  -- can't switch levels, a miniboss+  , ieffects = [Unique]   , ifeature = [Durable, Identified]   , idesc    = "The last of its kind. Blind with rage. Charges at deadly speed."   , ikit     = [ ("armored skin", COrgan), ("eye 2", COrgan)@@ -365,69 +434,77 @@ beeSwarm = ItemKind   { isymbol  = 'b'   , iname    = "bee swarm"-  , ifreq    = [("animal", 100), ("horror", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1)]   , iflavour = zipPlain [Brown]   , icount   = 1   , irarity  = [(1, 2), (10, 4)]   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30-               , AddSkills $ EM.singleton AbAlter (-1) ]  -- armor in sting+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 8, AddMaxCalm 60+               , AddSpeed 30, AddNocto 2  -- armor in sting+               , AddAbility AbAlter (-2) ]  -- can't use stairs nor doors   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("bee sting", COrgan), ("vision 4", COrgan)+  , ikit     = [ ("bee sting", COrgan), ("vision 6", COrgan)                , ("insect mortality", COrgan), ("animal brain", COrgan) ]   } hornetSwarm = ItemKind   { isymbol  = 'h'   , iname    = "hornet swarm"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]+  , ifreq    = [("animal", 100), ("mobile", 1), ("mobile animal", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(5, 1), (10, 8)]   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30-               , AddSkills $ EM.singleton AbAlter (-1)-               , AddArmorMelee 80, AddArmorRanged 80 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 8, AddMaxCalm 70, AddSpeed 30, AddNocto 2+               , AddAbility AbAlter (-2)  -- can't use stairs nor doors+               , AddArmorMelee 80, AddArmorRanged 40 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("sting", COrgan), ("vision 4", COrgan)+  , ikit     = [ ("sting", COrgan), ("vision 8", COrgan)                , ("insect mortality", COrgan), ("animal brain", COrgan) ]   } thornbush = ItemKind   { isymbol  = 't'   , iname    = "thornbush"-  , ifreq    = [("animal", 50)]+  , ifreq    = [("animal", 50), ("immobile animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1-  , irarity  = [(1, 3)]+  , irarity  = [(1, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 22, AddNocto 2+               , AddAbility AbWait 1, AddAbility AbMelee 1 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [("thorn", COrgan), ("armored skin", COrgan)]   } --- * Robots+-- * Robots, Allure-specific +-- Robots have any colors but only f, d and r letters. Avoid these letters+-- for other factions.+ razorwireFence = ItemKind   { isymbol  = 'f'   , iname    = "razorwire fence"   , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [Cyan]   , icount   = 1-  , irarity  = [(3 * 10/12, 0), (4, 2)]+  , irarity  = [(3 * 10/12, 0), (4 * 10/12, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])-               , AddArmorMelee 50, AddArmorRanged 50 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddNocto 2+               , AddAbility AbWait 1, AddAbility AbMelee 1+               , AddArmorMelee 40, AddArmorRanged 20 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Must have been bought by previous ship owners to contain the wild animal infestation."@@ -439,29 +516,31 @@   , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(3 * 10/12, 0), (4, 2)]+  , irarity  = [(3 * 10/12, 0), (4 * 10/12, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 40-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])-               , AddArmorMelee 50, AddArmorRanged 50 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 40, AddNocto 2+               , AddAbility AbWait 1, AddAbility AbMelee 1+               , AddArmorMelee 40, AddArmorRanged 20 ]   , ieffects = []   , ifeature = [Durable, Identified]-  , idesc    = "Marginally intelligent electric shepherd. Originally used in the spaceship's dairy farm and the zoo level."+  , idesc    = "Marginally intelligent electric shepherd. Originally used in orbital dairy farms and planetary zoos."   , ikit     = [("live wire", COrgan)]   } activeFence = ItemKind   { isymbol  = 'f'   , iname    = "active fence"-  , ifreq    = [("robot", 50), ("immobile robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [Red]   , icount   = 1-  , irarity  = [(3 * 10/12, 0), (4, 1)]+  , irarity  = [(5 * 10/12, 0), (6 * 10/12, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20-               , AddSkills $ EM.fromList [(AbWait, 1), (AbProject, 3)]-               , AddArmorMelee 50, AddArmorRanged 50 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20, AddNocto 2+               , AddAbility AbWait 1, AddAbility AbProject 3+               , AddArmorMelee 40, AddArmorRanged 20 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Makeshift, mostly non-lethal, autonomous perimeter defense outpost."@@ -471,15 +550,16 @@ steamFaucet = ItemKind   { isymbol  = 'f'   , iname    = "steam faucet"-  , ifreq    = [("robot", 50), ("immobile robot", 50)]-  , iflavour = zipPlain [BrWhite]+  , ifreq    = [("robot", 50), ("immobile robot", 60)]+  , iflavour = zipPlain [BrBlue]   , icount   = 1   , irarity  = [(5, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 10-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])-               , AddArmorMelee 80, AddArmorRanged 80 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 10, AddNocto 2+               , AddAbility AbWait 1, AddAbility AbMelee 1+               , AddArmorMelee 40, AddArmorRanged 20 ]  -- hard material   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A cracked valve on one of the superheated water pipes spreading radially outward from the tokamak level."@@ -488,14 +568,16 @@ biogasFaucet = ItemKind   { isymbol  = 'f'   , iname    = "biogas faucet"-  , ifreq    = [("robot", 50), ("immobile robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 120)]   , iflavour = zipPlain [BrGreen]   , icount   = 1   , irarity  = [(5, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 22+               , AddNocto 2, AddShine 3+               , AddAbility AbWait 1, AddAbility AbMelee 1 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "An emergency pressure-release vent on a smelly biogas pipe."@@ -504,14 +586,16 @@ medbotFaucet = ItemKind   { isymbol  = 'f'   , iname    = "nano medbot faucet"-  , ifreq    = [("robot", 50), ("immobile robot", 400)]+  , ifreq    = [("robot", 50), ("immobile robot", 300)]   , iflavour = zipPlain [BrYellow]   , icount   = 1   , irarity  = [(5, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3-               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 22+               , AddNocto 2, AddShine 3+               , AddAbility AbWait 1, AddAbility AbMelee 1 ]   , ieffects = []   , ifeature = [Durable, Identified]  -- TODO: only heal humans   , idesc    = "A faucet of a malfunctioning nano medical robot dispenser. Let's hope the medbots are still effective."@@ -520,17 +604,17 @@ surveillanceDrone = ItemKind   { isymbol  = 'd'   , iname    = "surveillance drone"-  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]+  , ifreq    = [("robot", 100), ("mobile", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1   , irarity  = []  -- TODO: too boring   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 3, AddMaxCalm 90, AddSpeed 30-               , AddSkills-                 $ EM.fromList-                 $ zip [AbDisplace, AbMoveItem, AbProject, AbMelee] [-1, -1..]-               , AddArmorMelee 80, AddArmorRanged 80 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 6, AddMaxCalm 90, AddSpeed 30, AddNocto 2+               , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1)+               , AddAbility AbProject (-1), AddAbility AbMelee (-1)+               , AddArmorMelee 40, AddArmorRanged 20 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A video camera in each room would violate privacy of passengers, hence surveillance drones. Programmed to be easy to fend off, they keep a respectful distance."@@ -539,17 +623,17 @@ shepherdDrone = ItemKind   { isymbol  = 'd'   , iname    = "shepherd drone"-  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]+  , ifreq    = [("robot", 100), ("mobile", 100), ("mobile robot", 100)]   , iflavour = zipPlain [BrRed]   , icount   = 1   , irarity  = [(1, 7)]   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 30-               , AddSkills-                 $ EM.fromList-                 $ zip [AbDisplace, AbMoveItem, AbProject] [-1, -1..]-               , AddArmorMelee 80, AddArmorRanged 80 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 30, AddNocto 2+               , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1)+               , AddAbility AbProject (-1)+               , AddArmorMelee 80, AddArmorRanged 40 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A shabby drone for bringing cows home."@@ -559,17 +643,17 @@ huntingDrone = ItemKind   { isymbol  = 'd'   , iname    = "hunting drone"-  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]+  , ifreq    = [("robot", 100), ("mobile", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Green]   , icount   = 1   , irarity  = [(3, 0), (5, 2), (10, 4)]   , iverbHit = "thud"   , iweight  = 500-  , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 40-               , AddSkills-                 $ EM.fromList-                 $ zip [AbDisplace, AbMoveItem, AbMelee] [-1, -1..]-               , AddArmorMelee 80, AddArmorRanged 80 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 6, AddMaxCalm 60, AddSpeed 40, AddNocto 2+               , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1)+               , AddAbility AbMelee (-1)+               , AddArmorMelee 40, AddArmorRanged 20 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Originally designed for hunting down and putting to sleep stray animals. The sleeping agent has long since dried up."@@ -580,14 +664,15 @@   { isymbol  = 'r'   , iname    = "feral home robot"                -- TODO: name another 'deranged', tertiary imperative: survival-  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]+  , ifreq    = [("robot", 100), ("mobile", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(1, 20), (10, 6)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20-               , AddSkills $ EM.singleton AbProject (-1) ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20, AddNocto 2+               , AddAbility AbProject (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Once a timid household robot, now sufficiently adapted to survive in the deadly environment."@@ -597,14 +682,15 @@ wasteRobot = ItemKind   { isymbol  = 'r'   , iname    = "waste disposal robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)-               , ("construction robot", 1) ]+  , ifreq    = [ ("robot", 100), ("mobile", 100), ("mobile robot", 100)+               , ("construction robot", 50) ]   , iflavour = zipPlain [Green]   , icount   = 1   , irarity  = [(1, 10), (10, 6)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 15 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 15, AddNocto 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "You are not in its database, hence you are waste."@@ -616,34 +702,36 @@ lightRobot = ItemKind   { isymbol  = 'r'   , iname    = "decoration robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)-               , ("construction robot", 1) ]+  , ifreq    = [ ("robot", 100), ("mobile", 100), ("mobile robot", 100)+               , ("construction robot", 100) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1   , irarity  = [(3, 1), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 30-               , AddSkills $ EM.singleton AbProject 2 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 30, AddNocto 2+               , AddAbility AbProject 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Interior and exterior decoration robot. Strongly fancies deep reds recently."-  , ikit     = [ ("claw", COrgan), ("tentacle", COrgan), ("spotlight", COrgan)-               , ("armored skin", COrgan), ("eye 5", COrgan)-               , ("robot brain", COrgan) ]+  , ikit     = [ ("hooked claw", COrgan), ("tentacle", COrgan)+               , ("spotlight", COrgan), ("armored skin", COrgan)+               , ("eye 5", COrgan), ("robot brain", COrgan) ]   } heavyRobot = ItemKind   { isymbol  = 'r'   , iname    = "construction robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)+  , ifreq    = [ ("robot", 100), ("mobile", 100), ("mobile robot", 100)                , ("construction robot", 100) ]   , iflavour = zipPlain [BrRed]   , icount   = 1-  , irarity  = [(6, 0), (10, 10)]+  , irarity  = [(8, 0), (10, 10)]   , iverbHit = "thud"   , iweight  = 800000-  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.singleton AbProject 2 ]+  , idamage  = toDmg 0+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 20, AddNocto 2+               , AddAbility AbProject 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Heavy multi-purpose construction robot. Excels at discharging, dismantling and demolition."@@ -662,15 +750,15 @@                  -- unique, appears at 10 of 12   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ Unique, AddMaxHP 120, AddMaxCalm 60, AddSpeed 18-               , AddSkills $ EM.singleton AbTrigger (-1) ]-                   -- can't switch levels, a miniboss-  , ieffects = []+  , idamage  = toDmg 0+  , iaspects = [AddMaxHP 120, AddMaxCalm 60, AddSpeed 18, AddNocto 2]+                 -- can't exit the gated level, a miniboss+  , ieffects = [Unique]   , ifeature = [Durable, Identified]   , idesc    = "A waste disposal robot repaired with parts from a heavy construction robot, including a scaled up goal matrix. The cosmic void is now the only acceptable model of cleanliness."   , ikit     = [ ("waste container", COrgan), ("boiling vent", COrgan)                , ("armored skin", COrgan), ("live wire", COrgan)-               , ("jaw", COrgan), ("claw", COrgan)+               , ("jaw", COrgan), ("hooked claw", COrgan)                , ("eye 2", COrgan), ("nostril", COrgan), ("spotlight", COrgan)                , ("currency", CInv), ("currency", CInv), ("currency", CInv)                , ("robot brain", COrgan) ]
GameDefinition/Content/ItemKindBlast.hs view
@@ -1,24 +1,33 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Blast definitions.-module Content.ItemKindBlast ( blasts ) where+module Content.ItemKindBlast+  ( blasts+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind  blasts :: [ItemKind] blasts =-  [burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, vulnerabilityBalm, hasteSpray, slownessSpray, eyeDrop, smellyDroplet, whiskeySpray]+  [burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, glassPiece, smoke, boilingWater, glue, singleSpark, spark, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, waste, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote] -burningOil2,    burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, vulnerabilityBalm, hasteSpray, slownessSpray, eyeDrop, smellyDroplet, whiskeySpray :: ItemKind+burningOil2,    burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, glassPiece, smoke, boilingWater, glue, singleSpark, spark, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, waste, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote :: ItemKind +-- We take care (e.g., in burningOil below) that blasts are not faster+-- than 100% fastest natural speed, or some frames would be skipped,+-- which is a waste of prefectly good frames.+ -- * Parameterized immediate effect blasts  burningOil :: Int -> ItemKind@@ -27,35 +36,38 @@   , iname    = "burning oil"   , ifreq    = [(toGroupName $ "burning oil" <+> tshow n, 1)]   , iflavour = zipFancy [BrYellow]-  , icount   = intToDice (n * 5)+  , icount   = intToDice (n * 8)   , irarity  = [(1, 1)]-  , iverbHit = "burn"+  , iverbHit = "sear"   , iweight  = 1-  , iaspects = [AddLight 2]-  , ieffects = [Burn 1, Paralyze 1]  -- tripping on oil-  , ifeature = [ toVelocity (min 100 $ n * 7)+  , idamage  = toDmg 0+  , iaspects = [AddShine 2]+  , ieffects = [Burn 1, Paralyze 2]  -- tripping on oil+  , ifeature = [ toVelocity (min 100 $ n `div` 2 * 10)                , Fragile, Identified ]   , idesc    = "Sticky oil, burning brightly."   , ikit     = []   }-burningOil2 = burningOil 2-burningOil3 = burningOil 3-burningOil4 = burningOil 4+burningOil2 = burningOil 2  -- 2 steps, 2 turns+burningOil3 = burningOil 3  -- 3 steps, 2 turns+burningOil4 = burningOil 4  -- 4 steps, 2 turns explosionBlast :: Int -> ItemKind explosionBlast n = ItemKind   { isymbol  = '*'   , iname    = "blast"   , ifreq    = [(toGroupName $ "blast" <+> tshow n, 1)]   , iflavour = zipPlain [BrRed]-  , icount   = 15  -- strong, but few, so not always hits target+  , icount   = 16  -- strong and wide, but few, so not always hits target   , irarity  = [(1, 1)]   , iverbHit = "tear apart"   , iweight  = 1-  , iaspects = [AddLight $ intToDice n]+  , idamage  = toDmg 0+  , iaspects = [AddShine $ intToDice $ min 10 n]   , ieffects = [RefillHP (- n `div` 2)]-               ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)]-               ++ [DropItem COrgan "temporary conditions" True | n >= 10]-  , ifeature = [Fragile, toLinger 20, Identified]+               ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)| n >= 10]+               ++ [DropItem 1 maxBound COrgan "temporary condition" | n >= 10]+               ++ [DropItem 1 maxBound COrgan "impressed" | n >= 10]  -- shock+  , ifeature = [toLinger 20, Fragile, Identified]  -- 4 steps, 1 turn   , idesc    = ""   , ikit     = []   }@@ -72,13 +84,14 @@   , irarity  = [(1, 1)]   , iverbHit = "crack"   , iweight  = 1-  , iaspects = [AddLight $ intToDice $ n `div` 2]+  , idamage  = toDmg 0+  , iaspects = [AddShine $ intToDice $ n `div` 2]   , ieffects = [ RefillCalm (-1) | n >= 5 ]                ++ [ DropBestWeapon | n >= 5]                ++ [ OnSmash (Explode $ toGroupName                              $ "firecracker" <+> tshow (n - 1))                   | n > 2 ]-  , ifeature = [ ToThrow $ ThrowMod (10 + 3 * n) (10 + 100 `div` n)+  , ifeature = [ ToThrow $ ThrowMod (5 + 3 * n) (10 + 100 `div` n)                , Fragile, Identified ]   , idesc    = ""   , ikit     = []@@ -93,89 +106,89 @@ -- * Assorted immediate effect blasts  fragrance = ItemKind-  { isymbol  = '\''-  , iname    = "fragrance"+  { isymbol  = '`'+  , iname    = "fragrance"  -- instant, fast fragrance   , ifreq    = [("fragrance", 1)]   , iflavour = zipFancy [Magenta]-  , icount   = 20+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "engulf"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [Impress]   -- Linger 10, because sometimes it takes 2 turns due to starting just   -- before actor turn's end (e.g., via a necklace).-  , ifeature = [ ToThrow $ ThrowMod 28 10  -- 2 steps, one turn-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]  -- 2 steps, 1 turn   , idesc    = ""   , ikit     = []   } pheromone = ItemKind-  { isymbol  = '\''-  , iname    = "musky whiff"+  { isymbol  = '`'+  , iname    = "musky whiff"  -- a kind of mist rather than fragrance   , ifreq    = [("pheromone", 1)]   , iflavour = zipFancy [BrMagenta]-  , icount   = 18+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "tempt"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [Impress, OverfillCalm (-20)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ieffects = [Impress, RefillCalm (-10)]+  , ifeature = [toVelocity 10, Fragile, Identified]  -- 2 steps, 2 turns   , idesc    = ""   , ikit     = []   }-mistCalming = ItemKind-  { isymbol  = '\''+mistCalming = ItemKind  -- unused+  { isymbol  = '`'   , iname    = "mist"   , ifreq    = [("calming mist", 1)]   , iflavour = zipFancy [White]-  , icount   = 19+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "sooth"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [RefillCalm 2]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   } odorDistressing = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "distressing whiff"   , ifreq    = [("distressing odor", 1)]   , iflavour = zipFancy [BrRed]-  , icount   = 10+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "distress"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [OverfillCalm (-20)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ieffects = [RefillCalm (-20)]+  , ifeature = [toLinger 10, Fragile, Identified]  -- 2 steps, 1 turn   , idesc    = ""   , ikit     = []   } mistHealing = ItemKind-  { isymbol  = '\''-  , iname    = "mist"+  { isymbol  = '`'+  , iname    = "mist"  -- powerful, so slow and narrow   , ifreq    = [("healing mist", 1)]   , iflavour = zipFancy [White]-  , icount   = 9+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "revitalize"   , iweight  = 1-  , iaspects = [AddLight 1]+  , idamage  = toDmg 0+  , iaspects = [AddShine 1]   , ieffects = [RefillHP 2]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   } mistHealing2 = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "mist"   , ifreq    = [("healing mist 2", 1)]   , iflavour = zipFancy [White]@@ -183,26 +196,26 @@   , irarity  = [(1, 1)]   , iverbHit = "revitalize"   , iweight  = 1-  , iaspects = [AddLight 2]+  , idamage  = toDmg 0+  , iaspects = [AddShine 2]   , ieffects = [RefillHP 4]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   } mistWounding = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "mist"   , ifreq    = [("wounding mist", 1)]   , iflavour = zipFancy [White]-  , icount   = 7+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "devitalize"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [RefillHP (-2)]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   }@@ -211,30 +224,14 @@   , iname    = "vortex"   , ifreq    = [("distortion", 1)]   , iflavour = zipFancy [White]-  , icount   = 6+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "engulf"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [Teleport $ 15 + d 10]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]-  , idesc    = ""-  , ikit     = []-  }-waste = ItemKind-  { isymbol  = '*'-  , iname    = "waste"-  , ifreq    = [("waste", 1)]-  , iflavour = zipPlain [Brown]-  , icount   = 18-  , irarity  = [(1, 1)]-  , iverbHit = "splosh"-  , iweight  = 50-  , iaspects = []-  , ieffects = [RefillHP (-1)]-  , ifeature = [ ToThrow $ ThrowMod 28 10  -- 2 steps, one turn-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]  -- 2 steps, 1 turn   , idesc    = ""   , ikit     = []   }@@ -243,28 +240,30 @@   , iname    = "glass piece"   , ifreq    = [("glass piece", 1)]   , iflavour = zipPlain [BrBlue]-  , icount   = 18+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "cut"-  , iweight  = 10+  , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [Hurt (1 * d 1)]-  , ifeature = [toLinger 20, Fragile, Identified]+  , ieffects = [RefillHP (-1)]  -- high velocity, so can't do idamage+  , ifeature = [toLinger 20, Fragile, Identified]  -- 4 steps, 1 turn   , idesc    = ""   , ikit     = []   }-smoke = ItemKind  -- when stuff burns out-  { isymbol  = '\''+smoke = ItemKind  -- when stuff burns out  -- unused+  { isymbol  = '`'   , iname    = "smoke"   , ifreq    = [("smoke", 1)]   , iflavour = zipPlain [BrBlack]-  , icount   = 19+  , icount   = 16   , irarity  = [(1, 1)]-  , iverbHit = "choke"+  , iverbHit = "choke"  -- or obscure   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = []-  , ifeature = [ toVelocity 21, Fragile, Identified ]+  , ifeature = [toVelocity 20, Fragile, Identified]  -- 4 steps, 2 turns   , idesc    = ""   , ikit     = []   }@@ -273,222 +272,360 @@   , iname    = "boiling water"   , ifreq    = [("boiling water", 1)]   , iflavour = zipPlain [BrWhite]-  , icount   = 21+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "boil"-  , iweight  = 5+  , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [Burn 1]-  , ifeature = [toVelocity 50, Fragile, Identified]+  , ifeature = [toVelocity 30, Fragile, Identified]  -- 6 steps, 2 turns   , idesc    = ""   , ikit     = []   } glue = ItemKind   { isymbol  = '*'-  , iname    = "sticky foam"+  , iname    = "hoof glue"   , ifreq    = [("glue", 1)]   , iflavour = zipPlain [BrYellow]-  , icount   = 20+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "glue"-  , iweight  = 20+  , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [Paralyze (3 + d 3)]-  , ifeature = [toVelocity 40, Fragile, Identified]+  , ieffects = [Paralyze 10]+  , ifeature = [toVelocity 20, Fragile, Identified]  -- 4 steps, 2 turns   , idesc    = ""   , ikit     = []   }-spark = ItemKind-  { isymbol  = '\''-  , iname    = "spark"-  , ifreq    = [("spark", 1)]+singleSpark = ItemKind+  { isymbol  = '`'+  , iname    = "single spark"+  , ifreq    = [("single spark", 1)]   , iflavour = zipPlain [BrYellow]-  , icount   = 17-  , irarity  = [(1, 1)]-  , iverbHit = "burn"-  , iweight  = 1-  , iaspects = [AddLight 4]-  , ieffects = [Burn 1]-  , ifeature = [Fragile, toLinger 10, Identified]-  , idesc    = ""-  , ikit     = []-  }-mistAntiSlow = ItemKind-  { isymbol  = '\''-  , iname    = "mist"-  , ifreq    = [("anti-slow mist", 1)]-  , iflavour = zipPlain [BrRed]-  , icount   = 7+  , icount   = 1   , irarity  = [(1, 1)]-  , iverbHit = "propel"+  , iverbHit = "spark"   , iweight  = 1-  , iaspects = []-  , ieffects = [DropItem COrgan "slow 10" True]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , idamage  = toDmg 0+  , iaspects = [AddShine 4]+  , ieffects = []+  , ifeature = [toLinger 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   }-mistAntidote = ItemKind-  { isymbol  = '\''-  , iname    = "mist"-  , ifreq    = [("antidote mist", 1)]-  , iflavour = zipPlain [BrBlue]-  , icount   = 8+spark = ItemKind+  { isymbol  = '`'+  , iname    = "spark"+  , ifreq    = [("spark", 1)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 16   , irarity  = [(1, 1)]-  , iverbHit = "cure"+  , iverbHit = "scorch"   , iweight  = 1-  , iaspects = []-  , ieffects = [DropItem COrgan "poisoned" True]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , idamage  = toDmg 0+  , iaspects = [AddShine 4]+  , ieffects = [Burn 1]+  , ifeature = [toLinger 10, Fragile, Identified]  -- 2 steps, 1 turn   , idesc    = ""   , ikit     = []   } --- * Assorted temporary condition blasts+-- * Temporary condition blasts strictly matching the aspects -mistStrength = ItemKind-  { isymbol  = '\''-  , iname    = "mist"-  , ifreq    = [("strength mist", 1)]+-- Almost all have @toLinger 10@, that travels 2 steps in 1 turn.+-- These are very fast projectiles, not getting into the way of big+-- actors and not burdening the engine for long.++denseShower = ItemKind+  { isymbol  = '`'+  , iname    = "dense shower"+  , ifreq    = [("dense shower", 1)]   , iflavour = zipFancy [Red]-  , icount   = 6+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "strengthen"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganActorTurn "strengthened" (3 + d 3)]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }-mistWeakness = ItemKind-  { isymbol  = '\''-  , iname    = "mist"-  , ifreq    = [("weakness mist", 1)]+sparseShower = ItemKind+  { isymbol  = '`'+  , iname    = "sparse shower"+  , ifreq    = [("sparse shower", 1)]   , iflavour = zipFancy [Blue]-  , icount   = 5+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "weaken"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganGameTurn "weakened" (3 + d 3)]-  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }-protectingBalm = ItemKind-  { isymbol  = '\''+protectingBalmMelee = ItemKind+  { isymbol  = '`'   , iname    = "balm droplet"-  , ifreq    = [("protecting balm", 1)]+  , ifreq    = [("melee protective balm", 1)]   , iflavour = zipPlain [Brown]-  , icount   = 13+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "balm"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [toOrganActorTurn "protected" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ieffects = [toOrganActorTurn "protected from melee" (3 + d 3)]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }+protectingBalmRanged = ItemKind+  { isymbol  = '`'+  , iname    = "balm droplet"+  , ifreq    = [("ranged protective balm", 1)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "balm"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganActorTurn "protected from ranged" (3 + d 3)]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  } vulnerabilityBalm = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "red paint"   , ifreq    = [("red paint", 1)]   , iflavour = zipPlain [BrRed]-  , icount   = 14+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "paint"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganGameTurn "painted red" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }+resolutionDust = ItemKind+  { isymbol  = '`'+  , iname    = "resolution dust"+  , ifreq    = [("resolution dust", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "calm"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganActorTurn "resolute" (3 + d 3)]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  } hasteSpray = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "haste spray"   , ifreq    = [("haste spray", 1)]   , iflavour = zipPlain [BrRed]-  , icount   = 15+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "haste"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [toOrganActorTurn "fast 20" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ieffects = [toOrganActorTurn "hasted" (3 + d 3)]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }-slownessSpray = ItemKind-  { isymbol  = '\''-  , iname    = "slowness spray"-  , ifreq    = [("slowness spray", 1)]+slownessMist = ItemKind+  { isymbol  = '`'+  , iname    = "slowness mist"+  , ifreq    = [("slowness mist", 1)]   , iflavour = zipPlain [BrBlue]-  , icount   = 16+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "slow"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []-  , ieffects = [toOrganGameTurn "slow 10" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ieffects = [toOrganGameTurn "slowed" (3 + d 3)]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn, mist   , idesc    = ""   , ikit     = []   } eyeDrop = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "eye drop"   , ifreq    = [("eye drop", 1)]   , iflavour = zipPlain [BrGreen]-  , icount   = 17+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "cleanse"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganActorTurn "far-sighted" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }+ironFiling = ItemKind+  { isymbol  = '`'+  , iname    = "iron filing"+  , ifreq    = [("iron filing", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "blind"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganActorTurn "blind" (10 + d 10)]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  } smellyDroplet = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "smelly droplet"   , ifreq    = [("smelly droplet", 1)]   , iflavour = zipPlain [Blue]-  , icount   = 18+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "sensitize"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganActorTurn "keen-smelling" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]   , idesc    = ""   , ikit     = []   }+eyeShine = ItemKind+  { isymbol  = '`'+  , iname    = "eye shine"+  , ifreq    = [("eye shine", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "smear"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganActorTurn "shiny-eyed" (3 + d 3)]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }++-- * Assorted temporary condition blasts or related (also, matching flasks)+ whiskeySpray = ItemKind-  { isymbol  = '\''+  { isymbol  = '`'   , iname    = "whiskey spray"   , ifreq    = [("whiskey spray", 1)]   , iflavour = zipPlain [Brown]-  , icount   = 19+  , icount   = 16   , irarity  = [(1, 1)]   , iverbHit = "inebriate"   , iweight  = 1+  , idamage  = toDmg 0   , iaspects = []   , ieffects = [toOrganActorTurn "drunk" (3 + d 3)]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps-               , Fragile, Identified ]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }+waste = ItemKind+  { isymbol  = '*'+  , iname    = "waste"+  , ifreq    = [("waste", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "splosh"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Burn (-1)]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }+youthSprinkle = ItemKind+  { isymbol  = '`'+  , iname    = "youth sprinkle"+  , ifreq    = [("youth sprinkle", 1)]+  , iflavour = zipPlain [BrGreen]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "sprinkle"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganNone "regenerating"]+  , ifeature = [toLinger 10, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }+poisonCloud = ItemKind+  { isymbol  = '`'+  , iname    = "poison cloud"+  , ifreq    = [("poison cloud", 1)]+  , iflavour = zipPlain [Green]+  , icount   = 16+  , irarity  = [(1, 1)]+  , iverbHit = "poison"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [toOrganNone "poisoned"]+  , ifeature = [toVelocity 10, Fragile, Identified]  -- 2 steps, 2 turns+  , idesc    = ""+  , ikit     = []+  }+mistAntiSlow = ItemKind+  { isymbol  = '`'+  , iname    = "mist"+  , ifreq    = [("anti-slow mist", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 8+  , irarity  = [(1, 1)]+  , iverbHit = "propel"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [DropItem 1 1 COrgan "slowed"]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn+  , idesc    = ""+  , ikit     = []+  }+mistAntidote = ItemKind+  { isymbol  = '`'+  , iname    = "mist"+  , ifreq    = [("antidote mist", 1)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 8+  , irarity  = [(1, 1)]+  , iverbHit = "cure"+  , iweight  = 1+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [DropItem 1 maxBound COrgan "poisoned"]+  , ifeature = [toVelocity 5, Fragile, Identified]  -- 1 step, 1 turn   , idesc    = ""   , ikit     = []   }
+ GameDefinition/Content/ItemKindEmbed.hs view
@@ -0,0 +1,281 @@+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+-- | Definitions of items embedded in map tiles.+module Content.ItemKindEmbed+  ( embeds+  ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.ItemKind++embeds :: [ItemKind]+embeds =+  [stairsUp, stairsDown, escape, terrainCache, terrainCacheTrap, signboardExit, signboardMap, fireSmall, fireBig, frost, rubble, staircaseTrapUp, staircaseTrapDown, doorwayTrap, obscenePictograms, subtleFresco, scratchOnWall, pulpit]++stairsUp,    stairsDown, escape, terrainCache, terrainCacheTrap, signboardExit, signboardMap, fireSmall, fireBig, frost, rubble, staircaseTrapUp, staircaseTrapDown, doorwayTrap, obscenePictograms, subtleFresco, scratchOnWall, pulpit :: ItemKind++stairsUp = ItemKind+  { isymbol  = '<'+  , iname    = "staircase up"+  , ifreq    = [("staircase up", 1)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "crash"+  , iweight  = 100000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Ascend True]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+stairsDown = stairsUp+  { isymbol  = '>'+  , iname    = "staircase down"+  , ifreq    = [("staircase down", 1)]+  , ieffects = [Ascend False]+  }+escape = stairsUp+  { iname    = "escape"+  , ifreq    = [("escape", 1)]+  , iflavour = zipPlain [BrYellow]+  , ieffects = [Escape]+  }+terrainCache = stairsUp+  { isymbol  = 'O'+  , iname    = "treasure cache"+  , ifreq    = [("terrain cache", 1)]+  , iflavour = zipPlain [BrYellow]+  , ieffects = [CreateItem CGround "useful" TimerNone]+  }+terrainCacheTrap = ItemKind+  { isymbol  = '^'+  , iname    = "treasure cache trap"+  , ifreq    = [("terrain cache trap", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "trap"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [OneOf [ toOrganNone "poisoned", Explode "glue"+                      , ELabel "", ELabel "", ELabel ""+                      , ELabel "", ELabel "", ELabel ""+                      , ELabel "", ELabel "" ]]+  , ifeature = [Identified]  -- not Durable, springs at most once+  , idesc    = ""+  , ikit     = []+  }+signboardExit = ItemKind+  { isymbol  = 'O'+  , iname    = "signboard with exits"+  , ifreq    = [("signboard", 80)]+  , iflavour = zipPlain [BrMagenta]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "whack"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [DetectExit 100]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+signboardMap = signboardExit+  { iname    = "signboard with map"+  , ifreq    = [("signboard", 20)]+  , ieffects = [Detect 10]+  }+fireSmall = ItemKind+  { isymbol  = '&'+  , iname    = "small fire"+  , ifreq    = [("small fire", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "burn"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Burn 1, Explode "single spark"]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+fireBig = fireSmall+  { isymbol  = 'O'+  , iname    = "big fire"+  , ifreq    = [("big fire", 1)]+  , ieffects = [ Burn 2, Explode "spark"+               , CreateItem CGround "wooden torch" TimerNone ]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+frost = ItemKind+  { isymbol  = '%'+  , iname    = "frost"+  , ifreq    = [("frost", 1)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "burn"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [ Burn 1  -- sensory ambiguity between hot and cold+               , RefillCalm 20  -- cold reason+               , PushActor (ThrowMod 200 50) ]  -- slippery ice+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+rubble = ItemKind+  { isymbol  = ':'+  , iname    = "rubble"+  , ifreq    = [("rubble", 1)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "bury"+  , iweight  = 100000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [OneOf [ Explode "glass piece", Explode "waste"+                      , Summon "animal" 1, toOrganNone "poisoned"+                      , CreateItem CGround "useful" TimerNone+                      , ELabel "", ELabel "", ELabel ""+                      , ELabel "", ELabel "", ELabel "" ]]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+staircaseTrapUp = ItemKind+  { isymbol  = '^'+  , iname    = "staircase trap"+  , ifreq    = [("staircase trap up", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "taint"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Temporary "be caught in an updraft", Teleport 20]+  , ifeature = [Identified]  -- not Durable, springs at most once+  , idesc    = ""+  , ikit     = []+  }+-- Needs to be separate from staircaseTrapUp, to make sure the item is+-- registered after up staircase (not only after down staircase)+-- so that effects are invoked in the proper order and, e.g., teleport works.+staircaseTrapDown = staircaseTrapUp+  { ifreq    = [("staircase trap down", 1)]+  , ieffects = [ Temporary "tumble down the stairwell"+               , toOrganActorTurn "drunk" (20 + d 5) ]+  }+doorwayTrap = ItemKind+  { isymbol  = '^'+  , iname    = "doorway trap"+  , ifreq    = [("doorway trap", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "trap"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [OneOf [ RefillCalm (-20)+                      , toOrganActorTurn "slowed" (20 + d 5)+                      , toOrganActorTurn "weakened" (20 + d 5) ]]+  , ifeature = [Identified]  -- not Durable, springs at most once+  , idesc    = ""+  , ikit     = []+  }+obscenePictograms = ItemKind+  { isymbol  = '*'+  , iname    = "repulsing graffiti"+  , ifreq    = [("obscene pictograms", 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "infuriate"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = [Timeout 7]+  , ieffects = [ Temporary "enter unexplainable rage at a glimpse of the inscrutable graffiti"+               , RefillCalm (-20)+               , Recharging $ OneOf+                   [ toOrganActorTurn "strengthened" (3 + d 3)+                   , CreateItem CInv "sandstone rock" TimerNone ] ]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+subtleFresco = ItemKind+  { isymbol  = '*'+  , iname    = "subtle mural"+  , ifreq    = [("subtle fresco", 1)]+  , iflavour = zipPlain [BrGreen]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = ""+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = [Timeout 7]+  , ieffects = [ Temporary "be entranced by the subtle mural"+               , RefillCalm 2+               , Recharging $ toOrganActorTurn "far-sighted" (3 + d 3)+               , Recharging $ toOrganActorTurn "keen-smelling" (3 + d 3) ]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+scratchOnWall = ItemKind+  { isymbol  = '*'+  , iname    = "scratch on wall"+  , ifreq    = [("scratch on wall", 1)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "scratch"+  , iweight  = 1000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [Temporary "start making sense of the scratches", DetectHidden 3]+  , ifeature = [Identified, Durable]+  , idesc    = ""+  , ikit     = []+  }+pulpit = ItemKind+  { isymbol  = 'O'+  , iname    = "VR harness"+  , ifreq    = [("pulpit", 1)]+  , iflavour = zipFancy [BrBlue]+  , icount   = 1+  , irarity  = [(1, 1)]+  , iverbHit = "ask"+  , iweight  = 10000+  , idamage  = toDmg 0+  , iaspects = []+  , ieffects = [ CreateItem CGround "any scroll" TimerNone+               , Detect 20+               , Paralyze 20+               , toOrganActorTurn "drunk" (20 + d 5) ]+  , ifeature = [Identified]  -- not Durable, springs at most once+  , idesc    = ""+  , ikit     = []+  }
GameDefinition/Content/ItemKindOrgan.hs view
@@ -1,26 +1,33 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Organ definitions.-module Content.ItemKindOrgan ( organs ) where+module Content.ItemKindOrgan+  ( organs+  ) where -import qualified Data.EnumMap.Strict as EM+import Prelude () +import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind  organs :: [ItemKind] organs =-  [fist, foot, claw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, razor, thorn, boilingFissure, biogasFissure, medbotFissure, insectMortality, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision6, vision8, vision10, vision12, vision14, vision16, nostril, sapientBrain, animalBrain, robotBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, biogasVent, medbotVent, wasteContainer, spotlight, bonusHP]+  [fist, foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP]+  -- Allure-specific+  ++ [razor, liveWire, robotBrain, wasteContainer, spotlight] -fist,    foot, claw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, razor, thorn, boilingFissure, biogasFissure, medbotFissure, insectMortality, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision6, vision8, vision10, vision12, vision14, vision16, nostril, sapientBrain, animalBrain, robotBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, biogasVent, medbotVent, wasteContainer, spotlight, bonusHP :: ItemKind+fist,    foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP :: ItemKind+-- Allure-specific+razor, liveWire, robotBrain, wasteContainer, spotlight :: ItemKind  -- Weapons @@ -35,45 +42,46 @@   , irarity  = [(1, 1)]   , iverbHit = "punch"   , iweight  = 2000+  , idamage  = toDmg $ 4 * d 1   , iaspects = []-  , ieffects = [Hurt (4 * d 1)]-  , ifeature = [Durable, Identified]+  , ieffects = []+  , ifeature = [Durable, Identified, Meleeable]   , idesc    = ""   , ikit     = []   } foot = fist   { iname    = "foot"   , ifreq    = [("foot", 50)]-  , icount   = 2   , iverbHit = "kick"-  , ieffects = [Hurt (4 * d 1)]+  , idamage  = toDmg $ 4 * d 1   , idesc    = ""   }  -- * Universal weapon organs -claw = fist-  { iname    = "claw"-  , ifreq    = [("claw", 50)]+hookedClaw = fist+  { iname    = "hooked claw"+  , ifreq    = [("hooked claw", 50)]   , icount   = 2  -- even if more, only the fore claws used for fighting   , iverbHit = "hook"+  , idamage  = toDmg $ 2 * d 1   , iaspects = [Timeout $ 4 + d 4]-  , ieffects = [Hurt (2 * d 1), Recharging (toOrganGameTurn "slow 10" 2)]+  , ieffects = [Recharging (toOrganGameTurn "slowed" 2)]   , idesc    = ""   } smallClaw = fist   { iname    = "small claw"   , ifreq    = [("small claw", 50)]-  , icount   = 2   , iverbHit = "slash"-  , ieffects = [Hurt (2 * d 1)]+  , idamage  = toDmg $ 2 * d 1   , idesc    = ""   } snout = fist   { iname    = "snout"   , ifreq    = [("snout", 10)]+  , icount   = 1   , iverbHit = "bite"-  , ieffects = [Hurt (2 * d 1)]+  , idamage  = toDmg $ 2 * d 1   , idesc    = ""   } smallJaw = fist@@ -81,7 +89,7 @@   , ifreq    = [("small jaw", 20)]   , icount   = 1   , iverbHit = "rip"-  , ieffects = [Hurt (3 * d 1)]+  , idamage  = toDmg $ 3 * d 1   , idesc    = ""   } jaw = fist@@ -89,7 +97,7 @@   , ifreq    = [("jaw", 20)]   , icount   = 1   , iverbHit = "rip"-  , ieffects = [Hurt (5 * d 1)]+  , idamage  = toDmg $ 5 * d 1   , idesc    = ""   } largeJaw = fist@@ -97,7 +105,7 @@   , ifreq    = [("large jaw", 100)]   , icount   = 1   , iverbHit = "crush"-  , ieffects = [Hurt (12 * d 1)]+  , idamage  = toDmg $ 10 * d 1   , idesc    = ""   } horn = fist@@ -105,29 +113,19 @@   , ifreq    = [("horn", 20)]   , icount   = 2   , iverbHit = "impale"-  , ieffects = [Hurt (8 * d 1)]+  , idamage  = toDmg $ 6 * d 1+  , iaspects = [AddHurtMelee 20]   , idesc    = ""   } --- * Monster weapon organs+-- * Special weapon organs  tentacle = fist   { iname    = "tentacle"   , ifreq    = [("tentacle", 50)]   , icount   = 4   , iverbHit = "slap"-  , ieffects = [Hurt (4 * d 1)]-  , idesc    = ""-  }---- * Special weapon organs--razor = fist-  { iname    = "razor"-  , ifreq    = [("razor", 100)]-  , icount   = 7-  , iverbHit = "slice"-  , ieffects = [Hurt (2 * d 1)]+  , idamage  = toDmg $ 4 * d 1   , idesc    = ""   } thorn = fist@@ -135,8 +133,9 @@   , ifreq    = [("thorn", 100)]   , icount   = 2 + d 3   , iverbHit = "impale"-  , ieffects = [Hurt (2 * d 1)]-  , ifeature = [Identified]  -- not Durable+  , idamage  = toDmg $ 1 * d 1+  , ieffects = [RefillHP (-2)]+  , ifeature = [Identified, Meleeable]  -- not Durable   , idesc    = ""   } boilingFissure = fist@@ -144,30 +143,34 @@   , ifreq    = [("boiling fissure", 100)]   , icount   = 5 + d 5   , iverbHit = "hiss at"-  , ieffects = [Burn $ 1 * d 1]-  , ifeature = [Identified]  -- not Durable+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddHurtMelee 20]+  , ieffects = [InsertMove $ 1 * d 3]+  , ifeature = [Identified, Meleeable]  -- not Durable   , idesc    = ""   }-biogasFissure = boilingFissure+arsenicFissure = boilingFissure   { iname    = "fissure"   , ifreq    = [("biogas fissure", 100)]-  , icount   = 2 + d 2-  , ieffects = [Burn $ 1 * d 1, toOrganGameTurn "weakened" (2 + d 2)]+  , icount   = 3 + d 3+  , idamage  = toDmg $ 2 * d 1+  , ieffects = [toOrganGameTurn "weakened" (2 + d 2)]   }-medbotFissure = boilingFissure+sulfurFissure = boilingFissure   { iname    = "fissure"   , ifreq    = [("medbot fissure", 100)]   , icount   = 2 + d 2-  , ieffects = [Burn $ 1 * d 1, RefillHP 6]+  , ieffects = [RefillHP 6]   } beeSting = fist   { iname    = "bee sting"   , ifreq    = [("bee sting", 100)]   , icount   = 1   , iverbHit = "sting"-  , iaspects = [AddArmorMelee 90, AddArmorRanged 90]-  , ieffects = [Burn $ 2 * d 1, Paralyze 3, RefillHP 5]-  , ifeature = [Identified]  -- not Durable+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [AddArmorMelee 90, AddArmorRanged 45]+  , ieffects = [Paralyze 6, RefillHP 5]+  , ifeature = [Identified, Meleeable]  -- not Durable   , idesc    = "Painful, but beneficial."   } sting = fist@@ -175,8 +178,9 @@   , ifreq    = [("sting", 100)]   , icount   = 1   , iverbHit = "sting"-  , iaspects = [Timeout $ 1 + d 5]-  , ieffects = [Burn $ 2 * d 1, Recharging (Paralyze 2)]+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [Timeout $ 1 + d 5, AddHurtMelee 40]+  , ieffects = [Recharging (Paralyze 4)]   , idesc    = "Painful, debilitating and harmful."   } venomTooth = fist@@ -184,31 +188,29 @@   , ifreq    = [("venom tooth", 100)]   , icount   = 2   , iverbHit = "bite"+  , idamage  = toDmg $ 2 * d 1   , iaspects = [Timeout $ 5 + d 3]-  , ieffects = [ Hurt (2 * d 1)-               , Recharging (toOrganGameTurn "slow 10" (3 + d 3)) ]+  , ieffects = [Recharging (toOrganGameTurn "slowed" (3 + d 3))]   , idesc    = ""   }--- TODO: should also confer poison resistance, but current implementation--- is too costly (poison removal each turn) venomFang = fist   { iname    = "venom fang"   , ifreq    = [("venom fang", 100)]   , icount   = 2   , iverbHit = "bite"+  , idamage  = toDmg $ 2 * d 1   , iaspects = [Timeout $ 7 + d 5]-  , ieffects = [ Hurt (2 * d 1)-               , Recharging (toOrganNone "poisoned") ]+  , ieffects = [Recharging (toOrganNone "poisoned")]   , idesc    = ""   }-screechingBeak = armoredSkin+screechingBeak = fist   { iname    = "screeching beak"   , ifreq    = [("screeching beak", 100)]   , icount   = 1   , iverbHit = "peck"+  , idamage  = toDmg $ 2 * d 1   , iaspects = [Timeout $ 5 + d 5]-  , ieffects = [ Recharging (Summon [("scavenger", 1)] $ 1 + dl 2)-               , Hurt (2 * d 1) ]+  , ieffects = [Recharging $ Summon "scavenger" $ 1 + dl 2]   , idesc    = ""   } largeTail = fist@@ -216,20 +218,9 @@   , ifreq    = [("large tail", 50)]   , icount   = 1   , iverbHit = "knock"-  , iaspects = [Timeout $ 1 + d 3]-  , ieffects = [Hurt (8 * d 1), Recharging (PushActor (ThrowMod 400 25))]-  , idesc    = ""-  }-liveWire = fist-  { iname    = "live wire"-  , ifreq    = [("live wire", 100)]-  , icount   = 1-  , iverbHit = "shock"-  , iaspects = [Timeout $ 3 + d 3]-  , ieffects = [ Hurt (1 * d 1)-               , Recharging (DropItem COrgan "temporary conditions" True)-               , Recharging $ RefillHP (-2)-               ]+  , idamage  = toDmg $ 6 * d 1+  , iaspects = [Timeout $ 1 + d 3, AddHurtMelee 20]+  , ieffects = [Recharging (PushActor (ThrowMod 400 25))]   , idesc    = ""   } @@ -246,7 +237,8 @@   , irarity  = [(1, 1)]   , iverbHit = "bash"   , iweight  = 2000-  , iaspects = [AddArmorMelee 30, AddArmorRanged 30]+  , idamage  = toDmg 0+  , iaspects = [AddArmorMelee 30, AddArmorRanged 15]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""@@ -275,13 +267,14 @@ vision n = armoredSkin   { iname    = "vision"   , ifreq    = [(toGroupName $ "vision" <+> tshow n, 100)]-  , icount   = 1   , iverbHit = "visualize"   , iaspects = [AddSight (intToDice n)]   , idesc    = ""   } vision4 = vision 4+vision5 = vision 5 vision6 = vision 6+vision7 = vision 7 vision8 = vision 8 vision10 = vision 10 vision12 = vision 12@@ -298,53 +291,40 @@  -- * Assorted -insectMortality = fist+insectMortality = armoredSkin   { iname    = "insect mortality"   , ifreq    = [("insect mortality", 100)]-  , icount   = 1   , iverbHit = "age"-  , iaspects = [Periodic, Timeout $ 40 + d 10]-  , ieffects = [Recharging (RefillHP (-1))]+  , iaspects = [Timeout $ 40 + d 10]+  , ieffects = [Periodic, Recharging (RefillHP (-1))]   , idesc    = ""   } sapientBrain = armoredSkin   { iname    = "sapient brain"   , ifreq    = [("sapient brain", 100)]-  , icount   = 1   , iverbHit = "outbrain"-  , iaspects = [AddSkills unitSkills]+  , iaspects = [AddAbility ab 1 | ab <- [minBound..maxBound]]+               ++ [AddAbility AbAlter 2]  -- can use stairs   , idesc    = ""   } animalBrain = armoredSkin   { iname    = "animal brain"   , ifreq    = [("animal brain", 100)]-  , icount   = 1   , iverbHit = "blank"-  , iaspects = [let absNo = [AbDisplace, AbMoveItem, AbProject, AbApply]-                    sk = EM.fromList $ zip absNo [-1, -1..]-                in AddSkills $ addSkills unitSkills sk]-  , idesc    = ""-  }-robotBrain = armoredSkin-  { iname    = "robot brain"-  , ifreq    = [("robot brain", 100)]-  , icount   = 1-  , iverbHit = "outcompute"-  , iaspects = [let absNo = [AbApply]-                    sk = EM.fromList $ zip absNo [-1, -1..]-                in AddSkills $ addSkills unitSkills sk]+  , iaspects = [AddAbility ab 1 | ab <- [minBound..maxBound]]+               ++ [AddAbility AbAlter 2]  -- can use stairs+               ++ [ AddAbility ab (-1)+                  | ab <- [AbDisplace, AbMoveItem, AbProject, AbApply] ]   , idesc    = ""   } speedGland :: Int -> ItemKind speedGland n = armoredSkin   { iname    = "speed gland"   , ifreq    = [(toGroupName $ "speed gland" <+> tshow n, 100)]-  , icount   = 1   , iverbHit = "spit at"   , iaspects = [ AddSpeed $ intToDice n-               , Periodic                , Timeout $ intToDice $ 100 `div` n ]-  , ieffects = [Recharging (RefillHP 1)]+  , ieffects = [Periodic, Recharging (RefillHP 1)]   , idesc    = ""   } speedGland2 = speedGland 2@@ -352,13 +332,12 @@ speedGland6 = speedGland 6 speedGland8 = speedGland 8 speedGland10 = speedGland 10-scentGland = armoredSkin  -- TODO: cone attack, 3m away, project? apply?+scentGland = armoredSkin   { iname    = "scent gland"   , ifreq    = [("scent gland", 100)]-  , icount   = 1   , iverbHit = "spray at"-  , iaspects = [Periodic, Timeout $ 10 + d 2 |*| 5 ]-  , ieffects = [ Recharging (Explode "distressing odor")+  , iaspects = [Timeout $ 10 + d 2 |*| 5 ]+  , ieffects = [ Periodic, Recharging (Explode "distressing odor")                , Recharging ApplyPerfume ]   , idesc    = ""   }@@ -366,39 +345,83 @@   { iname    = "vent"   , ifreq    = [("boiling vent", 100)]   , iflavour = zipPlain [BrBlue]-  , icount   = 1   , iverbHit = "menace"-  , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]-  , ieffects = [Recharging (Explode "boiling water")]+  , iaspects = [Timeout $ 2 + d 2 |*| 5]+  , ieffects = [Periodic+               , Recharging (Explode "boiling water")+               , Recharging (RefillHP 2) ]   , idesc    = ""   }-biogasVent = armoredSkin+arsenicVent = armoredSkin   { iname    = "vent"   , ifreq    = [("biogas vent", 100)]   , iflavour = zipPlain [BrGreen]-  , icount   = 1   , iverbHit = "menace"-  , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]-  , ieffects = [Recharging (Explode "weakness mist")]+  , iaspects = [Timeout $ 2 + d 2 |*| 5]+  , ieffects = [ Periodic+               , Recharging (Explode "sparse shower")+               , Recharging (RefillHP 2) ]   , idesc    = ""   }-medbotVent = armoredSkin+sulfurVent = armoredSkin   { iname    = "vent"   , ifreq    = [("medbot vent", 100)]   , iflavour = zipPlain [BrYellow]-  , icount   = 1   , iverbHit = "menace"-  , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]-  , ieffects = [Recharging (Explode "protecting balm")]+  , iaspects = [Timeout $ 2 + d 2 |*| 5]+  , ieffects = [ Periodic+               , Recharging (Explode "dense shower")+               , Recharging (RefillHP 2) ]   , idesc    = ""   }+bonusHP = armoredSkin+  { isymbol  = '+'+  , iname    = "bonus HP"+  , iflavour = zipPlain [BrBlue]+  , ifreq    = [("bonus HP", 1)]+  , iverbHit = "intimidate"+  , iweight  = 1  -- weight 0 reserved for tmp organs+  , iaspects = [AddMaxHP 1]+  , idesc    = ""+  }++-- * Allure-specific++razor = fist+  { iname    = "razor"+  , ifreq    = [("razor", 100)]+  , icount   = 2 + d 5+  , iverbHit = "slice"+  , idamage  = toDmg $ 2 * d 1+  , idesc    = ""+  }+liveWire = fist+  { iname    = "live wire"+  , ifreq    = [("live wire", 100)]+  , icount   = 1+  , iverbHit = "shock"+  , idamage  = toDmg $ 1 * d 1+  , iaspects = [Timeout $ 3 + d 3, AddHurtMelee 20]+  , ieffects = [ Recharging (DropItem 1 maxBound COrgan "temporary condition")+               , Recharging $ RefillHP (-2)+               ]+  , idesc    = ""+  }+robotBrain = armoredSkin+  { iname    = "robot brain"+  , ifreq    = [("robot brain", 100)]+  , iverbHit = "outcompute"+  , iaspects = [AddAbility ab 1 | ab <- [minBound..maxBound]]+               ++ [AddAbility AbApply (-1)]+  , idesc    = ""+  } wasteContainer = armoredSkin   { iname    = "waste container"   , ifreq    = [("waste container", 100)]-  , icount   = 1   , iverbHit = "spill over"-  , iaspects = [Periodic, Timeout $ 5 + d 5 |*| 10]-  , ieffects = [ Recharging (Summon [("mobile animal", 1)] $ 1 + dl 2)+  , iaspects = [Timeout $ 5 + d 5 |*| 10]+  , ieffects = [ Periodic+               , Recharging (Summon "mobile animal" 1)                , Recharging (RefillHP 1)                , Recharging (Explode "waste") ]   , idesc    = ""@@ -406,17 +429,7 @@ spotlight = armoredSkin   { iname    = "spotlight"   , ifreq    = [("spotlight", 100)]-  , icount   = 1-  , iverbHit = "blind"-  , iaspects = [AddLight 3]-  , idesc    = ""-  }-bonusHP = armoredSkin-  { iname    = "bonus HP"-  , ifreq    = [("bonus HP", 100)]-  , icount   = 1-  , iverbHit = "intimidate"-  , iweight  = 0-  , iaspects = [AddMaxHP 1]+  , iverbHit = "illuminate"+  , iaspects = [AddShine 3]   , idesc    = ""   }
GameDefinition/Content/ItemKindTemporary.hs view
@@ -1,80 +1,98 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Temporary aspect pseudo-item definitions.-module Content.ItemKindTemporary ( temporaries ) where+module Content.ItemKindTemporary+  ( temporaries+  ) where -import Data.Text (Text)+import Prelude () +import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind  temporaries :: [ItemKind] temporaries =-  [tmpStrengthened, tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant]+  [tmpStrengthened, tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant, tmpImpressed] -tmpStrengthened,    tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant :: ItemKind+tmpStrengthened,    tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant, tmpImpressed :: ItemKind +tmpNoLonger :: Text -> Effect+tmpNoLonger name = Temporary $ "be no longer" <+> name+ -- The @name@ is be used in item description, so it should be an adjective -- describing the temporary set of aspects.-tmpAs :: Text -> [Aspect Dice] -> ItemKind+tmpAs :: Text -> [Aspect] -> ItemKind tmpAs name aspects = ItemKind   { isymbol  = '+'   , iname    = name-  , ifreq    = [(toGroupName name, 1), ("temporary conditions", 1)]+  , ifreq    = [(toGroupName name, 1), ("temporary condition", 1)]   , iflavour = zipPlain [BrWhite]   , icount   = 1   , irarity  = [(1, 1)]   , iverbHit = "affect"   , iweight  = 0-  , iaspects = [Periodic, Timeout 0]  -- activates and vanishes soon,-                                      -- depending on initial timer setting-               ++ aspects-  , ieffects = let tmp = Temporary $ "be no longer" <+> name-               in [Recharging tmp, OnSmash tmp]-  , ifeature = [Identified]+  , idamage  = toDmg 0+  , iaspects = -- timeout is 0; activates and vanishes soon,+               -- depending on initial timer setting+               aspects+  , ieffects = [ Periodic+               , Recharging $ tmpNoLonger name+               , OnSmash $ tmpNoLonger name ]+  , ifeature = [Identified, Fragile, Durable]  -- hack: destroy on drop   , idesc    = ""   , ikit     = []   }  tmpStrengthened = tmpAs "strengthened" [AddHurtMelee 20] tmpWeakened = tmpAs "weakened" [AddHurtMelee (-20)]-tmpProtected = tmpAs "protected" [ AddArmorMelee 30-                                 , AddArmorRanged 30 ]-tmpVulnerable = tmpAs "painted red" [ AddArmorMelee (-30)-                                    , AddArmorRanged (-30) ]-tmpFast20 = tmpAs "fast 20" [AddSpeed 20]-tmpSlow10 = tmpAs "slow 10" [AddSpeed (-10)]+tmpProtectedMelee = tmpAs "protected from melee" [AddArmorMelee 50]+tmpProtectedRanged = tmpAs "protected from ranged" [AddArmorRanged 25]+tmpVulnerable = tmpAs "painted red" [ AddArmorMelee (-50)+                                    , AddArmorRanged (-25) ]+tmpResolute = tmpAs "resolute" [AddMaxCalm 60]+tmpFast20 = tmpAs "hasted" [AddSpeed 20]+tmpSlow10 = tmpAs "slowed" [AddSpeed (-10)] tmpFarSighted = tmpAs "far-sighted" [AddSight 5]+tmpBlind = tmpAs "blind" [AddSight (-99)] tmpKeenSmelling = tmpAs "keen-smelling" [AddSmell 2]+tmpNoctovision = tmpAs "shiny-eyed" [AddNocto 2] tmpDrunk = tmpAs "drunk" [ AddHurtMelee 30  -- fury                          , AddArmorMelee (-20)                          , AddArmorRanged (-20)-                         , AddSight (-7)+                         , AddSight (-8)                          ] tmpRegenerating =   let tmp = tmpAs "regenerating" []-  in tmp { icount = 7 + d 5+  in tmp { icount = 4 + d 2          , ieffects = Recharging (RefillHP 1) : ieffects tmp          } tmpPoisoned =   let tmp = tmpAs "poisoned" []-  in tmp { icount = 7 + d 5+  in tmp { icount = 4 + d 2          , ieffects = Recharging (RefillHP (-1)) : ieffects tmp          } tmpSlow10Resistant =   let tmp = tmpAs "slow resistant" []-  in tmp { icount = 7 + d 5-         , ieffects = Recharging (DropItem COrgan "slow 10" True) : ieffects tmp+  in tmp { icount = 8 + d 4+         , ieffects = Recharging (DropItem 1 1 COrgan "slowed") : ieffects tmp          } tmpPoisonResistant =   let tmp = tmpAs "poison resistant" []-  in tmp { icount = 7 + d 5-         , ieffects = Recharging (DropItem COrgan "poisoned" True) : ieffects tmp+  in tmp { icount = 8 + d 4+         , ieffects = Recharging (DropItem 1 maxBound COrgan "poisoned")+                      : ieffects tmp+         }+tmpImpressed =+  let tmp = tmpAs "impressed" []+  in tmp { isymbol = '!'+         , ifreq = [("impressed", 1)]  -- no "temporary condition"+         , ieffects = [OnSmash $ tmpNoLonger "impressed"]  -- not @Periodic@          }
GameDefinition/Content/ModeKind.hs view
@@ -1,17 +1,22 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game mode definitions.-module Content.ModeKind ( cdefs ) where+module Content.ModeKind+  ( cdefs+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude+ import qualified Data.IntMap.Strict as IM  import Content.ModeKindPlayer import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice-import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind  cdefs :: ContentDef ModeKind@@ -21,74 +26,124 @@   , getFreq = mfreq   , validateSingle = validateSingleModeKind   , validateAll = validateAllModeKind-  , content =-      [campaign, raid, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver]+  , content = contentFromList+      [raid, brawl, shootout, escape, zoo, ambush, exploration, explorationSurvival, safari, safariSurvival, battle, battleSurvival, defense, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverExploration, screensaverSafari]   }-campaign,        raid, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver :: ModeKind+raid,        brawl, shootout, escape, zoo, ambush, exploration, explorationSurvival, safari, safariSurvival, battle, battleSurvival, defense, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverExploration, screensaverSafari :: ModeKind -campaign = ModeKind-  { msymbol = 'c'-  , mname   = "campaign"-  , mfreq   = [("campaign", 1)]-  , mroster = rosterCampaign-  , mcaves  = cavesCampaign-  , mdesc   = "You got stranded looting the blasted bridge of a once luxurious cruise liner. Your current plan is to fight through, gathering your spoils, to the shuttle airlock somewhere among the giant spaceship's uppermost decks. There are animal cries down below and ominous silence up above."-  }+-- What other symmetric (two only-one-moves factions) and asymmetric vs crowd+-- scenarios make sense (e.g., are good for a tutorial or for standalone+-- extreme fun or are impossible as part of a crawl)?+-- sparse melee at night: no, shade ambush in brawl is enough+-- dense melee: no, keeping big party together is a chore and big enemy+--   party is less fun than huge enemy party+-- crowd melee in daylight: no, possible in crawl and at night is more fun+-- sparse ranged at night: no, less fun than dense and if no reaction fire,+--   just a camp fest or firing blindly+-- dense ranged in daylight: no, less fun than at night with flares+-- crowd ranged: no, fish in a barel, less predictable and more fun inside+--   crawl, even without reaction fire -raid = ModeKind+raid = ModeKind  -- mini-crawl   { msymbol = 'r'   , mname   = "raid"-  , mfreq   = [("raid", 1)]+  , mfreq   = [("raid", 1), ("campaign scenario", 1)]   , mroster = rosterRaid   , mcaves  = cavesRaid-  , mdesc   = "The Triton City sewers need purging. The first person to break through to the other end will be paid 100 gold grains. Please don't fight."+  , mdesc   = "Neptune Area Administration confirms isolated spottings of various oversize vermin in non-residential zones of the Triton moon's largest city. To put it plainly: Triton City sewers need purging. The first person to break through to the other exit will be paid 100 gold grains. The Administration strongly urges participants not to resort to violence against each other."   } -skirmish = ModeKind+brawl = ModeKind  -- sparse melee in daylight, with shade for melee ambush   { msymbol = 'k'-  , mname   = "skirmish"-  , mfreq   = [("skirmish", 1)]-  , mroster = rosterSkirmish-  , mcaves  = cavesSkirmish-  , mdesc   = "You cheated. Come alone to the woody biosphere behind the saloon at noon, if you dare. The winner takes all the spoils, including the keys and the papers of the decrepit giant spaceship."+  , mname   = "brawl"+  , mfreq   = [("brawl", 1), ("campaign scenario", 1)]+  , mroster = rosterBrawl+  , mcaves  = cavesBrawl+  , mdesc   = "\"You scoundrel! You cheated in the sewers. Come alone to the woody biosphere behind the saloon at noon, if you dare. Given that I win, I take back all your gold. Otherwise, you get the scrapping rights for the giant spaceliner's hull in orbit. Yes, it's mine, you tramp; here's the docking transmitter and the paperwork.\""   } -ambush = ModeKind+-- The trajectory tip is important because of tactics of scout looking from+-- behind a bush and others hiding in mist. If no suitable bushes,+-- fire once and flee into mist or behind cover. Then whomever is out of LOS+-- range or inside mist can shoot at the last seen enemy locations,+-- adjusting and according to ounds and incoming missile trajectories.+-- If the scount can't find bushes or glass building to set a lookout,+-- the other team member are more spotters and guardians than snipers+-- and that's their only role, so a small party makes sense.+shootout = ModeKind  -- sparse ranged in daylight+  { msymbol = 's'+  , mname   = "shootout"+  , mfreq   = [("shootout", 1), ("campaign scenario", 1)]+  , mroster = rosterShootout+  , mcaves  = cavesShootout+  , mdesc   = "The fight crashes over to a nearby mechanized farm. Law enforcement, crippled by the ban on firearms, won't show up until only wounded and dying remain to be revived and locked up. Farm supplies, scattered around, beg to be flung at foes as improvised missiles. Intense light makes it easy to aim and to discern trajectory of soaring items (point at projectiles with the crosshair in aiming mode)."+  }++escape = ModeKind  -- asymmetric ranged and stealth race at night+  { msymbol = 'e'+  , mname   = "escape"+  , mfreq   = [("escape", 1), ("campaign scenario", 1)]+  , mroster = rosterEscape+  , mcaves  = cavesEscape+  , mdesc   = "Bloodied spaceship deed in hand notwithstanding, you can reach the derelict spaceliner only via a shuttle from the Triton Spaceport across the city. After hours of being chased in the opposite direction towards the border wall, you sneak back and make a desperate dash through the very territory of the pursuing gang. Any valuables you come upon in this public park turned miscreant lair will be fair compensation for your personal losses, but you need to find the exit before the foes find you."+  }++zoo = ModeKind  -- asymmetric crowd melee at night+  { msymbol = 'b'+  , mname   = "zoo"+  , mfreq   = [("zoo", 1), ("campaign scenario", 1)]+  , mroster = rosterZoo+  , mcaves  = cavesZoo+  , mdesc   = "As justified and satisfying as setting the enemy headquarters on fire has been, it backfires when the blaze immediately spreads to the public zoo on the path to the spaceport. Crazed animals mill around while the flames ignite greenery and consume nets, cages and security equipment. Whether that's a good sign or bad, apparently nobody is willing to pursue you any more."+  }++-- The tactic is to sneak in the dark, highlight enemy with thrown torches+-- (and douse thrown enemy torches with blankets) and only if this fails,+-- actually scout using extended noctovision.+-- With reaction fire, larger team is more fun.+--+-- For now, while we have no shooters with timeout, massive ranged battles+-- without reaction fire don't make sense, because then usually only one hero+-- shoots (and often also scouts) and others just gather ammo.+ambush = ModeKind  -- dense ranged with reaction fire at night   { msymbol = 'm'   , mname   = "ambush"-  , mfreq   = [("ambush", 1)]+  , mfreq   = [("ambush", 1), ("campaign scenario", 1)]   , mroster = rosterAmbush   , mcaves  = cavesAmbush-  , mdesc   = "Conveniently, on the path to the Triton's spaceport, passengers can relax in a shady park."-  }--battle = ModeKind-  { msymbol = 'b'-  , mname   = "battle"-  , mfreq   = [("battle", 1)]-  , mroster = rosterBattle-  , mcaves  = cavesBattle-  , mdesc   = "Not even the unexplained ruin of the largest and tightest security Neptune's moon spaceport will prevent you from claiming your prize."+  , mdesc   = "Not even the unexplained ruin of the largest and tightest security of Neptune's spaceports will prevent you from claiming your prize. After all, you didn't take to the space to let others decide your fate. Onward!"   } -battleSurvival = ModeKind-  { msymbol = 'i'-  , mname   = "battle survival"-  , mfreq   = [("battle survival", 1)]-  , mroster = rosterBattleSurvival-  , mcaves  = cavesBattle-  , mdesc   = "Odds are stacked for those that breathe mathematics."+exploration = ModeKind+  { msymbol = 'c'+  , mname   = "crawl (long)"+  , mfreq   = [ ("crawl (long)", 1), ("exploration", 1)+              , ("campaign scenario", 1) ]+  , mroster = rosterExploration+  , mcaves  = cavesExploration+  , mdesc   = "You get stranded while looting, with utmost satisfaction, the blasted bridge of an old and extravagantly luxurious cruise liner. The inert spaceship, supposedly long deserted and barely able to sustain life support, suddenly releases the shuttle you came in, lights up its ion engines, manoeuvres deftly off Triton orbit and heads purposefully away from Neptune. Your plan of battle is to break through the dilapidated decks to the auxiliary engineering and docking hub somewhere among the giant spaceship's uppermost levels. You are ready to fight and determined not to leave the ship without taking of its wealth what is rightfully yours. There are animal cries down below and ominous silence up above."   } -safari = ModeKind+safari = ModeKind  -- easter egg available only via screensaver   { msymbol = 'f'   , mname   = "safari"   , mfreq   = [("safari", 1)]   , mroster = rosterSafari   , mcaves  = cavesSafari-  , mdesc   = "In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent (exit at the uppermost level)."+  , mdesc   = "\"In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent. Exit at the topmost level.\" This is a VR recording recovered from an alien nest debris."   } +-- * Testing modes++explorationSurvival = ModeKind+  { msymbol = 'd'+  , mname   = "crawl survival"+  , mfreq   = [("crawl survival", 1)]+  , mroster = rosterExplorationSurvival+  , mcaves  = cavesExploration+  , mdesc   = "Lure the human intruders deeper and deeper."+  }+ safariSurvival = ModeKind   { msymbol = 'u'   , mname   = "safari survival"@@ -98,256 +153,330 @@   , mdesc   = "In this simulation you'll discover the joys of being hunted among the most exquisite of Earth's flora and fauna, both animal and semi-intelligent."   } -pvp = ModeKind-  { msymbol = 'v'-  , mname   = "PvP"-  , mfreq   = [("PvP", 1)]-  , mroster = rosterPvP-  , mcaves  = cavesSkirmish-  , mdesc   = "(Not usable right now.) This is a fight to the death between two human-controlled teams."+battle = ModeKind+  { msymbol = 'b'+  , mname   = "battle"+  , mfreq   = [("battle", 1)]+  , mroster = rosterBattle+  , mcaves  = cavesBattle+  , mdesc   = "Odds are stacked against those that unleash the horrors of abstraction."   } -coop = ModeKind-  { msymbol = 'o'-  , mname   = "Coop"-  , mfreq   = [("Coop", 1)]-  , mroster = rosterCoop-  , mcaves  = cavesCampaign-  , mdesc   = "(This mode is intended solely for automated testing.)"+battleSurvival = ModeKind+  { msymbol = 'i'+  , mname   = "battle survival"+  , mfreq   = [("battle survival", 1)]+  , mroster = rosterBattleSurvival+  , mcaves  = cavesBattle+  , mdesc   = "Odds are stacked for those that breathe mathematics."   } -defense = ModeKind+defense = ModeKind  -- perhaps a real scenario in the future   { msymbol = 'e'   , mname   = "defense"   , mfreq   = [("defense", 1)]   , mroster = rosterDefense-  , mcaves  = cavesCampaign+  , mcaves  = cavesExploration   , mdesc   = "Don't let the half-witted humans derail your operation and flee, like the puny, naked, tentacle-less beasts that they are!"   } -screensaver = safari-  { mname   = "safari screensaver"-  , mfreq   = [("starting", 1)]-  , mroster = rosterSafari-      { rosterList = (head (rosterList rosterSafari))-                       -- changing leader by client needed, because of TFollow-                       -- changing level by client enabled for UI-                       {fleaderMode = LeaderAI $ AutoLeader False False}-                     : tail (rosterList rosterSafari)-      }+-- * Screensaver modes++screensave :: AutoLeader -> Roster -> Roster+screensave auto r =+  let f [] = []+      f ((player, initial) : rest) =+        (player {fleaderMode = LeaderAI auto}, initial) : rest+  in r {rosterList = f $ rosterList r}++screensaverRaid = raid+  { mname   = "auto-raid"+  , mfreq   = [("starting", 1), ("starting JS", 1), ("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterRaid   } +screensaverBrawl = brawl+  { mname   = "auto-brawl"+  , mfreq   = [("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterBrawl+  } -rosterCampaign, rosterRaid, rosterSkirmish, rosterAmbush, rosterBattle, rosterBattleSurvival, rosterSafari, rosterSafariSurvival, rosterPvP, rosterCoop, rosterDefense :: Roster+screensaverShootout = shootout+  { mname   = "auto-shootout"+  , mfreq   = [("starting", 1), ("starting JS", 1), ("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterShootout+  } -rosterCampaign = Roster-  { rosterList = [ playerHero-                 , playerMonster-                 , playerAnimal-                 , playerRobot ]-  , rosterEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")-                  , ("Spacefarer Crew", "Animal Kingdom")-                  , ("Spacefarer Crew", "Robot Anarchy") ]-  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                 , ("Alien Hierarchy", "Robot Anarchy")-                 , ("Robot Anarchy", "Animal Kingdom") ] }+screensaverEscape = escape+  { mname   = "auto-escape"+  , mfreq   = [("starting", 1), ("starting JS", 1), ("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterEscape+  } +screensaverZoo = zoo+  { mname   = "auto-zoo"+  , mfreq   = [("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterZoo+  }++screensaverAmbush = ambush+  { mname   = "auto-ambush"+  , mfreq   = [("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterAmbush+  }++screensaverExploration = exploration+  { mname   = "auto-crawl"+  , mfreq   = [("no confirms", 1)]+  , mroster = screensave (AutoLeader False False) rosterExploration+  }++screensaverSafari = safari+  { mname   = "auto-safari"+  , mfreq   = [("starting", 1), ("starting JS", 1), ("no confirms", 1)]+  , mroster = -- changing leader by client needed, because of TFollow+              screensave (AutoLeader False True) rosterSafari+  }++rosterRaid, rosterBrawl, rosterShootout, rosterEscape, rosterZoo, rosterAmbush, rosterExploration, rosterExplorationSurvival, rosterSafari, rosterSafariSurvival, rosterBattle, rosterBattleSurvival, rosterDefense :: Roster+ rosterRaid = Roster-  { rosterList = [ playerHero { fname = "Spacefarer Crew"-                              , fhiCondPoly = hiRaid-                              , fentryLevel = 4-                              , finitialActors = 1 }-                 , playerAntiHero { fname = "Red Collars"-                                  , fhiCondPoly = hiRaid-                                  , fentryLevel = 4-                                  , finitialActors = 1 }-                 , playerAnimal { fentryLevel = 4-                                , finitialActors = 1 }-                 , playerRobot { fentryLevel = 4-                               , finitialActors = 1 } ]-  , rosterEnemy = [ ("Spacefarer Crew", "Animal Kingdom")-                  , ("Spacefarer Crew", "Robot Anarchy")-                  , ("Red Collars", "Animal Kingdom")-                  , ("Red Collars", "Robot Anarchy") ]+  { rosterList = [ ( playerHero {fhiCondPoly = hiRaid}+                   , [(2, 1, "hero")] )+                 , ( playerAntiHero { fname = "Red Collar Bro"+                                    , fhiCondPoly = hiRaid }+                   , [(2, 1, "hero")] )+                 , ( playerAnimal  -- starting over escape+                   , [(2, 2, "animal")] )+                 , ( playerRobot+                   , [(2, 1, "robot")] )+                 , (playerHorror, []) ]  -- for summoned monsters+  , rosterEnemy = [ ("Spacefarer", "Animal Kingdom")+                  , ("Spacefarer", "Robot Anarchy")+                  , ("Spacefarer", "Horror Den")+                  , ("Spacefarer", "Red Collar Bro")+                  , ("Red Collar Bro", "Animal Kingdom")+                  , ("Red Collar Bro", "Robot Anarchy")+                  , ("Red Collar Bro", "Horror Den") ]   , rosterAlly = [("Robot Anarchy", "Animal Kingdom")] } -rosterSkirmish = Roster-  { rosterList = [ playerHero { fname = "Spacefarer Crew"-                              , fhiCondPoly = hiDweller-                              , fentryLevel = 4 }-                 , playerAntiHero { fname = "Red Collars"-                                  , fhiCondPoly = hiDweller-                                  , fentryLevel = 4 }-                 , playerHorror ]-  , rosterEnemy = [ ("Spacefarer Crew", "Red Collars")-                  , ("Spacefarer Crew", "Horror Den")-                  , ("Red Collars", "Horror Den") ]+rosterBrawl = Roster+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller }+                   , [(3, 3, "hero")] )+                 , ( playerAntiHero { fname = "Red Collar Bro"+                                    , fcanEscape = False+                                    , fhiCondPoly = hiDweller }+                   , [(3, 3, "hero")] )+                 , (playerHorror, []) ]+  , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")+                  , ("Spacefarer", "Horror Den")+                  , ("Red Collar Bro", "Horror Den") ]   , rosterAlly = [] } -rosterAmbush = rosterSkirmish-  { rosterList = [ playerSniper { fname = "Spacefarer Crew"-                                , fhiCondPoly = hiDweller-                                , fentryLevel = 7-                                , finitialActors = 4 }-                 , playerAntiSniper { fname = "Red Collars"-                                    , fhiCondPoly = hiDweller-                                    , fentryLevel = 7-                                    , finitialActors = 4 }-                 , playerHorror {fentryLevel = 7} ] }--rosterBattle = Roster-  { rosterList = [ playerSoldier { fhiCondPoly = hiDweller-                                 , fentryLevel = 7-                                 , finitialActors = 5 }-                 , playerMobileMonster { fentryLevel = 7-                                       , finitialActors = 35-                                       , fneverEmpty = True }-                 , playerMobileAnimal { fentryLevel = 7-                                      , finitialActors = 20-                                      , fneverEmpty = True }-                 , playerMobileRobot { fentryLevel = 7-                                     , finitialActors = 15-                                     , fneverEmpty = True } ]-  , rosterEnemy = [ ("Armed Spacefarer Crew", "Alien Hierarchy")-                  , ("Armed Spacefarer Crew", "Animal Kingdom")-                  , ("Armed Spacefarer Crew", "Robot Anarchy") ]-  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                , ("Alien Hierarchy", "Robot Anarchy")-                , ("Robot Anarchy", "Animal Kingdom") ] }--rosterBattleSurvival = rosterBattle-  { rosterList = [ playerSoldier { fhiCondPoly = hiDweller-                                 , fentryLevel = 7-                                 , finitialActors = 5-                                 , fleaderMode =-                                     LeaderAI $ AutoLeader True False-                                 , fhasUI = False }-                 , playerMobileMonster { fentryLevel = 7-                                       , finitialActors = 35-                                       , fneverEmpty = True }-                 , playerMobileAnimal { fentryLevel = 7-                                      , finitialActors = 20-                                      , fneverEmpty = True }-                 , playerMobileRobot { fentryLevel = 7-                                     , finitialActors = 15-                                     , fneverEmpty = True-                                     , fhasUI = True } ] }+-- Exactly one scout gets a sight boost, to help the aggressor, because he uses+-- the scout for initial attack, while camper (on big enough maps)+-- can't guess where the attack would come and so can't position his single+-- scout to counter the stealthy advance.+rosterShootout = Roster+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller }+                   , [(5, 1, "scout hero"), (5, 2, "ranger hero")] )+                 , ( playerAntiHero { fname = "Red Collar Bro"+                                    , fcanEscape = False+                                    , fhiCondPoly = hiDweller }+                   , [(5, 1, "scout hero"), (5, 2, "ranger hero")] )+                 , (playerHorror, []) ]+  , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")+                  , ("Spacefarer", "Horror Den")+                  , ("Red Collar Bro", "Horror Den") ]+  , rosterAlly = [] } -playerMonsterTourist, playerHunamConvict, playerAnimalMagnificent, playerAnimalExquisite :: Player Dice+rosterEscape = Roster+  { rosterList = [ ( playerHero {fhiCondPoly = hiEscapist}+                   , [(7, 1, "scout hero"), (7, 2, "escapist hero")] )+                 , ( playerAntiHero { fname = "Red Collar Bro"+                                    , fcanEscape = False  -- start on escape+                                    , fhiCondPoly = hiDweller }+                   , [(7, 1, "scout hero"), (7, 7, "ambusher hero")] )+                 , (playerHorror, []) ]+  , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")+                  , ("Spacefarer", "Horror Den")+                  , ("Red Collar Bro", "Horror Den") ]+  , rosterAlly = [] } -playerMonsterTourist =-  playerAntiMonster { fname = "Alien Tourist Office"-                    , fcanEscape = True-                    , fneverEmpty = True  -- no spawning-                      -- Follow-the-guide, as tourists do.-                    , ftactic = TFollow-                    , fentryLevel = 4-                    , finitialActors = 15-                    , fleaderMode =-                        LeaderUI $ AutoLeader False False }+rosterZoo = Roster+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller }+                   , [(8, 5, "soldier hero")] )+                 , ( playerAnimal {fneverEmpty = True}+                   , [(8, 100, "mobile animal")] )+                 , (playerHorror, []) ]  -- for summoned monsters+  , rosterEnemy = [ ("Spacefarer", "Animal Kingdom")+                  , ("Spacefarer", "Horror Den") ]+  , rosterAlly = [] } -playerHunamConvict =-  playerCivilian { fname = "Hunam Convict Pack"-                 , fentryLevel = 4 }+rosterAmbush = Roster+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller }+                   , [(9, 1, "scout hero"), (9, 5, "ambusher hero")] )+                 , ( playerAntiHero { fname = "Gray Off-world Mercenary"+                                    , fcanEscape = False+                                    , fhiCondPoly = hiDweller }+                   , [(9, 1, "scout hero"), (9, 5, "ambusher hero")] )+                 , (playerHorror, []) ]+  , rosterEnemy = [ ("Spacefarer", "Gray Off-world Mercenary")+                  , ("Spacefarer", "Horror Den")+                  , ("Gray Off-world Mercenary", "Horror Den") ]+  , rosterAlly = [] } -playerAnimalMagnificent =-  playerMobileAnimal { fname = "Animal Magnificent Specimen Variety"-                     , fneverEmpty = True-                     , fentryLevel = 7-                     , finitialActors = 10-                     , fleaderMode =  -- move away from stairs-                         LeaderAI $ AutoLeader True False }+rosterExploration = Roster+  { rosterList = [ ( playerHero+                   , [(3, 3, "hero")] )+                 , ( playerMonster+                   , [] )+                 , ( playerAnimal+                   , -- Fun from the start to avoid empty initial level:+                     [ (3, 5 + d 2, "animal")  -- many, because no spawning+                     -- Optional huge battle at the end:+                     , (12, 100, "mobile animal") ] )+                 , ( playerRobot+                   , [] ) ]  -- gentle introduction+  , rosterEnemy = [ ("Spacefarer", "Alien Hierarchy")+                  , ("Spacefarer", "Animal Kingdom")+                  , ("Spacefarer", "Robot Anarchy") ]+  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")+                 , ("Alien Hierarchy", "Robot Anarchy")+                 , ("Robot Anarchy", "Animal Kingdom") ] } -playerAnimalExquisite =-  playerMobileAnimal { fname = "Animal Exquisite Herds and Packs"-                     , fneverEmpty = True-                     , fentryLevel = 10-                     , finitialActors = 30 }+rosterExplorationSurvival = rosterExploration+  { rosterList = [ ( playerHero { fleaderMode =+                                    LeaderAI $ AutoLeader True False+                                , fhasUI = False }+                   , [(3, 3, "hero")] )+                 , ( playerMonster+                   , [] )+                 , ( playerAnimal {fhasUI = True}+                   , -- Fun from the start to avoid empty initial level:+                     [ (3, 5 + d 2, "animal")  -- many, because no spawning+                     -- Optional huge battle at the end:+                     , (12, 100, "mobile animal") ] )+                 , ( playerRobot+                   , [] ) ] }  -- gentle introduction +-- No horrors faction needed, because spawned heroes land in civilian faction. rosterSafari = Roster-  { rosterList = [ playerMonsterTourist-                 , playerHunamConvict-                 , playerAnimalMagnificent-                 , playerAnimalExquisite-                 ]-  , rosterEnemy = [ ( "Alien Tourist Office", "Hunam Convict Pack")+  { rosterList = [ ( playerMonsterTourist+                   , [(4, 15, "monster")] )+                 , ( playerHunamConvict+                   , [(4, 3, "civilian")] )+                 , ( playerAnimalMagnificent+                   , [(7, 20, "mobile animal")] )+                 , ( playerAnimalExquisite  -- start on escape+                   , [(10, 30, "mobile animal")] )+                 , (playerHorror, []) ]  -- construction hooter; neutral+  , rosterEnemy = [ ("Alien Tourist Office", "Hunam Convict")                   , ( "Alien Tourist Office"                     , "Animal Magnificent Specimen Variety" )                   , ( "Alien Tourist Office"-                    , "Animal Exquisite Herds and Packs" ) ]+                    , "Animal Exquisite Herds and Packs Galore" )+                  , ( "Animal Magnificent Specimen Variety"+                    , "Hunam Convict" )+                  , ( "Hunam Convict"+                    , "Animal Exquisite Herds and Packs Galore" ) ]   , rosterAlly = [ ( "Animal Magnificent Specimen Variety"-                   , "Animal Exquisite Herds and Packs" )-                 , ( "Animal Magnificent Specimen Variety"-                   , "Hunam Convict Pack" )-                 , ( "Hunam Convict Pack"-                   , "Animal Exquisite Herds and Packs" ) ] }+                   , "Animal Exquisite Herds and Packs Galore" ) ] }  rosterSafariSurvival = rosterSafari-  { rosterList = [ playerMonsterTourist-                     { fleaderMode = LeaderAI $ AutoLeader True False-                     , fhasUI = False }-                 , playerHunamConvict-                 , playerAnimalMagnificent-                     { fleaderMode = LeaderUI $ AutoLeader False False+  { rosterList = [ ( playerMonsterTourist+                       { fleaderMode = LeaderAI $ AutoLeader True True+                       , fhasUI = False }+                   , [(4, 15, "monster")] )+                 , ( playerHunamConvict+                   , [(4, 3, "civilian")] )+                 , ( playerAnimalMagnificent+                     { fleaderMode = LeaderUI $ AutoLeader True False                      , fhasUI = True }-                 , playerAnimalExquisite-                 ] }+                   , [(7, 20, "mobile animal")] )+                 , ( playerAnimalExquisite+                   , [(10, 30, "mobile animal")] )+                 , (playerHorror, []) ] } -rosterPvP = Roster-  { rosterList = [ playerHero { fname = "Red"-                              , fhiCondPoly = hiDweller-                              , fentryLevel = 4 }-                 , playerHero { fname = "Blue"-                              , fhiCondPoly = hiDweller-                              , fentryLevel = 4 }-                 , playerHorror ]-  , rosterEnemy = [ ("Red", "Blue")-                  , ("Red", "Horror Den")-                  , ("Blue", "Horror Den") ]-  , rosterAlly = [] }+rosterBattle = Roster+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller }+                   , [(5, 5, "soldier hero")] )+                 , ( playerMonster {fneverEmpty = True}+                   , [(5, 35, "mobile monster")] )+                 , ( playerAnimal {fneverEmpty = True}+                   , [(5, 20, "mobile animal")] )+                 , ( playerRobot {fneverEmpty = True}+                   , [(5, 15, "mobile robot")] ) ]+  , rosterEnemy = [ ("Spacefarer", "Alien Hierarchy")+                  , ("Spacefarer", "Animal Kingdom")+                  , ("Spacefarer", "Robot Anarchy") ]+  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")+                 , ("Alien Hierarchy", "Robot Anarchy")+                 , ("Robot Anarchy", "Animal Kingdom") ] } -rosterCoop = Roster-  { rosterList = [ playerAntiHero { fname = "Coral" }-                 , playerAntiHero { fname = "Amber"-                                  , fleaderMode = LeaderNull }-                 , playerAnimal { fhasUI = True }-                 , playerAnimal-                 , playerMonster { fname = "Alien Hierarchy"-                                 , finitialActors = 3 }-                 , playerMonster { fname = "Leaderless Alien Hierarchy"-                                 , finitialActors = 1-                                 , fleaderMode = LeaderNull }-                 , playerRobot ]-  , rosterEnemy = [ ("Coral", "Alien Hierarchy")-                  , ("Amber", "Alien Hierarchy") ]-  , rosterAlly = [ ("Coral", "Amber") ] }+rosterBattleSurvival = rosterBattle+  { rosterList = [ ( playerHero { fcanEscape = False+                                , fhiCondPoly = hiDweller+                                , fleaderMode =+                                    LeaderAI $ AutoLeader False False+                                , fhasUI = False }+                   , [(5, 5, "soldier hero")] )+                 , ( playerMonster {fneverEmpty = True}+                   , [(5, 35, "mobile monster")] )+                 , ( playerAnimal { fneverEmpty = True+                                  , fhasUI = True }+                   , [(5, 20, "mobile animal")] )+                 , ( playerRobot {fneverEmpty = True}+                   , [(5, 15, "mobile robot")] ) ] } -rosterDefense = rosterCampaign-  { rosterList = [ playerAntiHero-                 , playerAntiMonster-                 , playerAnimal-                 , playerRobot ] }+rosterDefense = rosterExploration+  { rosterList = [ ( playerAntiHero+                   , [(3, 3, "hero")] )+                 , ( playerAntiMonster+                   , [] )+                 , ( playerAnimal+                   , -- Fun from the start to avoid empty initial level:+                     [ (3, 5 + d 2, "animal")  -- many, because no spawning+                     -- Optional huge battle at the end:+                     , (12, 100, "mobile animal") ] )+                 , ( playerRobot+                   , [] ) ] }  -- gentle introduction -cavesCampaign, cavesRaid, cavesSkirmish, cavesAmbush, cavesBattle, cavesSafari :: Caves+cavesRaid, cavesBrawl, cavesShootout, cavesEscape, cavesZoo, cavesAmbush, cavesExploration, cavesSafari, cavesBattle :: Caves -cavesCampaign = IM.fromList-                $ [(1, ("shallow random 1", Nothing))]-                  ++ [(2, ("shallow random 2", Nothing))]-                  ++ [(3, ("caveBridge", Nothing))]-                  ++ [(4, ("caveNoise", Nothing))]-                  ++ zip [5..9] (repeat ("campaign random", Nothing))-                  ++ [(10, ("caveEmpty", Just False))]-                  ++ [(11, ("campaign random", Nothing))]-                  ++ [(12, ("caveNoise", Nothing))]+cavesRaid = IM.fromList [(2, "caveRaid")] -cavesRaid = IM.fromList [(4, ("caveRogueLit", Just True))]+cavesBrawl = IM.fromList [(3, "caveBrawl")] -cavesSkirmish = IM.fromList [(4, ("caveSkirmish", Nothing))]+cavesShootout = IM.fromList [(5, "caveShootout")] -cavesAmbush = IM.fromList [(7, ("caveAmbush", Nothing))]+cavesEscape = IM.fromList [(7, "caveEscape")] -cavesBattle = IM.fromList [(7, ("caveBattle", Nothing))]+cavesZoo = IM.fromList [(8, "caveZoo")] -cavesSafari = IM.fromList [ (4, ("caveSafari1", Nothing))-                          , (7, ("caveSafari2", Nothing))-                          , (10, ("caveSafari3", Just False)) ]+cavesAmbush = IM.fromList [(9, "caveAmbush")]++cavesExploration = IM.fromList $+  [(1, "outermost")]+  ++ [(2, "shallow random 2")]+  ++ [(3, "caveBridge")]+  ++ [(4, "caveNoise")]+  ++ [(5, "default random")]+  ++ [(6, "default random")]+  ++ [(7, "deep random")]+  ++ [(8, "deep random")]+  ++ [(9, "deep random")]+  ++ [(10, "caveEmptyExit")]+  ++ [(11, "deep random")]+  ++ [(12, "caveNoise2")]++cavesSafari = IM.fromList [ (4, "caveSafari1")+                          , (7, "caveSafari2")+                          , (10, "caveSafari3") ]++cavesBattle = IM.fromList [(5, "caveBattle")]
GameDefinition/Content/ModeKindPlayer.hs view
@@ -1,92 +1,70 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Basic players definitions. module Content.ModeKindPlayer-  ( playerHero, playerSoldier, playerSniper-  , playerAntiHero, playerAntiSniper, playerCivilian-  , playerMonster, playerMobileMonster, playerAntiMonster-  , playerAnimal, playerMobileAnimal-  , playerRobot, playerMobileRobot-  , playerHorror-  , hiHero, hiDweller, hiRaid+  ( playerHero, playerAntiHero, playerCivilian+  , playerMonster, playerAntiMonster, playerAnimal+  , playerHorror, playerMonsterTourist, playerHunamConvict+  , playerAnimalMagnificent, playerAnimalExquisite+  , hiHero, hiDweller, hiRaid, hiEscapist+  , playerRobot   ) where -import Data.List+import Prelude () +import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.Ability-import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind -playerHero, playerSoldier, playerSniper, playerAntiHero, playerAntiSniper, playerCivilian, playerMonster, playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal, playerRobot, playerMobileRobot, playerHorror :: Player Dice+playerHero, playerAntiHero, playerCivilian, playerMonster, playerAntiMonster, playerAnimal, playerHorror, playerMonsterTourist, playerHunamConvict, playerAnimalMagnificent, playerAnimalExquisite :: Player+playerRobot :: Player  playerHero = Player-  { fname = "Spacefarer Crew"-  , fgroup = "hero"+  { fname = "Spacefarer"+  , fgroups = ["hero"]   , fskillsOther = meleeAdjacent   , fcanEscape = True   , fneverEmpty = True   , fhiCondPoly = hiHero-  , fhasNumbers = True   , fhasGender = True   , ftactic = TExplore-  , fentryLevel = 3-  , finitialActors = 3   , fleaderMode = LeaderUI $ AutoLeader False False   , fhasUI = True   } -playerSoldier = playerHero-  { fname = "Armed Spacefarer Crew"-  , fgroup = "soldier"-  }--playerSniper = playerHero-  { fname = "Sniper Adventurer Party"-  , fgroup = "sniper"-  }- playerAntiHero = playerHero   { fleaderMode = LeaderAI $ AutoLeader True False   , fhasUI = False   } -playerAntiSniper = playerSniper-  { fleaderMode = LeaderAI $ AutoLeader True False-  , fhasUI = False-  }- playerCivilian = Player-  { fname = "Civilian Crowd"-  , fgroup = "civilian"+  { fname = "Civilian"+  , fgroups = ["hero", "civilian"]   , fskillsOther = zeroSkills  -- not coordinated by any leadership   , fcanEscape = False   , fneverEmpty = True   , fhiCondPoly = hiDweller-  , fhasNumbers = False   , fhasGender = True   , ftactic = TPatrol-  , fentryLevel = 1-  , finitialActors = d 2 + 1   , fleaderMode = LeaderNull  -- unorganized   , fhasUI = False   }  playerMonster = Player   { fname = "Alien Hierarchy"-  , fgroup = "alien"+  , fgroups = ["monster", "mobile monster", "immobile monster"]   , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False   , fhiCondPoly = hiDweller-  , fhasNumbers = False   , fhasGender = False   , ftactic = TExplore-  , fentryLevel = 4-  , finitialActors = 0   , fleaderMode =       -- No point changing leader on level, since all move and they       -- don't follow the leader.@@ -94,8 +72,6 @@   , fhasUI = False   } -playerMobileMonster = playerMonster- playerAntiMonster = playerMonster   { fhasUI = True   , fleaderMode = LeaderUI $ AutoLeader True True@@ -103,90 +79,102 @@  playerAnimal = Player   { fname = "Animal Kingdom"-  , fgroup = "animal"+  , fgroups = ["animal", "mobile animal", "immobile animal", "scavenger"]   , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False   , fhiCondPoly = hiDweller-  , fhasNumbers = False   , fhasGender = False   , ftactic = TRoam  -- can't pick up, so no point exploring-  , fentryLevel = 3-  , finitialActors = 2 + d 2  -- many, because no spawning   , fleaderMode = LeaderNull   , fhasUI = False   } -playerMobileAnimal = playerAnimal-  { fgroup = "mobile animal" }--playerRobot = Player-  { fname = "Robot Anarchy"-  , fgroup = "robot"-  , fskillsOther = zeroSkills-  , fcanEscape = False-  , fneverEmpty = False-  , fhiCondPoly = hiDweller-  , fhasNumbers = False-  , fhasGender = False-  , ftactic = TRoam  -- TODO:TFollow -- coordinated via net, follow alien leader-  , fentryLevel = 3-  , finitialActors = 2 + d 2  -- many, because no spawning-  , fleaderMode = LeaderNull-  , fhasUI = False-  }--playerMobileRobot = playerRobot-  { fgroup = "mobile robot" }- -- | A special player, for summoned actors that don't belong to any -- of the main players of a given game. E.g., animals summoned during--- a duel game between two hero players land in the horror faction.+-- a brawl game between two hero factions land in the horror faction. -- In every game, either all factions for which summoning items exist -- should be present or a horror player should be added to host them.--- Actors that can be summoned should have "horror" in their @ifreq@ set. playerHorror = Player   { fname = "Horror Den"-  , fgroup = "horror"+  , fgroups = [nameOfHorrorFact]   , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False   , fhiCondPoly = []-  , fhasNumbers = False   , fhasGender = False   , ftactic = TPatrol  -- disoriented-  , fentryLevel = 4-  , finitialActors = 0   , fleaderMode = LeaderNull   , fhasUI = False   } +playerMonsterTourist =+  playerAntiMonster { fname = "Alien Tourist Office"+                    , fcanEscape = True+                    , fneverEmpty = True  -- no spawning+                    , fhiCondPoly = hiEscapist+                    , ftactic = TFollow  -- follow-the-guide, as tourists do+                    , fleaderMode = LeaderUI $ AutoLeader False False }++playerHunamConvict =+  playerCivilian { fname = "Hunam Convict"+                 , fleaderMode = LeaderAI $ AutoLeader True False }++playerAnimalMagnificent =+  playerAnimal { fname = "Animal Magnificent Specimen Variety"+               , fneverEmpty = True+               , fleaderMode = -- False to move away from stairs+                               LeaderAI $ AutoLeader True False }++playerAnimalExquisite =+  playerAnimal { fname = "Animal Exquisite Herds and Packs Galore"+               , fneverEmpty = True }+ victoryOutcomes :: [Outcome] victoryOutcomes = [Conquer, Escape] -hiHero, hiDweller, hiRaid :: HiCondPoly+hiHero, hiRaid, hiDweller, hiEscapist :: HiCondPoly  -- Heroes rejoice in loot. hiHero = [ ( [(HiLoot, 1)]            , [minBound..maxBound] )-         , ( [(HiConst, 1000), (HiLoss, -100)]+         , ( [(HiConst, 1000), (HiLoss, -1)]            , victoryOutcomes )          ] +hiRaid = [ ( [(HiLoot, 1)]+           , [minBound..maxBound] )+         , ( [(HiConst, 100)]+           , victoryOutcomes )+         ]+ -- Spawners or skirmishers get no points from loot, but try to kill -- all opponents fast or at least hold up for long.-hiDweller = [ ( [(HiConst, 1000)]  -- no loot+hiDweller = [ ( [(HiConst, 1000)]  -- no loot, so big win reward               , victoryOutcomes )             , ( [(HiConst, 1000), (HiLoss, -10)]               , victoryOutcomes )-            , ( [(HiBlitz, -100)]+            , ( [(HiBlitz, -100)]  -- speed matters               , victoryOutcomes )             , ( [(HiSurvival, 100)]               , [minBound..maxBound] \\ victoryOutcomes )             ] -hiRaid = [ ( [(HiLoot, 1)]-           , [minBound..maxBound] )-         , ( [(HiConst, 100)]-           , victoryOutcomes )-         ]+hiEscapist = ( [(HiLoot, 1)]  -- loot matters a little bit+             , [minBound..maxBound] )+             : hiDweller++-- Allure-specific++playerRobot = Player+  { fname = "Robot Anarchy"+  , fgroups = ["robot", "mobile robot", "immobile robot"]+  , fskillsOther = zeroSkills+  , fcanEscape = False+  , fneverEmpty = False+  , fhiCondPoly = hiDweller+  , fhasGender = False+  , ftactic = TRoam  -- TODO:TFollow -- coordinated via net, follow alien leader+  , fleaderMode = LeaderNull+  , fhasUI = False+  }
GameDefinition/Content/PlaceKind.hs view
@@ -1,12 +1,19 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Room, hall and passage definitions.-module Content.PlaceKind ( cdefs ) where+module Content.PlaceKind+  ( cdefs+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude+ import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.PlaceKind  cdefs :: ContentDef PlaceKind@@ -16,301 +23,782 @@   , getFreq = pfreq   , validateSingle = validateSinglePlaceKind   , validateAll = validateAllPlaceKind-  , content =-      [rect, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells]+  , content = contentFromList $+      [rect, rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown]+      ++ map makeStaircaseUp lstaircase+      ++ map makeStaircaseDown lstaircase+      -- Allure-specific+      ++ [staircaseLift, escapeSpaceshipDown, escapeSpaceshipDown2, escapeSpaceshipDown3, escapeSpaceshipDown4, escapeSpaceshipDown5, colonnadeWide, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells, cells2, cells3, cells4, cells5, cells6, cells7]   }-rect,        ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind+rect,        rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown :: PlaceKind+-- Allure-specific+staircaseLift, escapeSpaceshipDown, escapeSpaceshipDown2, escapeSpaceshipDown3, escapeSpaceshipDown4, escapeSpaceshipDown5, colonnadeWide, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells, cells2, cells3, cells4, cells5, cells6, cells7 :: PlaceKind +lstaircase :: [PlaceKind]+lstaircase = [staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated]+  -- Allure-specific+  ++ [staircaseLift]++-- The dots below are @Char.chr 183@, as defined in @TileKind.floorSymbol@. rect = PlaceKind  -- Valid for any nonempty area, hence low frequency.   { psymbol  = 'r'   , pname    = "room"-  , pfreq    = [("rogue", 70), ("ambush", 8), ("noise", 80)]+  , pfreq    = [ ("rogue", 100), ("arena", 40), ("laboratory", 40)+               , ("zoo", 7) ]   , prarity  = [(1, 10), (10, 8)]   , pcover   = CStretch   , pfence   = FWall-  , ptopLeft = ["."]+  , ptopLeft = ["·"]   , poverride = []   }+rectWindows = PlaceKind+  { psymbol  = 'w'+  , pname    = "room"+  , pfreq    = [("empty", 10), ("park", 7)]+  , prarity  = [(1, 10), (10, 8)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "#%"+               , "%·"+               ]+  , poverride = [('%', "rectWindowsOver_%_Lit")]+      -- for now I need to specify 'Lit' or I'd be randomly getting lit and dark+      -- tiles, until ooverride is extended to take night/dark into account+  }+glasshouse = PlaceKind+  { psymbol  = 'g'+  , pname    = "glasshouse"+  , pfreq    = [("arena", 40), ("shootout", 8), ("zoo", 12), ("ambush", 7)]+  , prarity  = [(1, 10), (10, 8)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "%%"+               , "%·"+               ]+  , poverride = [('%', "glasshouseOver_%_Lit")]+  }+pulpit = PlaceKind+  { psymbol  = 'p'+  , pname    = "pulpit"+  , pfreq    = [("arena", 10), ("zoo", 30)]+  , prarity  = [(1, 10), (10, 8)]+  , pcover   = CMirror+  , pfence   = FGround+  , ptopLeft = [ "%%·"+               , "%··"+               , "··O"+               ]+  , poverride = [('%', "glasshouseOver_%_Lit"), ('O', "pulpit")]+      -- except for floor, this will all be lit, regardless of night/dark; OK+  } ruin = PlaceKind   { psymbol  = 'R'   , pname    = "ruin"-  , pfreq    = [("ambush", 17), ("battle", 100), ("noise", 40)]+  , pfreq    = [("battle", 33), ("noise", 50)]   , prarity  = [(1, 10), (10, 20)]   , pcover   = CStretch   , pfence   = FWall   , ptopLeft = ["X"]   , poverride = []   }-collapsed = PlaceKind+collapsed = PlaceKind  -- in a dark cave, they have little lights --- that's OK   { psymbol  = 'c'   , pname    = "collapsed cavern"   , pfreq    = [("noise", 1)]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FNone-  , ptopLeft = ["#"]+  , ptopLeft = [ "#"+               ]   , poverride = [('#', "doorlessWallOver_#")]   } collapsed2 = collapsed-  { pfreq    = [("noise", 100), ("battle", 50)]+  { pfreq    = [("noise", 100), ("battle", 20)]+  , ptopLeft = [ "X#"+               , "##"+               ]+  }+collapsed3 = collapsed+  { pfreq    = [("noise", 200), ("battle", 20)]   , ptopLeft = [ "XX#"+               , "###"+               ]+  }+collapsed4 = collapsed+  { pfreq    = [("noise", 200), ("battle", 20)]+  , ptopLeft = [ "XXX#"+               , "####"+               ]+  }+collapsed5 = collapsed+  { pfreq    = [("noise", 300), ("battle", 50)]+  , ptopLeft = [ "XX#"                , "X##"+               , "###"                ]   }-collapsed3 = collapsed-  { pfreq    = [("noise", 200), ("battle", 50)]+collapsed6 = collapsed+  { pfreq    = [("noise", 400), ("battle", 100)]   , ptopLeft = [ "XXX#"                , "X###"+               , "####"                ]   }-collapsed4 = collapsed-  { pfreq    = [("noise", 400), ("battle", 200)]+collapsed7 = collapsed+  { pfreq    = [("noise", 400), ("battle", 100)]   , ptopLeft = [ "XXX#"-               , "XXX#"-               , "X###"+               , "XX##"+               , "####"                ]   } pillar = PlaceKind   { psymbol  = 'p'   , pname    = "pillar room"-  , pfreq    = [("rogue", 1000), ("noise", 50)]+  , pfreq    = [ ("rogue", 500), ("arena", 1000), ("laboratory", 1000)+               , ("empty", 300), ("noise", 1000) ]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FWall   -- Larger rooms require support pillars.-  , ptopLeft = [ "...."-               , ".O.."-               , "...."-               , "...."+  , ptopLeft = [ "····"+               , "·#··"+               , "····"+               , "····"                ]-  , poverride = []+  , poverride = [('&', "cachable")]   } pillar2 = pillar-  { prarity  = [(1, 5), (10, 5)]-  , ptopLeft = [ ".#.."-               , "#..."-               , "...."-               , "...."+  { ptopLeft = [ "··#·"+               , "··#·"+               , "##··"+               , "····"                ]   } pillar3 = pillar-  { prarity  = [(1, 5), (10, 5)]-  , ptopLeft = [ "#..."-               , "..#."-               , ".#.."-               , "...."+  { prarity  = [(10, 5)]+  , ptopLeft = [ "&·#·"+               , "··#·"+               , "##··"+               , "····"                ]   } pillar4 = pillar-  { prarity  = [(10, 7)]-  , ptopLeft = [ "&.#."-               , "...."-               , "#..."-               , "...."+  { prarity  = [(10, 5)]+  , ptopLeft = [ "&#··"+               , "#·#·"+               , "·##·"+               , "····"                ]   } colonnade = PlaceKind   { psymbol  = 'c'   , pname    = "colonnade"-  , pfreq    = [("rogue", 70), ("noise", 2000)]-  , prarity  = [(1, 10), (10, 10)]+  , pfreq    = [ ("rogue", 30), ("arena", 70), ("laboratory", 40)+               , ("empty", 100), ("mine", 10000), ("park", 3000) ]+  , prarity  = [(1, 3), (10, 3)]   , pcover   = CAlternate   , pfence   = FFloor-  , ptopLeft = [ ".#"-               , "#."+  , ptopLeft = [ "#·"+               , "·#"                ]   , poverride = []   } colonnade2 = colonnade-  { prarity  = [(1, 2), (10, 4)]-  , pfence   = FGround-  , ptopLeft = [ ".."-               , ".O"+  { prarity  = [(1, 2), (10, 2)]+  , ptopLeft = [ "#·"+               , "··"                ]   } colonnade3 = colonnade-  { prarity  = [(1, 4), (10, 6)]-  , ptopLeft = [ "#.."-               , "..#"+  { prarity  = [(1, 12), (10, 12)]+  , ptopLeft = [ "··#"+               , "·#·"+               , "#··"                ]   } colonnade4 = colonnade-  { ptopLeft = [ "#."-               , ".."-               , ".#"+  { prarity  = [(1, 12), (10, 12)]+  , ptopLeft = [ "#··"+               , "·#·"+               , "··#"                ]   }-colonnadeWide = colonnade-  { prarity  = [(1, 3), (10, 3)]-  , pfence   = FWall-  , ptopLeft = [ ".."-               , ".#"+colonnade5 = colonnade+  { prarity  = [(1, 7), (10, 7)]+  , ptopLeft = [ "#··"+               , "··#"                ]   }+colonnade6 = colonnade+  { ptopLeft = [ "#·"+               , "··"+               , "·#"+               ]+  } lampPost = PlaceKind   { psymbol  = 'l'   , pname    = "lamp post"-  , pfreq    = [("ambush", 30), ("battle", 10)]+  , pfreq    = [("park", 20), ("ambush", 20), ("zoo", 10), ("battle", 10)]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CVerbatim   , pfence   = FNone-  , ptopLeft = [ "X.X"-               , ".O."-               , "X.X"+  , ptopLeft = [ "X·X"+               , "·O·"+               , "X·X"                ]-  , poverride = [('O', "lampPostOver_O")]+  , poverride = [('O', "lampPostOver_O"), ('·', "floorActorLit")]   } lampPost2 = lampPost-  { ptopLeft = [ "..."-               , ".O."-               , "..."+  { ptopLeft = [ "···"+               , "·O·"+               , "···"                ]   } lampPost3 = lampPost-  { ptopLeft = [ "XX.XX"-               , "X...X"-               , "..O.."-               , "X...X"-               , "XX.XX"+  { pfreq    = [("park", 3000), ("zoo", 50), ("battle", 110)]+  , ptopLeft = [ "XX·XX"+               , "X···X"+               , "··O··"+               , "X···X"+               , "XX·XX"                ]   } lampPost4 = lampPost-  { ptopLeft = [ "X...X"-               , "....."-               , "..O.."-               , "....."-               , "X...X"+  { pfreq    = [("park", 3000), ("zoo", 50), ("battle", 60)]+  , ptopLeft = [ "X···X"+               , "·····"+               , "··O··"+               , "·····"+               , "X···X"                ]   } treeShade = PlaceKind   { psymbol  = 't'   , pname    = "tree shade"-  , pfreq    = [("skirmish", 100)]+  , pfreq    = [("brawl", 300)]   , prarity  = [(1, 10), (10, 10)]-  , pcover   = CVerbatim+  , pcover   = CMirror   , pfence   = FNone-  , ptopLeft = [ "sss"-               , "XOs"-               , "XXs"+  , ptopLeft = [ "··s"+               , "sO·"+               , "Xs·"                ]-  , poverride = [('O', "treeShadeOver_O"), ('s', "treeShadeOver_s")]+  , poverride = [ ('O', "treeShadeOver_O_Lit"), ('s', "treeShadeOver_s_Lit")+                , ('·', "shaded ground") ]   }-treeShade2 = treeShade-  { ptopLeft = [ "sss"-               , "XOs"-               , "Xss"+fogClump = PlaceKind+  { psymbol  = 'f'+  , pname    = "foggy patch"+  , pfreq    = [("shootout", 170)]+  , prarity  = [(1, 1)]+  , pcover   = CMirror+  , pfence   = FNone+  , ptopLeft = [ "f;"+               , ";f"+               , ";f"                ]+  , poverride = [('f', "fogClumpOver_f_Lit"), (';', "lit fog")]   }-treeShade3 = treeShade-  { ptopLeft = [ "sss"-               , "sOs"-               , "XXs"+fogClump2 = fogClump+  { pfreq    = [("shootout", 400), ("empty", 1500)]+  , prarity  = [(1, 1)]+  , pcover   = CMirror+  , pfence   = FNone+  , ptopLeft = [ "Xff"+               , "f;f"+               , ";;f"+               , "XfX"                ]   }+smokeClump = PlaceKind+  { psymbol  = 's'+  , pname    = "smoky patch"+  , pfreq    = [("zoo", 100), ("ambush", 50)]+  , prarity  = [(1, 1)]+  , pcover   = CMirror+  , pfence   = FNone+  , ptopLeft = [ "f;"+               , ";f"+               , ";f"+               ]+  , poverride = [ ('f', "smokeClumpOver_f_Lit"), (';', "lit smoke")+                , ('·', "floorActorLit") ]+  }+smokeClump2FGround = smokeClump+  { pfreq    = [("laboratory", 100), ("zoo", 1000), ("ambush", 500)]+  , prarity  = [(1, 1)]+  , pcover   = CMirror+  , pfence   = FGround+  , ptopLeft = [ ";f;"+               , "f·f"+               , ";·f"+               , ";f;"+               ]+  }+bushClump = PlaceKind+  { psymbol  = 'b'+  , pname    = "bushy patch"+  , pfreq    = [("shootout", 120)]+  , prarity  = [(1, 1)]+  , pcover   = CMirror+  , pfence   = FNone+  , ptopLeft = [ "f;"+               , ";f"+               , ";f"+               ]+  , poverride = [('f', "bushClumpOver_f_Lit"), (';', "bush Lit")]+  }+staircase = PlaceKind+  { psymbol  = '|'+  , pname    = "staircase"+  , pfreq    = [("staircase", 1)]+  , prarity  = [(1, 1)]+  , pcover   = CVerbatim+  , pfence   = FGround+  , ptopLeft = [ "<·>"+               ]+  , poverride = [ ('<', "staircase up"), ('>', "staircase down")+                , ('I', "signboard") ]+  }+staircase2 = staircase+  { pfreq    = [("staircase", 1000)]+  , pfence   = FFloor+  , ptopLeft = [ "#·#"+               , "···"+               , "<·>"+               , "···"+               , "#·#"+               ]+  }+staircase3 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "#·I·#"+               , "·····"+               , "·<·>·"+               , "·····"+               , "#·I·#"+               ]+  }+staircase4 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "#·#·#·#"+               , "·······"+               , "#·<·>·#"+               , "·······"+               , "#·#·#·#"+               ]+  }+staircase5 = staircase+  { pfreq    = [("staircase", 100)]+  , pfence   = FGround+  , ptopLeft = [ "#·<·>·#"+               ]+  }+staircase6 = staircase+  { pfreq    = [("staircase", 100)]+  , pfence   = FGround+  , ptopLeft = [ "#··<·>··#"+               ]+  }+staircase7 = staircase+  { pfreq    = [("staircase", 100)]+  , pfence   = FGround+  , ptopLeft = [ "#·I·<·>·I·#"+               ]+  }+staircase8 = staircase+  { pfreq    = [("staircase", 1000)]+  , pfence   = FFloor+  , ptopLeft = [ "#·····#"+               , "··<·>··"+               , "#·····#"+               ]+  }+staircase9 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "#·······#"+               , "·#·<·>·#·"+               , "#·······#"+               ]+  }+staircase10 = staircase+  { pfreq    = [("staircase", 1000)]+  , pfence   = FFloor+  , ptopLeft = [ "·#·····#·"+               , "#··<·>··#"+               , "·#·····#·"+               ]+  }+staircase11 = staircase+  { pfreq    = [("staircase", 10000)]+  , pfence   = FGround+  , ptopLeft = [ "··#·#··"+               , "#·····#"+               , "··<·>··"+               , "#·····#"+               , "··#·#··"+               ]+  }+staircase12 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·····"+               , "·<·>·"+               , "·····"+               ]+  }+staircase13 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·······"+               , "#·<·>·#"+               , "·······"+               ]+  }+staircase14 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·········"+               , "·#·<·>·#·"+               , "·········"+               ]+  }+staircase15 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "···········"+               , "#·I·<·>·I·#"+               , "···········"+               ]+  }+staircase16 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "#·····#"+               , "··<·>··"+               , "#·····#"+               ]+  }+staircase17 = staircaseLift+  { pfreq    = [("staircase lift", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·#·····#·"+               , "#··<·>··#"+               , "·#·····#·"+               ]+  }+staircaseOutdoor = staircase+  { pname     = "staircase outdoor"+  , pfreq     = [("staircase outdoor", 1)]+  , poverride = [('<', "staircase outdoor up"), ('>', "staircase outdoor down")]+  }+staircaseGated = staircase+  { pname     = "gated staircase"+  , pfreq     = [("gated staircase", 1)]+  , poverride = [('<', "gated staircase up"), ('>', "gated staircase down")]+  }+escapeUp = PlaceKind+  { psymbol  = '<'+  , pname    = "escape up"+  , pfreq    = [("escape up", 1)]+  , prarity  = [(1, 1)]+  , pcover   = CVerbatim+  , pfence   = FGround+  , ptopLeft = [ "<"+               ]+  , poverride = []+  }+escapeUp2 = escapeUp+  { pfreq    = [("escape up", 1000)]+  , pfence   = FFloor+  , ptopLeft = [ "#·#"+               , "·<·"+               , "#·#"+               ]+  }+escapeUp3 = escapeUp+  { pfreq    = [("escape down", 2000)]+  , pcover   = CMirror+  , pfence   = FFloor+  , ptopLeft = [ "#··"+               , "·<·"+               , "#·#"+               ]+  }+escapeUp4 = escapeUp+  { pfreq    = [("escape up", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·#·"+               , "#<#"+               , "·#·"+               ]+  }+escapeUp5 = escapeUp+  { pfreq    = [("escape up", 2000)]+  , pcover   = CMirror+  , pfence   = FWall+  , ptopLeft = [ "#··"+               , "·<·"+               , "··#"+               ]+  }+escapeDown = PlaceKind+  { psymbol  = '>'+  , pname    = "escape down"+  , pfreq    = [("escape down", 1)]+  , prarity  = [(1, 1)]+  , pcover   = CVerbatim+  , pfence   = FGround+  , ptopLeft = [ ">"+               ]+  , poverride = []+  }+escapeDown2 = escapeDown+  { pfreq    = [("escape down", 1000)]+  , pfence   = FFloor+  , ptopLeft = [ "#·#"+               , "·>·"+               , "#·#"+               ]+  }+escapeDown3 = escapeDown+  { pfreq    = [("escape down", 2000)]+  , pcover   = CMirror+  , pfence   = FFloor+  , ptopLeft = [ "#··"+               , "·>·"+               , "#·#"+               ]+  }+escapeDown4 = escapeDown+  { pfreq    = [("escape down", 1000)]+  , pfence   = FWall+  , ptopLeft = [ "·#·"+               , "#>#"+               , "·#·"+               ]+  }+escapeDown5 = escapeDown+  { pfreq    = [("escape down", 2000)]+  , pcover   = CMirror+  , pfence   = FWall+  , ptopLeft = [ "#··"+               , "·>·"+               , "··#"+               ]+  }+escapeOutdoorDown = escapeDown+  { pfreq     = [("escape outdoor down", 1)]+  , poverride = [('>', "escape outdoor down")]+  }++-- * Allure-specific++staircaseLift = staircase+  { pname    = "staircase lift"+  , pfreq    = [("staircase lift", 1)]+  , poverride = [ ('<', "staircase lift up"), ('>', "staircase lift down")+                , ('I', "signboard") ]+  }+escapeSpaceshipDown = escapeDown+  { pfreq     = [("escape spaceship down", 1)]+  , poverride = [('>', "escape spaceship down")]+  }+escapeSpaceshipDown2 = escapeDown2+  { pfreq     = [("escape spaceship down", 1000)]+  , poverride = [('>', "escape spaceship down")]+  }+escapeSpaceshipDown3 = escapeDown3+  { pfreq     = [("escape spaceship down", 2000)]+  , poverride = [('>', "escape spaceship down")]+  }+escapeSpaceshipDown4 = escapeDown4+  { pfreq     = [("escape spaceship down", 1000)]+  , poverride = [('>', "escape spaceship down")]+  }+escapeSpaceshipDown5 = escapeDown5+  { pfreq     = [("escape spaceship down", 1000)]+  , poverride = [('>', "escape spaceship down")]+  }+colonnadeWide = colonnade+  { prarity  = [(1, 2), (10, 2)]+  , pfence   = FWall+  , ptopLeft = [ "··"+               , "#·"+               ]+  } oval = PlaceKind   { psymbol  = 'o'   , pname    = "oval room"-  , pfreq    = [("rogue", 1000)]+  , pfreq    = [ ("rogue", 1000), ("arena", 1000), ("empty", 1000)+               , ("zoo", 1000), ("ambush", 1000) ]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FWall-  , ptopLeft = [ "####."-               , "##..."-               , "#...."-               , "#...."-               , "....."+  , ptopLeft = [ "####·"+               , "##···"+               , "#····"+               , "#····"+               , "·····"                ]   , poverride = []   }-ovalFloor = oval  -- Without outer solid fence, visible from outside.-  { pfreq    = [("rogue", 10000)]+ovalFloor = oval  -- Without outer solid fence, visible from outside·+  { pfreq    = [ ("rogue", 10000), ("arena", 10000), ("empty", 10000)+               , ("zoo", 10000), ("ambush", 10000) ]   , pfence   = FGround   , ptopLeft = [ "XXXX+#"-               , "XX###."-               , "X##..."-               , "X#...."-               , "+#...."-               , "#....."+               , "XX###·"+               , "X##···"+               , "X#····"+               , "+#····"+               , "#·····"                ]   } ovalSquare = ovalFloor-  { pfreq    = [("rogue", 3000)]+  { pfreq    = [ ("rogue", 3000), ("arena", 3000), ("empty", 3000)+               , ("zoo", 3000) , ("ambush", 3000) ]   , ptopLeft = [ "X###+"-               , "##..."-               , "#...."-               , "#...."-               , "+...."+               , "##···"+               , "#····"+               , "#····"+               , "+····"                ]   } maze = PlaceKind   { psymbol  = 'm'   , pname    = "maze"-  , pfreq    = [("rogue", 20)]+  , pfreq    = [("rogue", 20), ("arena", 20), ("empty", 20)]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FNone-  , ptopLeft = [ "#.#.##"-               , "##.#.."-               , "#.##.#"-               , "#.#.#."+  , ptopLeft = [ "·####"+               , "#·#··"+               , "##··#"+               , "#··#·"                ]-  , poverride = []+  , poverride = [('&', "cachable")]   } maze2 = maze-  { ptopLeft = [ "###.##"-               , ".###.."-               , "..#..#"-               , ".#..#."+  { pfreq    = [("rogue", 40), ("arena", 40), ("empty", 40)]+  , ptopLeft = [ "··####"+               , "##·##·"+               , "#·#··#"+               , "#···#·"                ]   } maze3 = maze-  { ptopLeft = [ "###.##"-               , ".##.#."-               , "..##.#"-               , ".#..#."+  { pfreq    = [("rogue", 70), ("arena", 70), ("empty", 70)]+  , ptopLeft = [ "·######"+               , "·##·##·"+               , "#··#···"+               , "#··#··#"                ]   } mazeBig = maze-  { pfreq    = [("rogue", 1000)]-  , ptopLeft = [ "#.#.##"-               , ".#.#.."-               , "#.&.##"-               , ".#.#.."-               , "#.#..#"-               , "#.#.#."+  { pfreq    = [("rogue", 500), ("arena", 500), ("empty", 500)]+  , ptopLeft = [ "··####"+               , "·#·#··"+               , "##&·##"+               , "##·##·"+               , "#·#··#"                ]   } mazeBig2 = mazeBig-  { ptopLeft = [ "##..##"-               , "#.##.."-               , ".#.###"-               , ".##.#."-               , "#.#&.#"-               , "#.#.#."+  { ptopLeft = [ "··####"+               , "##·##·"+               , "#·#&··"+               , "#·#··#"+               , "#···#·"                ]   } mazeBig3 = mazeBig-  { ptopLeft = [ "##..##"-               , "#.###."-               , ".#...#"-               , ".#.##."-               , "##.#.#"-               , "#.#.#."+  { pfreq    = [("rogue", 800), ("arena", 800), ("empty", 800)]+  , ptopLeft = [ "·######"+               , "#·##·#·"+               , "#·#·#··"+               , "##·##·#"+               , "#··#···"                ]   } cells = PlaceKind   { psymbol  = '#'   , pname    = "cells"-  , pfreq    = [("rogue", 100), ("noise", 100)]+  , pfreq    = [ ("rogue", 50), ("arena", 50), (" laboratory", 50)+               , ("empty", 50), ("noise", 50) ]   , prarity  = [(1, 10), (10, 10)]   , pcover   = CReflect   , pfence   = FWall-  , ptopLeft = [ "..#"-               , "..#"-               , "##."+  , ptopLeft = [ "··#"+               , "·#·"+               , "#··"                ]   , poverride = []   }--- TODO: obtain all the rest as places nested within places.--- 3 places are enough, with 1 or 2 tiles between places,--- on all sides, only vertical, only horizontal,+cells2 = cells+  { pfreq = ("zoo", 400) : pfreq cells+  , ptopLeft = [ "··#"+               , "··#"+               , "##·"+               ]+  }+cells3 = cells+  { ptopLeft = [ "#··"+               , "·#·"+               , "··#"+               ]+  }+cells4 = cells+  { pfreq = ("zoo", 400) : pfreq cells+  , ptopLeft = [ "··#"+               , "·##"+               , "#··"+               ]+  }+cells5 = cells+  { pfreq = ("zoo", 400) : pfreq cells+  , ptopLeft = [ "··#"+               , "·#·"+               , "##·"+               ]+  }+cells6 = cells+  { pfreq    = [ ("rogue", 1), ("arena", 2), ("laboratory", 2)+               , ("empty", 2), ("noise", 1), ("zoo", 100) ]+  , ptopLeft = [ "··#"+               , "##·"+               ]+  }+cells7 = cells+  { pfreq    = [ ("rogue", 1), ("arena", 2), (" laboratory", 2)+               , ("empty", 2), ("noise", 1) ]+  , pfence   = FFloor+  , ptopLeft = [ "#·#"+               , "·#·"+               ]+  }++-- * Helper functions++makeStaircaseUp :: PlaceKind -> PlaceKind+makeStaircaseUp s = s+ { psymbol   = '<'+ , pname     = pname s <+> "up"+ , pfreq     = map (\(t, k) -> (toGroupName $ tshow t <+> "up", k)) $ pfreq s+ , poverride = [ ('>', "stair terminal")+               , ('<', toGroupName $ pname s <+> "up")+               , ('I', "signboard") ]+ }++makeStaircaseDown :: PlaceKind -> PlaceKind+makeStaircaseDown s = s+ { psymbol   = '>'+ , pname     = pname s <+> "down"+ , pfreq     = map (\(t, k) -> (toGroupName $ tshow t <+> "down", k)) $ pfreq s+ , poverride = [ ('<', "stair terminal")+               , ('>', toGroupName $ pname s <+> "down")+               , ('I', "signboard") ]+ }
GameDefinition/Content/RuleKind.hs view
@@ -1,17 +1,24 @@ {-# LANGUAGE TemplateHaskell #-}--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game rules and assorted game setup data.-module Content.RuleKind ( cdefs ) where+module Content.RuleKind+  ( cdefs+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude+ import Language.Haskell.TH.Syntax import System.FilePath+import System.IO (readFile)  -- Cabal-import qualified Paths_Allure as Self (getDataFileName, version)+import qualified Paths_Allure as Self (version)  import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Content.RuleKind@@ -23,57 +30,41 @@   , getFreq = rfreq   , validateSingle = validateSingleRuleKind   , validateAll = validateAllRuleKind-  , content =+  , content = contentFromList       [standard]   }  standard :: RuleKind standard = RuleKind-  { rsymbol        = 's'-  , rname          = "standard Allure of the Stars ruleset"-  , rfreq          = [("standard", 100)]-  -- Check whether one position is accessible from another.-  -- Precondition: the two positions are next to each other-  -- and the target tile is walkable.-  -- TODO: in the future check flying for chasms, swimming for water, etc.-  , raccessible    = Nothing-  , raccessibleDoor = Nothing-  , rtitle         = "Allure of the Stars"-  , rpathsDataFile = Self.getDataFileName-  , rpathsVersion  = Self.version+  { rsymbol = 's'+  , rname = "standard Allure of the Stars ruleset"+  , rfreq = [("standard", 100)]+  , rtitle = "Allure of the Stars"+  , rexeVersion = Self.version   -- The strings containing the default configuration file   -- included from config.ui.default.-  , rcfgUIName = "config.ui"+  , rcfgUIName = "config.ui" <.> "ini"   , rcfgUIDefault = $(do       let path = "GameDefinition" </> "config.ui" <.> "default"       qAddDependentFile path       x <- qRunIO (readFile path)       lift x)   -- ASCII art for the Main Menu. Only pure 7-bit ASCII characters are-  -- allowed. The picture should be exactly 24 rows by 80 columns,-  -- plus an extra frame (of any characters) that is ignored.-  -- For a different screen size, the picture is centered and the outermost-  -- rows and columns cloned. When displayed in the Main Menu screen,-  -- it's overwritten with the game version string and keybinding strings.-  -- The game version string begins and ends with a space and is placed-  -- in the very bottom right corner. The keybindings overwrite places-  -- marked with 25 left curly brace signs '{' in a row. The sign is forbidden-  -- everywhere else. A specific number of such places with 25 left braces-  -- are required, at most one per row, and all are overwritten-  -- with text that is flushed left and padded with spaces.-  -- The Main Menu is displayed dull white on black.-  -- TODO: Show highlighted keybinding in inverse video or bright white on grey-  -- background. The spaces that pad keybindings are not highlighted.+  -- allowed. The picture should be exactly 24 rows by 80 columns.+  -- For a different screen size, the picture is centered and padded.+  -- with spaces. When displayed in the Main Menu screen, the picture+  -- is overwritten with game and engine version strings and keybindings.+  -- The keybindings overwrite places marked with left curly brace signs.+  -- The sign is forbidden anywhere else. The Main Menu is displayed dull+  -- white on black.   , rmainMenuArt = $(do       let path = "GameDefinition/MainMenu.ascii"       qAddDependentFile path       x <- qRunIO (readFile path)       lift x)   , rfirstDeathEnds = False-  , rfovMode = Digital-  , rwriteSaveClips = 500-  , rleadLevelClips = 100+  , rwriteSaveClips = 1000+  , rleadLevelClips = 50   , rscoresFile = "scores"-  , rsavePrefix = "save"   , rnearby = 20   }
GameDefinition/Content/TileKind.hs view
@@ -1,20 +1,22 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Terrain tile definitions.-module Content.TileKind ( cdefs ) where+module Content.TileKind+  ( cdefs+  ) where -import Control.Arrow (first)-import Data.Maybe+import Prelude ()++import Game.LambdaHack.Common.Prelude+ import qualified Data.Text as T  import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Common.Msg-import qualified Game.LambdaHack.Content.ItemKind as IK import Game.LambdaHack.Content.TileKind  cdefs :: ContentDef TileKind@@ -24,237 +26,563 @@   , getFreq = tfreq   , validateSingle = validateSingleTileKind   , validateAll = validateAllTileKind-  , content =-      [wall, wallCache, hardRock, doorlessWall, oriel, pillar, lampPost, burningBush, bush, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorArenaShade, floorRedLit, floorBlueLit, floorGreenLit]-      ++ map makeDarkColor [floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit]+  , content = contentFromList $+      [unknown, hardRock, wall, wallSuspect, wallObscured, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorArenaShade ]+      ++ map makeDarkColor ldarkColorable+      -- Allure-specific+      ++ [oriel, outerHullWall, doorlessWall, machineWall, wallObscuredDefaced, wallObscuredFrescoed, rock, stairsLiftUp, stairsLiftDown, escapeSpaceshipDown]   }-wall,        wallCache, hardRock, doorlessWall, oriel, pillar, lampPost, burningBush, bush, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorArenaShade, floorRedLit, floorBlueLit, floorGreenLit :: TileKind+unknown,        hardRock, wall, wallSuspect, wallObscured, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorArenaShade :: TileKind+-- Allure-specific+oriel, outerHullWall, doorlessWall, machineWall, wallObscuredDefaced, wallObscuredFrescoed, rock, stairsLiftUp, stairsLiftDown, escapeSpaceshipDown :: TileKind -oriel = TileKind-  { tsymbol  = '\''-  , tname    = "oriel"-  , tfreq    = [("oriels fence", 4)]-  , tcolor   = White-  , tcolor2  = Black-  , tfeature = [Dark, Impenetrable]+ldarkColorable :: [TileKind]+ldarkColorable = [tree, bush, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem]++-- Symbols to be used:+--         LOS    noLOS+-- Walk    .'     :;+-- noWalk  %^     #O&<>++--+-- can be opened ^&++-- can be closed '+-- some noWalk can be changed without opening, regardless of symbol+-- not used yet:+-- ~ (water, acid, ect.)+-- : (curtain, etc., not flowing, but solid and static)+-- ` (not visible enough, would need font modification)++-- Note that for AI hints and UI comfort, most multiple-use @Embed@ tiles+-- should have a variant, which after first use transforms into a different+-- colour tile without @ChangeTo@ and similar (which then AI no longer touches).+-- If a tile is supposed to be repeatedly activated by AI (e.g., cache),+-- it should keep @ChangeTo@ for the whole time.++-- * Main tiles, modified for Allure; some removed++-- ** Not walkable++-- *** Not clear++unknown = TileKind  -- needs to have index 0 and alter 1+  { tsymbol  = ' '+  , tname    = "unknown space"+  , tfreq    = [("unknown space", 1)]+  , tcolor   = defFG+  , tcolor2  = defFG+  , talter   = 1+  , tfeature = [Dark]   }+hardRock = TileKind+  { tsymbol  = '#'+  , tname    = "habitat containment wall"+  , tfreq    = [("basic outer fence", 1)]+  , tcolor   = BrBlack+  , tcolor2  = BrBlack+  , talter   = maxBound  -- impenetrable+  , tfeature = []+  } wall = TileKind   { tsymbol  = '#'-  , tname    = "granite wall"+  , tname    = "wall"   , tfreq    = [ ("fillerWall", 1), ("legendLit", 100), ("legendDark", 100)-               , ("cachable", 70)-               , ("noiseSet", 100), ("battleSet", 250) ]+               , ("cachable", 80), ("stair terminal", 100)+               , ("battleSet", 250), ("rectWindowsOver_%_Lit", 80) ]   , tcolor   = BrWhite   , tcolor2  = defFG-  , tfeature = [HideAs "suspect wall"]+  , talter   = 100+  , tfeature = [BuildAs "suspect wall", Indistinct]   }-hardRock = TileKind+wallSuspect = TileKind  -- only on client   { tsymbol  = '#'-  , tname    = "outer hull"-  , tfreq    = [("basic outer fence", 100), ("oriels fence", 96)]-  , tcolor   = BrBlack-  , tcolor2  = BrBlack-  , tfeature = [Impenetrable]+  , tname    = "suspect uneven wall"+  , tfreq    = [("suspect wall", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , talter   = 2+  , tfeature = [ RevealAs "trapped door"+               , ObscureAs "obscured wall"+               , Indistinct ]   }-doorlessWall = TileKind+wallObscured = TileKind   { tsymbol  = '#'-  , tname    = "granite wall"-  , tfreq    = [("doorlessWallOver_#", 100)]+  , tname    = "scratched wall"+  , tfreq    = [("obscured wall", 100)]   , tcolor   = BrWhite   , tcolor2  = defFG-  , tfeature = []+  , talter   = 5+  , tfeature = [ Embed "scratch on wall"+               , HideAs "suspect wall"+               , Indistinct+               ]   } pillar = TileKind   { tsymbol  = 'O'-  , tname    = "rock"-  , tfreq    = [ ("legendLit", 100), ("legendDark", 100)-               , ("skirmishSet", 5) ]-  , tcolor   = BrWhite-  , tcolor2  = defFG-  , tfeature = []+  , tname    = "pillar"+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]+  , tcolor   = BrCyan  -- not BrWhite, to tell from heroes+  , tcolor2  = Cyan+  , talter   = 100+  , tfeature = [Indistinct]   }-wallCache = TileKind-  { tsymbol  = '&'+pillarCache = TileKind+  { tsymbol  = '#'   , tname    = "cache"-  , tfreq    = [ ("cachable", 30)-               , ("legendLit", 100), ("legendDark", 100) ]-  , tcolor   = BrWhite-  , tcolor2  = defFG-  , tfeature = [ Cause $ IK.CreateItem CGround "useful" IK.TimerNone-               , ChangeTo "cachable" ]+  , tfreq    = [("cachable", 20), ("stair terminal", 1), ("escapeSetDark", 1)]+  , tcolor   = BrBlue+  , tcolor2  = Blue+  , talter   = 5+  , tfeature = [ Embed "terrain cache", Embed "terrain cache trap"+               , ChangeTo "cachable", ConsideredByAI, Indistinct ]+      -- Not explorable, but prominently placed, so hard to miss.+      -- Very beneficial, so AI eager to trigger.   } lampPost = TileKind   { tsymbol  = 'O'   , tname    = "lamp post"-  , tfreq    = [("lampPostOver_O", 90)]+  , tfreq    = [("lampPostOver_O", 1)]   , tcolor   = BrYellow   , tcolor2  = Brown+  , talter   = 100   , tfeature = []   }-burningBush = TileKind+signboardUnread = TileKind  -- client only, indicates never used by this faction   { tsymbol  = 'O'-  , tname    = "burning bush"-  , tfreq    = [("lampPostOver_O", 10), ("ambushSet", 3), ("battleSet", 2)]-  , tcolor   = BrRed-  , tcolor2  = Red-  , tfeature = []+  , tname    = "signboard"+  , tfreq    = [("signboard unread", 1)]+  , tcolor   = BrCyan+  , tcolor2  = Cyan+  , talter   = 5+  , tfeature = [ Embed "signboard", Indistinct+               , ConsideredByAI  -- changes after use, so safe for AI+               , RevealAs "signboard" ]  -- to display as hidden   }-bush = TileKind+signboardRead = TileKind  -- after first use revealed to be this one   { tsymbol  = 'O'-  , tname    = "bush"-  , tfreq    = [("ambushSet", 100) ]-  , tcolor   = Green-  , tcolor2  = BrBlack-  , tfeature = [Dark]+  , tname    = "signboard"+  , tfreq    = [("signboard", 1), ("zooSet", 2), ("ambushSet", 1)]+  , tcolor   = BrCyan+  , tcolor2  = Cyan+  , talter   = 5+  , tfeature = [Embed "signboard", HideAs "signboard unread", Indistinct]   } tree = TileKind   { tsymbol  = 'O'   , tname    = "tree"-  , tfreq    = [("skirmishSet", 14), ("battleSet", 20), ("treeShadeOver_O", 1)]+  , tfreq    = [ ("brawlSetLit", 140), ("shootoutSetLit", 10)+               , ("escapeSetLit", 30), ("treeShadeOver_O_Lit", 1) ]   , tcolor   = BrGreen   , tcolor2  = Green+  , talter   = 50   , tfeature = []   }-wallSuspect = TileKind-  { tsymbol  = '#'-  , tname    = "moldy wall"-  , tfreq    = [("suspect wall", 1)]-  , tcolor   = BrWhite-  , tcolor2  = defFG-  , tfeature = [Suspect, RevealAs "closed door"]+treeBurnt = tree+  { tname    = "burnt tree"+  , tfreq    = [("zooSet", 3), ("tree with fire", 30)]+  , tcolor   = BrBlack+  , tcolor2  = BrBlack+  , tfeature = Dark : tfeature tree   }+treeBurning = tree+  { tname    = "burning tree"+  , tfreq    = [("zooSet", 30), ("tree with fire", 70)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , talter   = 5+  , tfeature = Embed "big fire" : ChangeTo "tree with fire" : tfeature tree+      -- dousing off the tree will have more sense when it periodically+      -- explodes, hitting and lighting up the team and so betraying it+  }+rubble = TileKind+  { tsymbol  = '&'+  , tname    = "rubble"+  , tfreq    = []  -- [("floorCorridorLit", 1)]+                   -- disabled while it's all or nothing per cave and per room;+                   -- we need a new mechanism, Spice is not enough, because+                   -- we don't want multicolor trailLit corridors+      -- ("rubbleOrNot", 70)+      -- until we can sync change of tile and activation, it always takes 1 turn+  , tcolor   = BrYellow+  , tcolor2  = Brown+  , talter   = 5+  , tfeature = [OpenTo "rubbleOrNot", Embed "rubble", Indistinct]+  }+rubbleSpice = TileKind+  { tsymbol  = '&'+  , tname    = "rubble"+  , tfreq    = [ ("smokeClumpOver_f_Lit", 1), ("emptySet", 1), ("noiseSet", 10)+               , ("zooSet", 100), ("ambushSet", 20) ]+  , tcolor   = BrYellow+  , tcolor2  = Brown+  , talter   = 5+  , tfeature = [Spice, OpenTo "rubbleSpiceOrNot", Embed "rubble", Indistinct]+      -- It's not explorable, due to not being walkable nor clear and due+      -- to being a door (@OpenTo@), which is kind of OK, because getting+      -- the item is risky and, e.g., AI doesn't attempt it.+      -- Also, AI doesn't go out of its way to clear the way for heroes.+  }+doorTrapped = TileKind+  { tsymbol  = '+'+  , tname    = "trapped door"+  , tfreq    = [("trapped door", 1)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , talter   = 2+  , tfeature = [ Embed "doorway trap"+               , OpenTo "open door"+               , HideAs "suspect wall"+               ]+  } doorClosed = TileKind   { tsymbol  = '+'   , tname    = "closed door"   , tfreq    = [("legendLit", 100), ("legendDark", 100), ("closed door", 1)]   , tcolor   = Brown   , tcolor2  = BrBlack-  , tfeature = [OpenTo "open door", HideAs "suspect wall"]-  }-doorOpen = TileKind-  { tsymbol  = '\''-  , tname    = "open door"-  , tfreq    = [("legendLit", 100), ("legendDark", 100), ("open door", 1)]-  , tcolor   = Brown-  , tcolor2  = BrBlack-  , tfeature = [Walkable, Clear, NoItem, NoActor, CloseTo "closed door"]+  , talter   = 2+  , tfeature = [OpenTo "open door"]  -- never hidden   } stairsUp = TileKind   { tsymbol  = '<'   , tname    = "staircase up"-  , tfreq    = []  -- TODO: [("legendLit", 100), ("legendDark", 100)]+  , tfreq    = [("staircase up", 9), ("ordinary staircase up", 1)]   , tcolor   = BrWhite   , tcolor2  = defFG-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend 1]+  , talter   = talterForStairs+  , tfeature = [Embed "staircase up", ConsideredByAI]   }+stairsTaintedUp = TileKind+  { tsymbol  = '<'+  , tname    = "tainted staircase up"+  , tfreq    = [("staircase up", 1)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , talter   = talterForStairs+  , tfeature = [ Embed "staircase up", Embed "staircase trap up"+               , ConsideredByAI, ChangeTo "ordinary staircase up" ]+                 -- AI uses despite the trap; exploration more important+  }+stairsOutdoorUp = stairsUp+  { tname    = "signpost pointing backward"+  , tfreq    = [("staircase outdoor up", 1)]+  }+stairsGatedUp = stairsUp+  { tname    = "gated staircase up"+  , tfreq    = [("gated staircase up", 1)]+  , talter   = talterForStairs + 1  -- animals and bosses can't use+  } stairsDown = TileKind   { tsymbol  = '>'   , tname    = "staircase down"-  , tfreq    = []  -- TODO: [("legendLit", 100), ("legendDark", 100)]+  , tfreq    = [("staircase down", 9), ("ordinary staircase down", 1)]   , tcolor   = BrWhite   , tcolor2  = defFG-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend (-1)]+  , talter   = talterForStairs+  , tfeature = [Embed "staircase down", ConsideredByAI]   }+stairsTaintedDown = TileKind+  { tsymbol  = '>'+  , tname    = "tainted staircase down"+  , tfreq    = [("staircase down", 1)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , talter   = talterForStairs+  , tfeature = [ Embed "staircase down", Embed "staircase trap down"+               , ConsideredByAI, ChangeTo "ordinary staircase down" ]+  }+stairsOutdoorDown = stairsDown+  { tname    = "signpost pointing forward"+  , tfreq    = [("staircase outdoor down", 1)]+  }+stairsGatedDown = stairsDown+  { tname    = "gated staircase down"+  , tfreq    = [("gated staircase down", 1)]+  , talter   = talterForStairs + 1  -- animals and bosses can't use+  } escapeUp = TileKind   { tsymbol  = '<'-  , tname    = "airlock to the shuttle"-  , tfreq    = [("legendLit", 100), ("legendDark", 100)]+  , tname    = "exit hatch up"+  , tfreq    = [("legendLit", 1), ("legendDark", 1)]   , tcolor   = BrYellow   , tcolor2  = BrYellow-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Escape 1]+  , talter   = 0  -- anybody can escape (or guard escape)+  , tfeature = [Embed "escape", ConsideredByAI]   } escapeDown = TileKind   { tsymbol  = '>'-  , tname    = "airlock to the shuttle"-  , tfreq    = [("legendLit", 100), ("legendDark", 100)]+  , tname    = "exit trapdoor down"+  , tfreq    = [("legendLit", 1), ("legendDark", 1)]   , tcolor   = BrYellow   , tcolor2  = BrYellow-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Escape (-1)]+  , talter   = 0  -- anybody can escape (or guard escape)+  , tfeature = [Embed "escape", ConsideredByAI]   }-liftUp = TileKind-  { tsymbol  = '<'-  , tname    = "lift up"-  , tfreq    = [("legendLit", 100), ("legendDark", 100)]-  , tcolor   = BrCyan-  , tcolor2  = BrCyan-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend 1]+escapeOutdoorDown = escapeDown+  { tname    = "exit back to town"+  , tfreq    = [("escape outdoor down", 1)]   }-lift = TileKind-  { tsymbol  = '<'-  , tname    = "lift"-  , tfreq    = [("legendLit", 100), ("legendDark", 100)]++-- *** Clear++wallGlass = TileKind+  { tsymbol  = '%'+  , tname    = "transparent polymer wall"+  , tfreq    = [("glasshouseOver_%_Lit", 1)]   , tcolor   = BrBlue-  , tcolor2  = BrBlue-  , tfeature = [ Walkable, Clear, NoItem, NoActor-               , Cause $ IK.Ascend 1-               , Cause $ IK.Ascend (-1) ]+  , tcolor2  = Blue+  , talter   = 10+  , tfeature = [BuildAs "suspect wall", Clear]   }-liftDown = TileKind-  { tsymbol  = '>'-  , tname    = "lift down"-  , tfreq    = [("legendLit", 100), ("legendDark", 100)]+wallGlassSpice = wallGlass+  { tfreq    = [("rectWindowsOver_%_Lit", 20)]+  , tfeature = Spice : tfeature wallGlass+  }+pillarIce = TileKind+  { tsymbol  = '^'+  , tname    = "ice"+  , tfreq    = [("brawlSetLit", 20)]+  , tcolor   = BrBlue+  , tcolor2  = Blue+  , talter   = 5+  , tfeature = [Clear, Embed "frost", OpenTo "damp stone floor"]+      -- Is door, due to @OpenTo@, so is not explorable, but it's OK, because+      -- it doesn't generate items nor clues. This saves on the need to+      -- get each ice pillar into sight range when exploring level.+  }+pulpit = TileKind+  { tsymbol  = '%'+  , tname    = "VR harness"+  , tfreq    = [("pulpit", 1), ("zooSet", 2)]+  , tcolor   = BrYellow+  , tcolor2  = Brown+  , talter   = 5+  , tfeature = [Clear, Embed "pulpit", Indistinct]+                 -- mixed blessing, so AI ignores, saved for player fun+  }+bush = TileKind+  { tsymbol  = '%'+  , tname    = "bush"+  , tfreq    = [ ("bush Lit", 1), ("shootoutSetLit", 30), ("escapeSetLit", 30)+               , ("arenaSetLit", 3), ("bushClumpOver_f_Lit", 1) ]+  , tcolor   = BrGreen+  , tcolor2  = Green+  , talter   = 10+  , tfeature = [Clear]+  }+bushBurnt = bush+  { tname    = "burnt bush"+  , tfreq    = [ ("battleSet", 30), ("ambushSet", 4), ("zooSet", 30)+               , ("bush with fire", 70) ]+  , tcolor   = BrBlack+  , tcolor2  = BrBlack+  , tfeature = Dark : tfeature bush+  }+bushBurning = bush+  { tname    = "burning bush"+  , tfreq    = [("ambushSet", 40), ("zooSet", 300), ("bush with fire", 30)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , talter   = 5+  , tfeature = Embed "small fire" : ChangeTo "bush with fire" : tfeature bush+  }++-- ** Walkable++-- *** Not clear++floorFog = TileKind+  { tsymbol  = ';'+  , tname    = "faint fog"+  , tfreq    = [ ("lit fog", 1), ("emptySet", 5), ("shootoutSetLit", 20)+               , ("noiseSet", 10), ("fogClumpOver_f_Lit", 60) ]+      -- lit fog is OK for shootout, because LOS is mutual, as opposed+      -- to dark fog, and so camper has little advantage, especially+      -- on big maps, where he doesn't know on which side of fog patch to hide   , tcolor   = BrCyan-  , tcolor2  = BrCyan-  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend (-1)]+  , tcolor2  = Cyan+  , talter   = 0+  , tfeature = [Walkable, NoItem, Indistinct, OftenActor]   }-unknown = TileKind-  { tsymbol  = ' '-  , tname    = "unknown space"-  , tfreq    = [("unknown space", 1)]-  , tcolor   = defFG-  , tcolor2  = defFG-  , tfeature = [Dark]+floorFogDark = floorFog+  { tname    = "thick fog"+  , tfreq    = [("noiseSet", 10), ("escapeSetDark", 60)]+  , tfeature = Dark : tfeature floorFog   }-floorCorridorLit = TileKind-  { tsymbol  = '.'+floorSmoke = TileKind+  { tsymbol  = ';'+  , tname    = "billowing smoke"+  , tfreq    = [ ("lit smoke", 1)+               , ("ambushSet", 30), ("zooSet", 30), ("battleSet", 5)+               , ("labTrailLit", 1), ("stair terminal", 2)+               , ("smokeClumpOver_f_Lit", 1) ]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , talter   = 0+  , tfeature = [Walkable, NoItem, Indistinct]  -- not dark, embers+  }+floorSmokeDark = floorSmoke+  { tname    = "lingering smoke"+  , tfreq    = [("ambushSet", 30)]+  , tfeature = Dark : tfeature floorSmoke+  }++-- *** Clear++doorOpen = TileKind+  { tsymbol  = '\''+  , tname    = "open door"+  , tfreq    = [("legendLit", 100), ("legendDark", 100), ("open door", 1)]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , talter   = 4+  , tfeature = [ Walkable, Clear, NoItem, NoActor+               , CloseTo "closed door"+               ]+  }+floorCorridor = TileKind+  { tsymbol  = floorSymbol   , tname    = "floor"-  , tfreq    = [ ("floorCorridorLit", 1), ("floorArenaLit", 1)-               , ("arenaSet", 1), ("emptySet", 1), ("noiseSet", 50)-               , ("battleSet", 1000), ("skirmishSet", 100)-               , ("ambushSet", 1000) ]+  , tfreq    = [("floorCorridorLit", 99), ("rubbleOrNot", 30)]   , tcolor   = BrWhite   , tcolor2  = defFG-  , tfeature = [Walkable, Clear]+  , talter   = 0+  , tfeature = [Walkable, Clear, Indistinct]   }-floorActorLit = floorCorridorLit-  { tfreq    = [("floorActorLit", 1)]-  , tfeature = OftenActor : tfeature floorCorridorLit+floorArena = floorCorridor+  { tfreq    = [ ("floorArenaLit", 1), ("rubbleSpiceOrNot", 30)+               , ("arenaSetLit", 96), ("emptySet", 94), ("zooSet", 1000) ]   }-floorItemLit = floorCorridorLit-  { tfreq    = []-  , tfeature = OftenItem : tfeature floorCorridorLit+floorNoise = floorArena+  { tname    = "oily floor"+  , tfreq    = [("noiseSet", 60), ("damp stone floor", 1)]   }-floorActorItemLit = floorItemLit-  { tfreq    = [("legendLit", 100)]-  , tfeature = OftenActor : tfeature floorItemLit+floorDirt = floorArena+  { tname    = "dirt"+  , tfreq    = [ ("battleSet", 1000), ("brawlSetLit", 1000)+               , ("shootoutSetLit", 1000), ("escapeSetLit", 1000)+               , ("ambushSet", 1000) ]   }-floorArenaShade = floorActorLit-  { tname    = "floor"  -- TODO: "shaded ground"-  , tfreq    = [("treeShadeOver_s", 1)]-  , tcolor2  = BrBlack-  , tfeature = Dark : tfeature floorActorLit  -- no OftenItem+floorDirtSpice = floorDirt+  { tfreq    = [ ("treeShadeOver_s_Lit", 1), ("fogClumpOver_f_Lit", 40)+               , ("smokeClumpOver_f_Lit", 1), ("bushClumpOver_f_Lit", 1) ]+  , tfeature = Spice : tfeature floorDirt   }-floorRedLit = floorCorridorLit+floorActor = floorArena+  { tfreq    = [("floorActorLit", 1)]  -- lit even in dark cave, so no items+  , tfeature = OftenActor : tfeature floorArena+  }+floorActorItem = floorActor+  { tfreq    = [("legendLit", 100)]+  , tfeature = OftenItem : tfeature floorActor+  }+floorRed = floorCorridor   { tname    = "emergency walkway"   , tfreq    = [("emergency walkway", 1), ("trailLit", 20)]   , tcolor   = BrRed   , tcolor2  = Red-  , tfeature = Trail : tfeature floorCorridorLit+  , tfeature = Trail : tfeature floorCorridor  -- no Indistinct   }-floorBlueLit = floorRedLit+floorBlue = floorRed   { tname    = "transport route"   , tfreq    = [("trailLit", 100)]   , tcolor   = BrBlue   , tcolor2  = Blue   }-floorGreenLit = floorRedLit+floorGreen = floorRed   { tname    = "greenery trail"   , tfreq    = [("trailLit", 100)]   , tcolor   = BrGreen   , tcolor2  = Green   }+floorArenaShade = floorActor+  { tname    = "shaded ground"+  , tfreq    = [("shaded ground", 1), ("treeShadeOver_s_Lit", 2)]+  , tcolor2  = BrBlack+  , tfeature = Dark : NoItem : tfeature floorActor+  } +-- * Allure-specific +-- ** Not walkable++oriel = TileKind+  { tsymbol  = '%'  -- story-wise it's transparent, hence the symbol+  , tname    = "oriel"+  , tfreq    = [("oriels fence", 4)]+  , tcolor   = White+  , tcolor2  = Black+  , talter   = maxBound  -- impenetrable+  , tfeature = [Dark, Indistinct]+  }+outerHullWall = hardRock+  { tname    = "outer hull wall"+  , tfreq    = [("oriels fence", 96), ("noise fence", 1)]+  }+doorlessWall = TileKind+  { tsymbol  = '#'+  , tname    = "wall"+  , tfreq    = [("noiseSet", 60), ("doorlessWallOver_#", 20)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , talter   = 100+  , tfeature = [HideAs "fillerWall", Indistinct]+  }+machineWall = TileKind+  { tsymbol  = '%'+  , tname    = "hardware rack"+  , tfreq    = [("noiseSet", 35), ("doorlessWallOver_#", 80)]+  , tcolor   = White+  , tcolor2  = BrBlack+  , talter   = 100+  , tfeature = [Spice, Clear, Indistinct]+  }+wallObscuredDefaced = TileKind+  { tsymbol  = '#'+  , tname    = "defaced wall"+  , tfreq    = [("obscured wall", 45), ("escapeSetDark", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , talter   = 5+  , tfeature = [ Embed "obscene pictograms"+               , HideAs "suspect wall"+               , Indistinct+               ]+  }+wallObscuredFrescoed = TileKind+  { tsymbol  = '#'+  , tname    = "subtle mural"+  , tfreq    = [("obscured wall", 5), ("brawlSetLit", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , talter   = 5+  , tfeature = [ Embed "subtle fresco"+               , HideAs "suspect wall"+               , Indistinct+               ]+  }+rock = pillar+  { tname    = "rock"+  , tfreq    = [("brawlSetLit", 30), ("arenaSetLit", 1), ("arenaSetDark", 1)]+  }+stairsLiftUp = stairsUp+  { tname    = "lift up"+  , tfreq    = [("staircase lift up", 1)]+  }+stairsLiftDown = stairsDown+  { tname    = "lift down"+  , tfreq    = [("staircase lift down", 1)]+  }+escapeSpaceshipDown = escapeDown+  { tname    = "airlock to the shuttle"+  , tfreq    = [("escape spaceship down", 1)]+  }++-- ** Walkable++-- none++-- * Helper functions+ makeDark :: TileKind -> TileKind makeDark k = let darkText :: GroupName TileKind -> GroupName TileKind                  darkText t = maybe t (toGroupName . (<> "Dark"))@@ -264,7 +592,9 @@                  darkFeat (CloseTo t) = Just $ CloseTo $ darkText t                  darkFeat (ChangeTo t) = Just $ ChangeTo $ darkText t                  darkFeat (HideAs t) = Just $ HideAs $ darkText t+                 darkFeat (BuildAs t) = Just $ BuildAs $ darkText t                  darkFeat (RevealAs t) = Just $ RevealAs $ darkText t+                 darkFeat (ObscureAs t) = Just $ ObscureAs $ darkText t                  darkFeat OftenItem = Nothing  -- items not common in the dark                  darkFeat feat = Just feat              in k { tfreq    = darkFrequency@@ -272,6 +602,8 @@                   }  makeDarkColor :: TileKind -> TileKind-makeDarkColor k = (makeDark k) { tcolor  = BrYellow+makeDarkColor k = (makeDark k) { tcolor  = if tsymbol k == floorSymbol+                                           then BrYellow+                                           else tcolor k                                , tcolor2 = BrBlack                                }
+ GameDefinition/InGameHelp.txt view
@@ -0,0 +1,178 @@+This is a snapshot of in-game help, rendered with default config file.+For more general gameplay information see PLAYING.md.+++Minimal cheat sheet for casual play (1/2).++ Walk throughout a level with mouse or numeric keypad (left diagram below)+ or its compact laptop replacement (middle) or the Vi text editor keys (right,+ enabled in config.ui.ini). Run, until disturbed, by adding Shift or Control.+ Go-to with LMB (left mouse button). Run collectively with RMB.++                7 8 9          7 8 9          y k u+                 \|/            \|/            \|/+                4-5-6          u-i-o          h-.-l+                 /|\            /|\            /|\+                1 2 3          j k l          b j n++ In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair).+ Press 'KP_5' ('5' on keypad, if present) 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 wait 0.1 of a turn, without bracing.+ You displace enemies by running into them with Shift/Control or RMB. Search,+ open, descend and attack by bumping into walls, doors, stairs and enemies.+ The best item to attack with is automatically chosen from among+ weapons in your personal equipment and your unwounded organs.+++Minimal cheat sheet for casual play (2/2).++ The following commands, joined with the basic set above, let you accomplish+ anything in the game, though not necessarily with the fewest keystrokes.+ You can also play the game exclusively with a mouse, or both mouse and+ keyboard. See the ending help screens for mouse commands.+ Lastly, you can select a command with arrows or mouse directly from the help+ screen and execute it on the spot.++ keys         command+ g or ,       grab item(s)+ c            close door+ P            manage item pack of the leader+ KP_* or !    cycle x-hair among enemies+ +            swerve the aiming line+ ESC          cancel aiming/open Main Menu+ RET or INS   accept target/open Help+ SPACE        clear messages/display history+ S-TAB        cycle among all party members+ =            select (or deselect) party member+++All terrain exploration and alteration commands.++ keys         command+ g or ,       grab item(s)+ d or .       drop item(s)+ ;            go to x-hair for 25 steps+ :            run to x-hair collectively for 25 steps+ x            explore nearest unknown spot+ X            autoexplore 25 times+ R            rest (wait 25 times)+ C-R          lurk (wait 0.1 turns 100 times)+ c            close door+++Item Menu commands.++ keys         command+ g or ,       grab item(s)+ d or .       drop item(s)+ f            fling projectile+ C-f          fling without aiming+ a            apply consumable+ C-a          apply and keep choice+ p            pack item+ e            equip item+ s            stash and share item+++Remaining item-related commands.++ keys         command+ ^            sort items by kind and stats+ P            manage item pack of the leader+ G            manage items on the ground+ E            manage equipment of the leader+ S            manage the shared party stash+ A            manage all owned items+ @            describe organs of the leader+ #            show stat summary of the leader+ ~            display known lore+ q            quaff potion+ r            read scroll+ t            throw missile+++Aiming.++ keys         command+ KP_* or !    cycle x-hair among enemies+ KP_/ or /    cycle x-hair among items+ \            cycle aiming modes+ +            swerve the aiming line+ -            unswerve the aiming line+ C-?          set x-hair to nearest unknown spot+ C-I          set x-hair to nearest item+ C-{          set x-hair to nearest upstairs+ C-}          set x-hair to nearest downstairs+ <            move aiming one level higher+ >            move aiming one level lower+ BACKSPACE    clear chosen item and target+ ESC          cancel aiming/open Main Menu+ RET or INS   accept target/open Help+++Assorted.++ keys         command+ SPACE        clear messages/display history+ ? or F1      display Help+ TAB          cycle among party members on the level+ S-TAB        cycle among all party members+ =            select (or deselect) party member+ _            deselect (or select) all on the level+ v            voice again the recorded commands+ V            voice recorded commands 100 times+ C-v          voice recorded commands 1000 times+ C-V          voice recorded commands 25 times+ '            start recording commands+ 0, 1 ... 6   pick a particular actor as the new leader+++Mouse overview.++ Screen area and UI mode (aiming/exploration) determine mouse click effects.+ Here is an overview of effects of each button over most of the game map area.+ The list includes not only left and right buttons, but also the optional+ middle mouse button (MMB) and even the mouse wheel, which is normally used+ over menus, to page-scroll them, rather than over game map.+ For mice without RMB, one can use C-LMB (Control key and left mouse button).++ keys         command+ LMB          set x-hair to enemy/go to pointer for 25 steps+ RMB or C-LMB fling at enemy/run to pointer collectively for 25 steps+ C-RMB        open or close door+ MMB          snap x-hair to floor under pointer+ WHEEL-UP     swerve the aiming line+ WHEEL-DN     unswerve the aiming line+++Mouse in aiming mode.++ area           LMB (left mouse button)          RMB (right mouse button)+ message line   clear messages/display history   display known lore+ the map area   set x-hair to enemy              fling at enemy under pointer+ level number   move aiming one level higher     move aiming one level lower+ level caption  accept target                    cancel aiming+ percent seen   set x-hair to nearest upstairs   set x-hair to nearest downstai$+ x-hair info    cycle x-hair among enemies       cycle x-hair among items+ party roster   pick new leader on screen        select party member on screen+ Calm gauge     rest (wait 25 times)             lurk (wait 0.1 turns 100 times)+ HP gauge       wait a turn, bracing for impact  wait 0.1 of a turn+ target info    manage item pack of the leader   clear chosen item and target+++Mouse in exploration mode.++ area           LMB (left mouse button)          RMB (right mouse button)+ message line   clear messages/display history   display known lore+ leader on map  grab item(s)                     drop item(s)+ party on map   pick new leader on screen        select party member on screen+ the map area   go to pointer for 25 steps       run to pointer collectively+ level number   move aiming one level higher     move aiming one level lower+ level caption  display Help                     open Main Menu+ percent seen   explore nearest unknown spot     autoexplore 25 times+ x-hair info    cycle x-hair among enemies       cycle x-hair among items+ party roster   pick new leader on screen        select party member on screen+ Calm gauge     rest (wait 25 times)             lurk (wait 0.1 turns 100 times)+ HP gauge       wait a turn, bracing for impact  wait 0.1 of a turn+ target info    manage item pack of the leader   fling without aiming
GameDefinition/Main.hs view
@@ -1,12 +1,19 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | The main source code file of Allure of the Stars. -- Module "TieKnot" is separated to make it usable in tests.-module Main ( main ) where+module Main+  ( main+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude++import Control.Concurrent.Async import System.Environment (getArgs)  import TieKnot@@ -16,4 +23,6 @@ main :: IO () main = do   args <- getArgs-  tieKnot args+  -- Avoid the bound thread that would slow down the communication.+  a <- async $ tieKnot args+  wait a
GameDefinition/MainMenu.ascii view
@@ -1,26 +1,24 @@------------------------------------------------------------------------------------|                                                                                |-|                      >> Allure of the Stars <<                                 |-|                                                                                |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |-|                                                                                |-|                                                                                |-|                        Version X.X.X (frontend: gtk, engine: LambdaHack X.X.X) |-----------------------------------------------------------------------------------+... jiii;.LGEDEi.  . .   .    .   ;KEKEGLLGEDt                :tfL:,ittjjjjfffff+.. tii;,iGEWDL;    .      .  .    . fEDEDGfLDDG              . Lf.;itjjjfffLLLLf+.tti;, GDKLt,        . . .    . .   ,itLDEGLLGED.           :.fi.;ttjjfffLEWW#DL+.tti;::GELti    Allure of the Stars  .KtGDEDLfGEDt        ...j;:;ttjjffLD#WWW#Kf+.tti;.jGDt                  .  .  ..   ,LDEDLfGEDt      ...t.:itjjfffL WWWWW#K;+jtti,iLDLt                            .  ;jDEEGLGEDt      ,t :itjjffLG  WKWWWWE+jtii: GEf;                                ,iGDEDGGEDt.   tt :itjjffLG  GWEWWWKE+jtii: GGj;   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{.fGDEDGLDDt  tt :itjfffLG   KKKWWWEL+jtti. GDj,   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{  DLDEDGLDD.tj :itjjffLD   LWDKWWWD+jtti  GDj,   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{   ELDEDGL.jj :itjjffLD   jKDEWWWEL+jtti  GGf,   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{    ELDEE.ff::itjjffLG   fKEDKWKKD+ftti  LGt:   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{     ELE.Lf: ijjjffLG   tEEDEWKWG+fjjt.,jGf,   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{     ,K:Gf,.ijjtffLD..tjEDGDKKWEE+tti;,i;GL.   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{     .:ftt itiiffLGDGDDDGLDKGKfE+Ltjt;, jLj   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{     :Lf;iitjifLLGfDDLijGEKEKDE..+Lffjif.Lft   {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{  .,:LL;,ijjfffLGLGLLLGDKKEELK . .+ffjt iiGfj;  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{...:LL;;ijffffLGDEKKKKKEEKDj.......+.Lffj:j fDi  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{:::fL;,itjfffLGLGDEEDEKDGtK..........+. Lfffifiif  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{,.Lf;.ijjfffLL,,Lfijjt,E,::..........+.  fffj:i;t;                              .tfj,.tjjfffLL;ijfLGGGGGLjt;,::......+.. Lfffjjiii,                       ...  :LL;,,tjjfffLL;;;;iiiiiiii,;;;,:::::..+.. LfffijijjLfi;                   ,:::,ffj,j;tjffffLG;;;;;;;;;;;;;;;;;,,:::::..+... LLLff,i;jGLLLL                   LiLt:::tjjffffLG:,,,,,,,,,;;;;,,,,::.......+.Version X.X.X (frontend: xxx, engine: LambdaHack X.X.X) ,,,,,,,,,,,:::::..    .
GameDefinition/PLAYING.md view
@@ -2,14 +2,14 @@ ===========================  Your party of trusted crew-members is about to test their fortune-by exploring an abandoned Solar System passenger cruiser.+by plundering an abandoned Solar System passenger cruiser. You are going to set up ambushes for it's feral denizens, hide in shadows, cover tracks, bump into unspeakable horrors, hidden mechanisms and astounding technical treasures and make creative use of it all.-The mysterious inhabitants of the gigantic spaceship are bound-to welcome intruders with bloody surprises of their own.+The mysterious inhabitants of the Solar System's outer frontier+are bound to welcome intruders with bloody surprises of their own. As soon as you turn your back in fear, expect to be chased tirelessly-throughout all the decks, by sight, sound and smell.+by sight, sound and smell.  Once the few basic command keys and on-screen symbols are learned, mastery and enjoyment of the game is the matter of tactical skill@@ -22,193 +22,237 @@ ------  The heroes are marked on the map with symbols `@` and `1` through `9`.-Their goal is to explore a warped, old, once luxurious space liner,-battle the horrors within, gather as much gold and precious gems-as possible, and escape to tell the tale.--The currently chosen party leader is highlighted on the screen+The currently chosen party leader is highlighted on the map and his attributes are displayed at the bottommost status line,-which in its most complex form may look as follows.+which in its most complex form looks as follows. -    *@12 Adventurer  4d1+5% Calm: 20/60 HP: 33/50 Target: basilisk  [**__]+    *@12        4d1+5% Calm: 20/60 HP: 33/50 Target: basilisk  [**__] -The line starts with the list of party members (unless there's only one member)-and the shortened name of the team. Clicking on the list selects heroes and-the selected run together when `:` or `SHIFT`-left mouse button is pressed.+The line starts with the list of party members, with the leader highlighted.+Most commands involve only the leader, including movement with keyboard's+keypad or `LMB` (left mouse button). If more heroes are selected, e.g.,+by clicking on the list with `RMB` (right mouse button), they run together+whenever `:` or `RMB` over map area is pressed. -Then comes the damage of the highest damage dice weapon the leader can use,-then his current and maximum Calm (composure, focus, attentiveness), then-his current and maximum HP (hit points, health). At the end, the personal-target of the leader is described, in this case a basilisk monster,-with hit points drawn as a bar. Weapon damage and other item stats-are displayed using the dice notation `XdY`, which means X rolls-of Y-sided dice. A variant denoted `XdsY` is additionally-scaled by the level depth in proportion to the maximal spaceship depth.-You can read more about combat resolution in section Monsters below.+Next on the status line is the damage of the currently best melee weapon+the leader can use, then his current and maximum Calm (morale, composure,+focus, attentiveness), then his current and maximum HP (hit points, health).+At the end, the personal target of the leader is described, in this case+a basilisk monster, with hit points drawn as a bar. Additionally,+the colon after "Calm" turning into a dot signifies that the leader+is in a position without ambient illumination and a brace sign instead+of colon after "HP" means the leader is braced for combat (see section+[Basic Commands](#basic-commands)). -The second status line describes the current level in relation+Instead of a monster, the target area may describe a position on the map,+a recently spotted item on the floor or an item in inventory selected+for further action or, if none are available, just display the current+leader name. Weapon damage and other item stats are displayed using+the dice notation `XdY`, which means `X` rolls of `Y`-sided dice.+A variant denoted `XdlY` is additionally scaled by the level depth+in proportion to the maximal level depth. Section [Monsters](#monsters)+below describes combat resolution in detail, including the percentage+bonus seen in the example.++The second, upper status line describes the current level in relation to the party.      5  Lofty hall   [33% seen] X-hair: exact spot (71,12)  p15 l10  First comes the depth of the current level and its name. Then the percentage of its explorable tiles already seen by the heroes.-The 'X-hair' (meaning 'crosshair') is the common focus of the whole party,-denoted on the map by a white box and manipulated with movement keys-in aiming mode. At the end of the status line comes the length of the shortest-path from the leader to the crosshair position and the straight-line distance+The `X-hair` (aiming crosshair) is the common focus of the whole party,+marked on the map and manipulated with mouse or movement keys in aiming mode.+In this example, the corsshair points at an exact position on the map+and at the end of the status line comes the length of the shortest+path from the leader to the spot position and the straight-line distance between the two points.  -Spaceship----------+Game map+-------- -The spaceship and other scenario locations consist of one or many-levels or decks and each deck consists of a large number of tiles.+The map of any particular scenario may consist of one or many+levels and each level consists of a large number of tiles.+The game world is persistent, i.e., every time the player visits+a level during a single game, its layout is the same. The basic tile kinds are as follows. -               terrain type                       on-screen symbol-               floor                              .-               wall                               #-               rock or tree                       O-               cache                              &-               stairs up                          <-               stairs down                        >-               open door                          '-               closed door                        ++    game map terrain type                  on-screen symbol+    wall                                   #+    tree or rock or man-made column        O+    rubble                                 &+    bush, transparent obstacle             %+    trap, ice                              ^+    closed door                            ++    open door (horizontal and vertical)    '+    smoke or fog                           ;+    ground, corridor                       .+    stairs or exit up                      <+    stairs or exit down                    > -The game world is persistent, i.e., every time the player visits a deck-during a single game, its layout is the same.+So, for example, the following map shows a room with a closed door+connected by a corridor with a room with an open door, a pillar,+staircase down and rubble that obscures one of the corners. +    ####       ####+    #..#########..&&+    #..+.......'.O.>&#+    #..#########.....#+    ####       ####### -Commands--------- -You walk throughout a level using the left mouse button or the numeric-keypad (left diagram) or its compact laptop replacement (middle)-or Vi text editor keys (right, also known as "Rogue-like keys",-which have to be enabled in config.ui.ini).+Basic Commands+-------------- -                7 8 9          7 8 9          y k u-                 \|/            \|/            \|/-                4-5-6          u-i-o          h-.-l-                 /|\            /|\            /|\-                1 2 3          j k l          b j n+This section is a copy of the first two screens of in-game help+and a screen introducing mouse commands. The help pages are+automatically generated based on a game's keybinding content and+on overrides in the player's config file. The remaiing in-game help screens,+not shown here, list all game commands grouped by categories, in detail.+A text snapshot of the complete in-game help is in+[InGameHelp.txt](InGameHelp.txt). -In aiming mode (`KEYPAD_*` or `\`) the same keys (or the middle and right-mouse buttons) move the crosshair (the white box). In normal mode,-`SHIFT` (or `CTRL`) and a movement key make the current party leader-run in the indicated direction, until anything of interest is spotted.-The `5` keypad key and the `i` and `.` keys consume a turn and make you-brace for combat, which reduces any damage taken for a turn and makes it-impossible for foes to displace you. You displace enemies or friends-by bumping into them with `SHIFT` (or `CTRL`).+Walk throughout a level with mouse or numeric keypad (left diagram below)+or its compact laptop replacement (middle) or the Vi text editor keys (right,+enabled in config.ui.ini). Run, until disturbed, by adding Shift or Control.+Go-to with LMB (left mouse button). Run collectively with RMB. -Melee, searching for secret doors, looting and opening closed doors-can be done by bumping into a monster, a wall and a door, respectively.-Few commands other than movement, 'g'etting an item from the floor,-'a'pplying an item and 'f'linging an item are necessary for casual play.-Some are provided only as specialized versions of the more general-commands or as building blocks for more complex convenience macros.-E.g., the autoexplore command (key `X`) could be defined-by the player as a macro using `CTRL-?`, `CTRL-.` and `V`.+               7 8 9          7 8 9          y k u+                \|/            \|/            \|/+               4-5-6          u-i-o          h-.-l+                /|\            /|\            /|\+               1 2 3          j k l          b j n -The following minimal command set lets you accomplish almost anything-in the game, though not necessarily with the fewest number of keystrokes.-The full list of commands can be seen in the in-game help accessible-from the Main Menu.+In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair).+Press 'KP_5' ('5' on keypad, if present) 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 wait 0.1 of a turn, without bracing.+You displace enemies by running into them with Shift/Control or RMB. Search,+open, descend and attack by bumping into walls, doors, stairs and enemies.+The best item to attack with is automatically chosen from among+weapons in your personal equipment and your unwounded organs. -        keys            command-        <               ascend a level-        >               descend a level-        c               close door-        E               manage equipment of the leader-        g or ,          get items-        a               apply consumable-        f               fling projectile-        +               swerve the aiming line-        D               display player diary-        T               toggle suspect terrain display-        SHIFT-TAB       cycle among all party members-        ESC             cancel action, open Main Menu+The following commands, joined with the basic set above, let you accomplish+anything in the game, though not necessarily with the fewest keystrokes.+You can also play the game exclusively with a mouse, or both mouse and+keyboard. See the ending help screens for mouse commands.+Lastly, you can select a command with arrows or mouse directly from the help+screen and execute it on the spot. -The only activity not possible with the commands above is the management-of non-leader party members. You don't need it, unless your non-leader actors-can move or fire opportunistically (via innate skills or rare equipment).-If really needed, you can manually set party tactics with `CTRL-T`-and you can assign individual targets to party members using the aiming-and targeting commands listed below.+    keys         command+    g or ,       grab item(s)+    c            close door+    P            manage item pack of the leader+    KP_* or !    cycle x-hair among enemies+    +            swerve the aiming line+    ESC          cancel aiming/open Main Menu+    RET or INS   accept target/open Help+    SPACE        clear messages/display history+    S-TAB        cycle among all party members+    =            select (or deselect) party member -        keys            command-        KEYPAD_* or \   aim at an enemy-        KEYPAD_/ or |   cycle aiming styles-        +               swerve the aiming line-        -               unswerve the aiming line-        CTRL-?          set crosshair to the closest unknown spot-        CTRL-I          set crosshair to the closest item-        CTRL-{          set crosshair to the closest stairs up-        CTRL-}          set crosshair to the closest stairs down-        BACKSPACE       reset target/crosshair-        RET or INSERT   accept target/choice+Screen area and UI mode (aiming/exploration) determine mouse click effects.+Here is an overview of effects of each button over most of the game map area.+The list includes not only left and right buttons, but also the optional+middle mouse button (MMB) and even the mouse wheel, which is normally used+over menus, to page-scroll them, rather than over game map.+For mice without RMB, one can use C-LMB (Control key and left mouse button). -For ranged attacks, setting the crosshair or individual targets-beforehand is not mandatory, because the crosshair is set automatically-as soon as a monster comes into view and can still be adjusted while-in the missile choice menu. However, if you want to assign persistent-personal targets or just inspect the level map closely, you can enter-the detailed aiming mode with the right mouse button or with-the `*` keypad key that selects enemies or the `/` keypad key that-marks a tile. You can move the aiming crosshair with direction keys-and assign a personal target to the leader with `RET`.-The details of the shared crosshair position and of the personal target-are described in the status lines at the bottom of the screen.+    keys         command+    LMB          set x-hair to enemy/go to pointer for 25 steps+    RMB or C-LMB fling at enemy/run to pointer collectively for 25 steps+    C-RMB        open or close door+    MMB          snap x-hair to floor under pointer+    WHEEL-UP     swerve the aiming line+    WHEEL-DN     unswerve the aiming line -Commands for saving and exiting the current game, starting a new game, etc.,++Advanced Commands+-----------------++For ranged attacks, setting the aiming crosshair beforehand is not mandatory,+because x-hair is set automatically as soon as a monster comes into view+and can still be adjusted for as long as the missile to fling is not chosen.+However, sometimes you want to examine the level map tile by tile+or assign persistent personal targets to party members.+The latter is essential in the rare cases when your henchmen+(non-leader characters) can move autonomously or fire opportunistically+(via innate skills or rare equipment). Also, if your henchman is adjacent+to more than one enemy, setting his target makes him melee a particular foe.++You can enter the detailed aiming mode with the `*` keypad key that selects+enemies or the `/` keypad key that cycles among items on the floor+and marks a tile underneath an item. You can move x-hair with direction keys+and assign a personal target to the leader with `RET` key (Return, Enter).+The details of the shared x-hair position and of the personal target+are described in the status lines at the bottom of the screen,+as explained in section [Heroes](#heroes) above.++Commands for saving and exiting the current game, starting a new game,+setting options for the current game and challenges for the next game, etc., are listed in the Main Menu, brought up by the `ESC` key.-Game difficulty setting affects hitpoints at birth for any actors-of any UI-using faction. For a person new to roguelikes, the Raid scenario-offers a gentle introduction. The subsequent game modes gradually introduce-squad combat, stealth, opportunity fire, asymmetric battles and more.+Game difficulty, from the challenges menu, determines+hitpoints at birth for any actor of any UI-using faction.+The "lone wolf" challenge mode reduces player's starting actors to exactly+one (consequently, this does not affect the initial 'raid' scenario).+The "cold fish" challenge mode makes it impossible for player characters+to be healed by actors from other factions (this is a significant+restriction in the final 'crawl' scenario). +For a person new to roguelikes, the 'raid' scenario offers a gentle+introduction. The subsequent game scenarios gradually introduce squad combat,+stealth, opportunity fire, asymmetric battles and more. + Monsters -------- -Heroes are not alone in the spaceship. Monstrosities, natural-and out of this world, roam the dark halls and crawl from damp air-ducts+The life of the heroes is full of dangers. Monstrosities, natural+and out of this world, roam the dark corridors and crawl from damp holes day and night. While heroes pay attention to all other party members and take care to move one at a time, monsters don't care about each other and all move at once, sometimes brutally colliding by accident.  When the hero bumps into a monster or a monster attacks the hero, melee combat occurs. Heroes and monsters running into one another-(with the `SHIFT` key) do not inflict damage, but change places.+(with the `Shift` or `Control` key) do not inflict damage, but change places. This gives the opponent a free blow, but can improve the tactical situation or aid escape. In some circumstances actors are immune to the displacing, e.g., when both parties form a continuous front-line.  In melee combat, the best equipped weapon (or the best fighting organ) of each opponent is taken into account for determining the damage-and any extra effects of the blow. If a recharged weapon with a non-trivial-effect is in the equipment, it is preferred for combat. Otherwise combat-involves the weapon with the highest raw damage dice (the same as displayed-at bottommost status line).+and any extra effects of the blow. Since an item needs to be recharged+in order to have its full effect, weapons on timeout are only considered+according to their raw damage dice (the same as displayed at bottommost+status line).  To determine the damage dealt, the outcome of the weapon's damage dice roll-is multiplied by the melee damage bonus (summed from the equipped items-of the attacker) minus the melee armor modifier of the defender.-Regardless of the calculation, each attack inflicts at least 1 damage.+is multiplied by a percentage bonus. The bonus is calculated by taking+the damage bonus (summed from the equipped items of the attacker,+capped at 200%) minus the melee armor modifier of the defender+(capped at 200%, as well), with the outcome bounded between -99% and 99%,+which means that at least 1% of damage always gets through+and the damage is always lower than twice the dice roll. The current leader's melee bonus, armor modifier and other detailed-stats can be viewed via the `!` command.+stats can be viewed via the `#` command.  In ranged combat, the missile is assumed to be attacking the defender-in melee, using itself as the weapon, but the ranged damage bonus-and the ranged armor modifier are taken into account for calculations.-You may propel any item in your equipment, inventory pack and on the ground-(by default you are offered only the appropriate items; press `?`-to cycle item menu modes). Only items of a few kinds inflict any damage,-but some have other effects, beneficial, detrimental or mixed.+in melee, using itself as the weapon, with the usual dice and damage bonus.+This time, the ranged armor stat of the defender is taken into account+and, additionally, the speed of the missile (based on shape and weight)+figures in the calculation. You may propel any item from your inventory+(by default you are offered only the appropriate items; press `?`to cycle+item menu modes). Only items of a few kinds inflict any damage, but some+have other effects, beneficial, detrimental or mixed. +In-game detailed item descriptions contain melee and ranged damage estimates.+They do not take into account damage from effects and, if bonuses are not+known, they are guessed based on average bonuses for that kind of item.+The displayed figures are rounded, but the game internally keeps track+of minute fractions of HP.+ Whenever the monster's or hero's hit points reach zero, the combatant dies. When the last hero dies, the scenario ends in defeat. @@ -216,16 +260,17 @@ On Winning and Dying -------------------- -You win the scenario if you escape the spaceship alive or, in scenarios with+You win a scenario if you escape the location alive or, in scenarios with no exit locations, if you eliminate all opposition. In the former case,-your score is based on the gold and precious gems you've plundered.-In the latter case, your score is based on the number of turns you spent-overcoming your foes (the quicker the victory, the better; the slower-the demise, the better). Bonus points, based on the number of heroes lost,-are awarded if you win.+your score is based predominantly on the gold and precious gems you've+plundered. In the latter case, your score is most influenced by the number+of turns you spent overcoming your foes (the quicker the victory, the better;+the slower the demise, the better). Bonus points, affected by the number+of heroes lost, are awarded only if you win. The score is heavily+modified by the chosen game difficulty, but not by any other challenges.  When all your heroes fall, you are going to invariably see a new foolhardy-party of adventurers clamoring to be led into the spaceship. They start+party of adventurers clamoring to be led into danger. They start their conquest from a new entrance, with no experience and no equipment, and new, undaunted enemies bar their way. Lead the new hopeful explorers to fame, wealth and glory!
GameDefinition/TieKnot.hs view
@@ -1,12 +1,27 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Here the knot of engine code pieces and the game-specific -- content definitions is tied, resulting in an executable game.-module TieKnot ( tieKnot ) where+module TieKnot+  ( tieKnot+  ) where +import Prelude ()++import Game.LambdaHack.Common.Prelude++import qualified System.Random as R++import Game.LambdaHack.Common.ContentDef+import qualified Game.LambdaHack.Common.Kind as Kind+import qualified Game.LambdaHack.Common.Tile as Tile+import Game.LambdaHack.Content.ItemKind+import Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer)+import Game.LambdaHack.Server+ import qualified Client.UI.Content.KeyKind as Content.KeyKind import qualified Content.CaveKind import qualified Content.ItemKind@@ -14,40 +29,63 @@ import qualified Content.PlaceKind import qualified Content.RuleKind import qualified Content.TileKind-import Game.LambdaHack.Client-import qualified Game.LambdaHack.Common.Kind as Kind-import Game.LambdaHack.SampleImplementation.SampleMonadClient (executorCli)-import Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer)-import Game.LambdaHack.Server  -- | Tie the LambdaHack engine client, server and frontend code -- with the game-specific content definitions, and run the game.+--+-- The action monad types to be used are determined by the 'executorSer'+-- and 'executorCli' calls. If other functions are used in their place+-- the types are different and so the whole pattern of computation+-- is different. Which of the frontends is run inside the UI client+-- depends on the flags supplied when compiling the engine library. tieKnot :: [String] -> IO () tieKnot args = do-  let -- Common content operations, created from content definitions.-      -- Evaluated fully to discover errors ASAP and free memory.-      !copsSlow = Kind.COps+  -- Options for the next game taken from the commandline.+  let sdebug@DebugModeSer{sallClear, sboostRandomItem, sdungeonRng} =+        debugArgs args+  -- This setup ensures the boosting option doesn't affect generating initial+  -- RNG for dungeon, etc., and also, that setting dungeon RNG on commandline+  -- equal to what was generated last time, ensures the same item boost.+  initialGen <- maybe R.getStdGen return sdungeonRng+  let sdebugNxt = sdebug {sdungeonRng = Just initialGen}+      -- Common content operations, created from content definitions.+      -- Evaluated fully to discover errors ASAP and to free memory.+      cotile = Kind.createOps Content.TileKind.cdefs+      boostItem :: ItemKind -> ItemKind+      boostItem i =+        let mainlineLabel (label, _) = label `elem` ["useful", "treasure"]+        in if any mainlineLabel (ifreq i)+           then i { ifreq = ("useful", 10000)+                            : filter (not . mainlineLabel) (ifreq i)+                  , ieffects = delete Unique $ ieffects i+                  }+           else i+      boostList :: [ItemKind] -> [ItemKind]+      boostList l | not sboostRandomItem = l+      boostList [] = []+      boostList l =+        let (r, _) = R.randomR (0, length l - 1) initialGen+        in case splitAt r l of+          (pre, i : post) -> pre ++ boostItem i : post+          _ -> assert `failure` l+      boostedItems = boostList Content.ItemKind.items+      cdefsItem =+        Content.ItemKind.cdefs+          {content = contentFromList+                     $ boostedItems ++ Content.ItemKind.otherItemContent}+      coitem = Kind.createOps cdefsItem+      !cops = Kind.COps         { cocave  = Kind.createOps Content.CaveKind.cdefs-        , coitem  = Kind.createOps Content.ItemKind.cdefs+        , coitem         , comode  = Kind.createOps Content.ModeKind.cdefs         , coplace = Kind.createOps Content.PlaceKind.cdefs         , corule  = Kind.createOps Content.RuleKind.cdefs-        , cotile  = Kind.createOps Content.TileKind.cdefs+        , cotile+        , coTileSpeedup = Tile.speedup sallClear cotile         }-      !copsShared = speedupCOps False copsSlow-      -- Client content operations.-      copsClient = Content.KeyKind.standardKeys-  sdebugNxt <- debugArgs args-  -- Fire up the frontend with the engine fueled by content.-  -- The action monad types to be used are determined by the 'exeSer'-  -- and 'executorCli' calls. If other functions are used in their place-  -- the types are different and so the whole pattern of computation-  -- is different. Which of the frontends is run depends on the flags supplied-  -- when compiling the engine library.-  let exeServer executorUI executorAI =-        executorSer $ loopSer copsShared sdebugNxt executorUI executorAI-  -- Currently a single frontend is started by the server,-  -- instead of each client starting it's own.-  srtFrontend (executorCli . loopUI)-              (executorCli . loopAI)-              copsClient copsShared (sdebugCli sdebugNxt) exeServer+      -- Client content operations containing default keypresses+      -- and command descriptions.+      !copsClient = Content.KeyKind.standardKeys+  -- Wire together game content, the main loops of game clients+  -- and the game server loop.+  executorSer cops copsClient sdebugNxt
GameDefinition/config.ui.default view
@@ -1,4 +1,4 @@-; Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+; Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski ; This file is a part of the computer game Allure of the Stars ; and is released under the terms of the GNU Affero General Public License. ; For license and copyright information, see the file LICENSE.@@ -18,10 +18,8 @@ ; or elsewhere.  [extra_commands]-; A handy shorthand with Vi keys-Macro_1 = ("comma", ([CmdItem], Macro "" ["g"])) ; Angband compatibility (accept target)-Macro_2 = ("KP_Insert", ([CmdMeta], Macro "" ["Return"]))+Cmd_2 = ("KP_Insert", ([CmdAim], "", ByAimMode {exploration = Help, aiming = Accept}))  [hero_names] HeroName_0 = ("Haskell Alvin", "he")@@ -35,12 +33,17 @@ [ui] movementViKeys_hjklyubn = False movementLaptopKeys_uk8o79jl = True-; Monospace fonts that have fixed size regardless of boldness (on some OSes)-font = "Terminus,DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace normal normal normal normal 14"-;font = "Terminus,DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace normal normal normal normal 18"+; Monospace fonts that have fixed size regardless of boldness (on some OSes at least)+gtkFontFamily = "DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace"+;sdlFontFile = "Fix15Mono-Bold.woff"+sdlFontFile = "16x16x.fon"+sdlTtfSizeAdd = -2+sdlFonSizeAdd = 1+fontSize = 16 colorIsBold = True ; New historyMax takes effect after removal of savefiles. historyMax = 5000 maxFps = 30 noAnim = False runStopMsgs = False+overrideCmdline = ""
+ GameDefinition/fonts/16x16x.fon view

binary file changed (absent → 9840 bytes)

+ GameDefinition/fonts/8x8x.fon view

binary file changed (absent → 3648 bytes)

+ GameDefinition/fonts/8x8xb.fon view

binary file changed (absent → 3648 bytes)

+ GameDefinition/fonts/Fix15Mono-Bold.woff view

binary file changed (absent → 96748 bytes)

+ GameDefinition/fonts/LICENSE.16x16x view
@@ -0,0 +1,339 @@+                    GNU GENERAL PUBLIC LICENSE+                       Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++                            Preamble++  The licenses for most software are designed to take away your+freedom to share and change it.  By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users.  This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it.  (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.)  You can apply it to+your programs, too.++  When we speak of free software, we are referring to freedom, not+price.  Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++  To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have.  You must make sure that they, too, receive or can get the+source code.  And you must show them these terms so they know their+rights.++  We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++  Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software.  If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++  Finally, any free program is threatened constantly by software+patents.  We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary.  To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++  The precise terms and conditions for copying, distribution and+modification follow.++                    GNU GENERAL PUBLIC LICENSE+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++  0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License.  The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language.  (Hereinafter, translation is included without limitation in+the term "modification".)  Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope.  The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++  1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++  2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++    a) You must cause the modified files to carry prominent notices+    stating that you changed the files and the date of any change.++    b) You must cause any work that you distribute or publish, that in+    whole or in part contains or is derived from the Program or any+    part thereof, to be licensed as a whole at no charge to all third+    parties under the terms of this License.++    c) If the modified program normally reads commands interactively+    when run, you must cause it, when started running for such+    interactive use in the most ordinary way, to print or display an+    announcement including an appropriate copyright notice and a+    notice that there is no warranty (or else, saying that you provide+    a warranty) and that users may redistribute the program under+    these conditions, and telling the user how to view a copy of this+    License.  (Exception: if the Program itself is interactive but+    does not normally print such an announcement, your work based on+    the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole.  If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works.  But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++  3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++    a) Accompany it with the complete corresponding machine-readable+    source code, which must be distributed under the terms of Sections+    1 and 2 above on a medium customarily used for software interchange; or,++    b) Accompany it with a written offer, valid for at least three+    years, to give any third party, for a charge no more than your+    cost of physically performing source distribution, a complete+    machine-readable copy of the corresponding source code, to be+    distributed under the terms of Sections 1 and 2 above on a medium+    customarily used for software interchange; or,++    c) Accompany it with the information you received as to the offer+    to distribute corresponding source code.  (This alternative is+    allowed only for noncommercial distribution and only if you+    received the program in object code or executable form with such+    an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it.  For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable.  However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++  4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License.  Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++  5. You are not required to accept this License, since you have not+signed it.  However, nothing else grants you permission to modify or+distribute the Program or its derivative works.  These actions are+prohibited by law if you do not accept this License.  Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++  6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions.  You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++  7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all.  For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices.  Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++  8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded.  In such case, this License incorporates+the limitation as if written in the body of this License.++  9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number.  If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation.  If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++  10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission.  For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this.  Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++                            NO WARRANTY++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++                     END OF TERMS AND CONDITIONS++            How to Apply These Terms to Your New Programs++  If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++  To do so, attach the following notices to the program.  It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++    <one line to give the program's name and a brief idea of what it does.>+    Copyright (C) <year>  <name of author>++    This program is free software; you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation; either version 2 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License along+    with this program; if not, write to the Free Software Foundation, Inc.,+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++    Gnomovision version 69, Copyright (C) year name of author+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary.  Here is a sample; alter the names:++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program+  `Gnomovision' (which makes passes at compilers) written by James Hacker.++  <signature of Ty Coon>, 1 April 1989+  Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs.  If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ GameDefinition/fonts/LICENSE.Fix15Mono-Bold view
@@ -0,0 +1,94 @@+Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
+with Reserved Font Name < Fira >, 
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
− GameDefinition/scores

binary file changed (962 → absent bytes)

LICENSE view
@@ -1,3 +1,18 @@+Fonts 16x16x.fon, 8x8x.fon and 8x8xb.fon are are taken from+https://github.com/angband/angband, copyrighted by Leon Marrick,+Sheldon Simms III and Nick McConnell and released by them under+GNU GPL version 2. Any further modifications by authors of LambdaHack+are also released under GNU GPL version 2. The licence file is at+GameDefinition/fonts/LICENSE.16x16x++Font Fix15Mono-Bold.woff is a modified version of+https://github.com/mozilla/Fira/blob/master/ttf/FiraMono-Bold.ttf+that is copyright 2012-2015, The Mozilla Foundation and Telefonica S.A.+The modified font is released under the SIL Open Font License, as seen in+GameDefinition/fonts/LICENSE.Fix15Mono-Bold++The whole Allure of the Stars work is licensed under+                     GNU AFFERO GENERAL PUBLIC LICENSE                        Version 3, 19 November 2007 
Makefile view
@@ -1,265 +1,201 @@-# Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+# Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski # This file is a part of the computer game Allure of the Stars # and is released under the terms of the GNU Affero General Public License. # For license and copyright information, see the file LICENSE. # -# All xc* tests assume a profiling build (for stack traces).-# See the install-debug target below.--install-debug:-	cabal install --enable-library-profiling --enable-executable-profiling --ghc-options="-fprof-auto-calls" --disable-optimization+play:+	dist/build/Allure/Allure --dbgMsgSer --dumpInitRngs  configure-debug:-	cabal configure --enable-library-profiling --enable-executable-profiling --ghc-options="-fprof-auto-calls" --disable-optimization---xcplay:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --dumpInitRngs--xcfrontendCampaign:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 1 --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign--xcfrontendRaid:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode raid+	cabal configure --enable-profiling --profiling-detail=all-functions -fwith_expensive_assertions --disable-optimization -xcfrontendSkirmish:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish+configure-prof:+	cabal configure --enable-profiling --profiling-detail=exported-functions -frelease -xcfrontendAmbush:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode ambush+ghcjs-configure:+	cabal configure --disable-library-profiling --disable-profiling --ghcjs --ghcjs-option=-dedupe -f-release -xcfrontendBattle:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode battle+chrome-prof:+	google-chrome --no-sandbox --js-flags="--logfile=%t.log --prof" ../allureofthestars.github.io/play/index.html -xcfrontendBattleSurvival:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival"+minific:+	ccjs dist/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --jscomp_off="*" --externs=node > ../allureofthestars.github.io/play/allure.all.js -xcfrontendSafari:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode safari+frontendRaid:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode raid -xcfrontendSafariSurvival:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival"+frontendBrawl:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode brawl -xcfrontendDefense:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 9 --maxFps 60 --dumpInitRngs --automateAll --gameMode defense+frontendShootout:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode shootout +frontendEscape:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 3 --dumpInitRngs --automateAll --gameMode escape -play:-	dist/build/Allure/Allure --dbgMsgSer --dumpInitRngs+frontendZoo:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode zoo -frontendCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign+frontendAmbush:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode ambush -frontendRaid:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode raid+frontendExploration:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 1 --dumpInitRngs --automateAll --gameMode exploration -frontendSkirmish:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish+frontendSafari:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode safari -frontendAmbush:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode ambush+frontendSafariSurvival:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "safari survival"  frontendBattle:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode battle+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode battle  frontendBattleSurvival:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival"--frontendSafari:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode safari--frontendSafariSurvival:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival"+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "battle survival"  frontendDefense:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --maxFps 60 --dumpInitRngs --automateAll --gameMode defense+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix test --newGame 9 --dumpInitRngs --automateAll --gameMode defense -benchCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS +benchMemoryAnim:+	dist/build/Allure/Allure --dbgMsgSer --newGame 1 --maxFps 100000 --benchmark --stopAfterFrames 33000 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 120 --setMainRng 47 --frontendNull --noAnim +RTS -s -A1M -RTS+ benchBattle:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --newGame 3 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 1500 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7 -benchFrontendCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+benchAnimBattle:+	dist/build/Allure/Allure --dbgMsgSer --newGame 3 --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 7000 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7  benchFrontendBattle:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --newGame 3 --noAnim --maxFps 100000 --benchmark --stopAfterFrames 1500 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7 -benchNull: benchCampaign benchBattle+benchExploration:+	dist/build/Allure/Allure --dbgMsgSer --newGame 1 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 7000 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 0 --setMainRng 0 -bench: benchCampaign benchFrontendCampaign benchBattle benchFrontendBattle+benchFrontendExploration:+	dist/build/Allure/Allure --dbgMsgSer --newGame 1 --noAnim --maxFps 100000 --benchmark --stopAfterFrames 7000 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 0 --setMainRng 0 +benchNull: benchBattle benchAnimBattle benchExploration -test-travis-short: test-short+bench: benchBattle benchAnimBattle benchFrontendBattle benchExploration benchFrontendExploration -test-travis-medium: test-short test-medium+nativeBenchExploration:+	dist/build/Allure/Allure		   --dbgMsgSer --newGame 2 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 2000 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 0 --setMainRng 0 -test-travis-medium-no-safari: test-short test-medium-no-safari+nativeBenchBattle:+	dist/build/Allure/Allure		   --dbgMsgSer --newGame 3 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 1000 --automateAll --keepAutomated --gameMode battle --setDungeonRng 0 --setMainRng 0 -test-travis-long: test-short test-long+nativeBench: nativeBenchBattle nativeBenchExploration -test-travis-long-no-safari: test-short test-long-no-safari+nodeBenchExploration:+	node dist/build/Allure/Allure.jsexe/all.js --dbgMsgSer --newGame 2 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 2000 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 0 --setMainRng 0 -test: test-short test-medium test-long+nodeBenchBattle:+	node dist/build/Allure/Allure.jsexe/all.js --dbgMsgSer --newGame 3 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 1000 --automateAll --keepAutomated --gameMode battle --setDungeonRng 0 --setMainRng 0 -test-short: test-short-new test-short-load+nodeBench: nodeBenchBattle nodeBenchExploration -test-medium: testCampaign-medium testRaid-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testSafari-medium testSafariSurvival-medium testPvP-medium testCoop-medium testDefense-medium -test-medium-no-safari: testCampaign-medium testRaid-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testPvP-medium testCoop-medium testDefense-medium--test-long: testCampaign-long testRaid-medium testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testSafari-long testSafariSurvival-long testPvP-medium testDefense-long+test-travis-short: test-short -test-long-no-safari: testCampaign-long testRaid-medium testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testPvP-medium testDefense-long+test-travis: test-short test-medium benchNull -testCampaign-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign > /tmp/stdtest.log+test: test-short test-medium benchNull -testCampaign-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign > /tmp/stdtest.log+test-short: test-short-new test-short-load -testRaid-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode raid > /tmp/stdtest.log+test-medium: testRaid-medium testBrawl-medium testShootout-medium testEscape-medium testZoo-medium testAmbush-medium testExploration-medium testSafari-medium testSafariSurvival-medium testBattle-medium testBattleSurvival-medium  testRaid-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode raid > /tmp/stdtest.log--testSkirmish-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log--testSkirmish-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log--testAmbush-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode raid 2> /tmp/teletypetest.log -testAmbush-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log+testBrawl-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode brawl 2> /tmp/teletypetest.log -testBattle-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode battle > /tmp/stdtest.log+testShootout-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode shootout 2> /tmp/teletypetest.log -testBattle-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode battle > /tmp/stdtest.log+testEscape-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 3 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode escape 2> /tmp/teletypetest.log -testBattleSurvival-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" > /tmp/stdtest.log+testZoo-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 2 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 100 --dumpInitRngs --automateAll --keepAutomated --gameMode zoo 2> /tmp/teletypetest.log -testBattleSurvival-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" > /tmp/stdtest.log+testAmbush-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush 2> /tmp/teletypetest.log -testSafari-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode safari > /tmp/stdtest.log+testExploration-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 1 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 200 --dumpInitRngs --automateAll --keepAutomated --gameMode exploration 2> /tmp/teletypetest.log  testSafari-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode safari > /tmp/stdtest.log--testSafariSurvival-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 2 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 100 --dumpInitRngs --automateAll --keepAutomated --gameMode safari 2> /tmp/teletypetest.log  testSafariSurvival-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" > /tmp/stdtest.log---testPvP-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode PvP > /tmp/stdtest.log--testPvP-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode PvP > /tmp/stdtest.log--testCoop-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 8 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 60 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" 2> /tmp/teletypetest.log -testCoop-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop > /tmp/stdtest.log+testBattle-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 3 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode battle 2> /tmp/teletypetest.log -testDefense-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode defense > /tmp/stdtest.log+testBattleSurvival-medium:+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 7 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 60 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" 2> /tmp/teletypetest.log  testDefense-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode defense > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 9 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 500 --dumpInitRngs --automateAll --keepAutomated --gameMode defense 2> /tmp/teletypetest.log  test-short-new:-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix skirmish --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix PvP --dumpInitRngs --automateAll --keepAutomated --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix Coop --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix defense --dumpInitRngs --automateAll --keepAutomated --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix brawl --dumpInitRngs --automateAll --keepAutomated --gameMode brawl --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix shootout --dumpInitRngs --automateAll --keepAutomated --gameMode shootout --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix escape --dumpInitRngs --automateAll --keepAutomated --gameMode escape --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix zoo --dumpInitRngs --automateAll --keepAutomated --gameMode zoo --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix exploration --dumpInitRngs --automateAll --keepAutomated --gameMode exploration --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --newGame 5 --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log +# "--setDungeonRng 0 --setMainRng 0" is needed for determinism relative to seed+# generated before game save test-short-load:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix skirmish --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix PvP --dumpInitRngs --automateAll --keepAutomated --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix Coop --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix defense --dumpInitRngs --automateAll --keepAutomated --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix brawl --dumpInitRngs --automateAll --keepAutomated --gameMode brawl --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix shootout --dumpInitRngs --automateAll --keepAutomated --gameMode shootouti --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix escape --dumpInitRngs --automateAll --keepAutomated --gameMode escape --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix zoo --dumpInitRngs --automateAll --keepAutomated --gameMode zoo --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix exploration --dumpInitRngs --automateAll --keepAutomated --gameMode exploration --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log+	dist/build/Allure/Allure --dbgMsgSer --boostRandomItem --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendTeletype --stopAfterSeconds 2 --setDungeonRng 0 --setMainRng 0 2> /tmp/teletypetest.log  -build-binary:-	cabal configure -frelease --prefix=/-	cabal build Allure-	rm -rf /tmp/Allure_x_ubuntu-12.04-amd64.tar.gz-	rm -rf /tmp/AllureOfTheStarsInstall-	rm -rf /tmp/AllureOfTheStars-	mkdir -p /tmp/AllureOfTheStars/GameDefinition-	cabal copy --destdir=/tmp/AllureOfTheStarsInstall-	cp /tmp/AllureOfTheStarsInstall/bin/Allure /tmp/AllureOfTheStars-	cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition-	cp CHANGELOG.md /tmp/AllureOfTheStars-	cp CREDITS /tmp/AllureOfTheStars-	cp LICENSE /tmp/AllureOfTheStars-	cp README.md /tmp/AllureOfTheStars-	tar -czf /tmp/Allure_x_ubuntu-12.04-amd64.tar.gz -C /tmp AllureOfTheStars--build-binary-i386:-	cabal configure -frelease --prefix=/ --ghc-option="-optc-m32" --ghc-option="-opta-m32" --ghc-option="-optl-m32" --ld-option="-melf_i386"-	cabal build Allure-	rm -rf /tmp/Allure_x_ubuntu-12.04-i386.tar.gz-	rm -rf /tmp/AllureOfTheStarsInstall-	rm -rf /tmp/AllureOfTheStars-	mkdir -p /tmp/AllureOfTheStars/GameDefinition-	cabal copy --destdir=/tmp/AllureOfTheStarsInstall-	cp /tmp/AllureOfTheStarsInstall/bin/Allure /tmp/AllureOfTheStars-	cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition-	cp CHANGELOG.md /tmp/AllureOfTheStars-	cp CREDITS /tmp/AllureOfTheStars-	cp LICENSE /tmp/AllureOfTheStars-	cp README.md /tmp/AllureOfTheStars-	tar -czf /tmp/Allure_x_ubuntu-12.04-i386.tar.gz -C /tmp AllureOfTheStars+build-binary-common:+# LH should be installed with that:+#	cabal configure --disable-library-profiling --disable-profiling -f-release --datadir=. --datasubdir=.+#	cabal build+#	cabal register --inplace+	cabal configure --disable-library-profiling --disable-profiling -f-release --prefix=/ --datadir=. --datasubdir=.+	cabal build exe:Allure+	mkdir -p AllureOfTheStars/GameDefinition/fonts+	cabal copy --destdir=AllureOfTheStarsInstall+	cp GameDefinition/config.ui.default AllureOfTheStars/GameDefinition+	cp GameDefinition/fonts/16x16x.fon AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/fonts/8x8xb.fon AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/fonts/8x8x.fon AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/fonts/LICENSE.16x16x AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/fonts/Fix15Mono-Bold.woff AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/fonts/LICENSE.Fix15Mono-Bold AllureOfTheStars/GameDefinition/fonts+	cp GameDefinition/PLAYING.md AllureOfTheStars/GameDefinition+	cp GameDefinition/InGameHelp.txt AllureOfTheStars/GameDefinition+	cp README.md AllureOfTheStars+	cp CHANGELOG.md AllureOfTheStars+	cp LICENSE AllureOfTheStars+	cp CREDITS AllureOfTheStars -# TODO: figure out, whey this must be so different from Linux-build-binary-windows-i386:-	wine cabal configure -frelease-	wine cabal build exe:Allure-	rm -rf /tmp/Allure_x_windows-i386.zip-	rm -rf /tmp/AllureOfTheStarsInstall-	rm -rf /tmp/AllureOfTheStars-	mkdir -p /tmp/AllureOfTheStars/GameDefinition-	wine cabal copy --destdir=Z:/tmp/AllureOfTheStarsInstall-	cp /tmp/AllureOfTheStarsInstall/users/mikolaj/Application\ Data/cabal/bin/Allure.exe /tmp/AllureOfTheStars-	cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition-	cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition-	cp CHANGELOG.md /tmp/AllureOfTheStars-	cp CREDITS /tmp/AllureOfTheStars-	cp LICENSE /tmp/AllureOfTheStars-	cp README.md /tmp/AllureOfTheStars-	cp /home/mikolaj/.wine/drive_c/users/mikolaj/gtk/bin/zlib1.dll /tmp/AllureOfTheStars-	wine Z:/home/mikolaj/.local/share/wineprefixes/7zip/drive_c/Program\ Files/7-Zip/7z.exe a -ssc -sfx Z:/tmp/Allure_x_windows-i386.exe Z:/tmp/AllureOfTheStars+build-binary: build-binary-common+	cp AllureOfTheStarsInstall/bin/Allure AllureOfTheStars+	tar -czf Allure_x_ubuntu-16.04-amd64.tar.gz AllureOfTheStars
README.md view
@@ -1,107 +1,138 @@-Allure of the Stars [![Build Status](https://travis-ci.org/AllureOfTheStars/Allure.svg?branch=master)](https://travis-ci.org/AllureOfTheStars/Allure)[![Build Status](https://drone.io/github.com/AllureOfTheStars/Allure/status.png)](https://drone.io/github.com/AllureOfTheStars/Allure/latest)+Allure of the Stars =================== -[Allure of the Stars] [6] is a near-future Sci-Fi [roguelike] [2]-and tactical squad game. Have a look at [PLAYING.md](GameDefinition/PLAYING.md)-or jump straight into the fray.+[![Build Status](https://travis-ci.org/AllureOfTheStars/Allure.svg?branch=master)](https://travis-ci.org/AllureOfTheStars/Allure)+[![Hackage](https://img.shields.io/hackage/v/Allure.svg)](https://hackage.haskell.org/package/Allure)+[![Join the chat at https://gitter.im/AllureOfTheStars/Allure](https://badges.gitter.im/AllureOfTheStars/Allure.svg)](https://gitter.im/AllureOfTheStars/Allure?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![gameplay screenshot](https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/campaign3.png)+Allure of the Stars[6] is a near-future Sci-Fi roguelike[2]+and tactical squad game.+Try out the browser version of the LambdaHack sample game at+[http://allureofthestars.com/play](http://allureofthestars.com/play)!+(It runs fastest on Chrome. Keyboard commands and savefiles+are supported only on recent enough versions of browsers.+Mouse should work everywhere.) -The game is written in [Haskell] [1] using the [LambdaHack] [10]+![gameplay screenshot](https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/crawl-0.6.0.0-8x8xb.png)++Please see the changelog file for recent improvements+and the issue tracker for short-term plans. Long term goals+are high replayability and auto-balancing through procedural+content generation and persistent content modification+based on player behaviour. Contributions are welcome.++The game is written in Haskell[1] using the LambdaHack [10] roguelike game engine. Long-term goals of the project are high replayability and auto-balancing through procedural content generation and persistent content modification based on player behaviour.  -Installation from binary archives----------------------------------+Game installation from binary archives+-------------------------------------- -Pre-compiled game binaries for some platforms are available through-the [release page] [11] and from the [Nix Packages Collection] [12].-To manually install a binary archive, make sure you have the GTK-libraries suite on your system, unpack the Allure archive-and run the executable in the unpacked directory.+The game runs rather slowly in the browser (fastest on Chrome)+and you are limited to only one font, though it's scalable.+Keyboard input and saving game progress requires recent enough+version of a browser (but mouse input is enough to play the game).+Also, savefiles are prone to corruption on the browser,+e.g., when it's closed while the game is still saving progress+(which takes a long time). Hence, after trying out the game,+you may prefer to use a native binary for your architecture, if it exists. -On Windows, if you don't already have GTK installed (e.g., for the GIMP-picture editor) please download and run (with default settings)-the GTK installer from+Pre-compiled game binaries for some platforms are available through+the release page[11] and from the Nix Packages Collection[12] (Linux)+and AppVeyor (Windows 32bit[17] and Windows 64bit[18]; note that these+no longer work on Windows XP, since Cygwin and MSYS2 dropped support for XP;+they may also be broken in other ways; feedback and help appreciated).+To use a pre-compiled binary archive, unpack it and run the executable+in the unpacked directory. -http://sourceforge.net/projects/gtk-win/+On Linux, make sure you have the SDL2 libraries suite installed on your system+(e.g., libsdl2, libsdl2-ttf). For Windows, the SDL2 and all other needed+libraries are already contained in the game's binary archive.   Screen and keyboard configuration ---------------------------------  The game UI can be configured via a config file.-A file with the default settings, the same as built into the binary, is in-[GameDefinition/config.ui.default](GameDefinition/config.ui.default).-When the game is run for the first time, the file is copied to the official-location, which is `~/.Allure/config.ui.ini` on Linux and-`C:\Users\<username>\AppData\Roaming\Allure\config.ui.ini`-(or `C:\Documents And Settings\user\Application Data\Allure\config.ui.ini`-or something else altogether) on Windows.+A file with the default settings, the same that is built into the binary,+is in [GameDefinition/config.ui.default](https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/config.ui.default).+When the game is run for the first time, the file is copied to the default+user data folder, which is `~/.Allure/` on Linux,+`C:\Users\<username>\AppData\Roaming\Allure\`+(or `C:\Documents And Settings\user\Application Data\Allure\`+or something else altogether) on Windows, and in RMB menu, under+`Inspect/Application/Local Storage` when run inside the Chrome browser. -Screen font can be changed and enlarged by editing the config file- at its official location or by CTRL-right-clicking on the game window.+Screen font can be changed by editing the config file in the user+data folder. For a small game window, the highly optimized+bitmap fonts 16x16x.fon, 8x8x.fon and 8x8xb.fon are the best,+but for larger window sizes or if you require international characters+(e.g. to give custom names to player characters), a modern scalable font+supplied with the game is the only option. The game window automatically+scales according to the specified font size. Display on SDL2+and in the browser is superior to all the other frontends,+due to custom square font and less intrusive ways of highlighting+interesting squares. -If you use the numeric keypad, use the NumLock key on your keyboard-to toggle the game keyboard mode. With NumLock off, you walk with the numeric-keys and run with SHIFT (or CONTROL) and the keys. This mode is probably-the best if you use mouse for running. When you turn NumLock on,-the reversed key setup enforces good playing habits by setting as the default-the run command (which automatically stops at threats, keeping you safe)-and requiring SHIFT (or CONTROL) for the error-prone step by step walking.+If you don't have a numeric keypad, you can use mouse or laptop keys+(uk8o79jl) for movement or you can enable the Vi keys (aka roguelike keys)+in the config file. If numeric keypad doesn't work, toggling+the Num Lock key sometimes helps. If running with the Shift key+and keypad keys doesn't work, try Control key instead.+The game is fully playable with mouse only, as well as with keyboard only,+but the most efficient combination for some players is mouse for go-to,+inspecting, and aiming at distant positions and keyboard for everything else. -If you don't have the numeric keypad, you can use laptop keys (uk8o79jl)-or you can enable the Vi keys (aka roguelike keys) in the config file.+If you are using a terminal frontend, numeric keypad may not work+correctly depending on versions of the libraries, terminfo and terminal+emulators. Toggling the Num Lock key may help.+The curses frontend is not fully supported due to the limitations+of the curses library. With the vty frontend started in an xterm,+Control-keypad keys for running seem to work OK, but on rxvt they do not.+The commands that require pressing Control and Shift together won't+work either, but fortunately they are not crucial to gameplay.   Compilation from source ----------------------- -If you want to compile your own binaries from the source code,+If you want to compile native binaries from the source code, use Cabal (already a part of your OS distribution, or available within-[The Haskell Platform] [7]), which also takes care of all the dependencies.-You also need the GTK libraries for your OS. On Linux, remember to install-the -dev versions as well. On Windows follow [the same steps as for Wine] [13].-On OSX, if you encounter problems, you may want to-[compile the GTK libraries from sources] [14].+The Haskell Platform[7]), which also takes care of all the dependencies. +The recommended frontend is based on SDL2, so you need the SDL2 libraries+for your OS. On Linux, remember to install the -dev versions as well,+e.g., libsdl2-dev and libsdl2-ttf-dev on Ubuntu Linux 16.04.+(Compilation to Javascript for the browser is more complicated+and requires the ghcjs[15] compiler and optionally the Google Closure+Compiler[16] as well. See the+[Makefile](https://github.com/AllureOfTheStars/Allure/blob/master/Makefile)+for more details.)+ The latest official version of the game can be downloaded,-compiled and installed automatically by Cabal from [Hackage] [3] as follows+compiled for SDL2 and installed automatically by Cabal from Hackage[3]+as follows      cabal update-    cabal install gtk2hs-buildtools     cabal install Allure --force-reinstalls  For a newer version, install a matching LambdaHack library snapshot-from a development branch, download the game source from [github] [5]+from a development branch, download the game source from github[5] and run `cabal install` from the main directory. -Compatibility notes-------------------- -If you are using a terminal frontend, numeric keypad may not work-correctly depending on versions of the libraries, terminfo and terminal-emulators. The curses frontend is not fully supported due to the limitations-of the curses library. With the vty frontend started in an xterm,-CTRL-keypad keys for running seem to work OK, but on rxvt they do not.-The commands that require pressing CTRL and SHIFT together won't-work either, but fortunately they are not crucial to gameplay.-For movement, laptop (uk8o79jl) and Vi keys (hjklyubn, if enabled-in config.ui.ini) should work everywhere. GTK works fine, too, both-with numeric keypad and with mouse.-- Testing and debugging --------------------- -The [Makefile](Makefile) contains many sample test commands.+The [Makefile](https://github.com/AllureOfTheStars/Allure/blob/master/Makefile)+contains many sample test commands. Numerous tests that use the screensaver game modes (AI vs. AI)-and the dumb `stdout` frontend are gathered in `make test`.-Of these, travis runs `test-travis-*` on each push to the repo.+and the teletype frontend are gathered in `make test`.+Of these, travis runs `test-travis` on each push to github. Test commands with prefix `frontend` start AI vs. AI games-with the standard, user-friendly gtk frontend.+with the standard, user-friendly frontend.  Run `Allure --help` to see a brief description of all debug options. Of these, `--sniffIn` and `--sniffOut` are very useful (though verbose@@ -114,9 +145,10 @@ Further information ------------------- -For more information, visit the [wiki] [4]-and see [PLAYING.md](GameDefinition/PLAYING.md), [CREDITS](CREDITS)-and [LICENSE](LICENSE).+For more information, visit the wiki[4]+and see [PLAYING.md](https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/PLAYING.md),+[CREDITS](https://github.com/AllureOfTheStars/Allure/blob/master/CREDITS)+and [LICENSE](https://github.com/AllureOfTheStars/Allure/blob/master/LICENSE).  Have fun! @@ -124,7 +156,7 @@ Copyright --------- -Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski+Copyright (c) 2008--2011 Andres Loeh, 2010--2017 Mikolaj Konarski  Allure of the Stars is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by@@ -150,8 +182,13 @@ [6]: http://allureofthestars.com [7]: http://www.haskell.org/platform + [10]: http://github.com/LambdaHack/LambdaHack [11]: https://github.com/AllureOfTheStars/Allure/releases/latest-[12]: http://hydra.cryp.to/search?query=Allure+[12]: http://hydra.nixos.org/search?query=Allure [13]: http://www.haskell.org/haskellwiki/GHC_under_Wine#Code_that_uses_gtk2hs [14]: http://www.edsko.net/2014/04/27/haskell-including-gtk-on-mavericks+[15]: https://github.com/ghcjs/ghcjs+[16]: https://www.npmjs.com/package/google-closure-compiler+[17]: https://ci.appveyor.com/project/Mikolaj/allure-hpt6r/build/artifacts+[18]: https://ci.appveyor.com/project/Mikolaj/allure/build/artifacts
test/test.hs view
@@ -2,5 +2,5 @@  main :: IO () main =-  tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42"-  -- tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42"+  tieKnot $ words "--dbgMsgSer --newGame 2 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 100 --automateAll --keepAutomated --gameMode exploration --setDungeonRng 42 --setMainRng 42"+  -- tieKnot $ words "--dbgMsgSer --newGame 2 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 100 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42"