packages feed

Allure 0.4.100.0 → 0.4.101.1

raw patch · 22 files changed

+1575/−1020 lines, 22 filesdep ~LambdaHackdep ~containers

Dependency ranges changed: LambdaHack, containers

Files

Allure.cabal view
@@ -5,13 +5,13 @@ -- PVP summary: +-+------- breaking API changes --              | | +----- non-breaking API additions --              | | |   +--- code changes with no API change-version:        0.4.100.0+version:        0.4.101.1 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.                .-               <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/safari1.png>>+               <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/campaign2.png>>                .                Please see the changelog file for recent improvements                and the issue tracker for short-term plans. Long term goals@@ -23,9 +23,9 @@                available at <http://hackage.haskell.org/package/LambdaHack>. homepage:      http://allureofthestars.com bug-reports:   http://github.com/AllureOfTheStars/Allure/issues-license:       AGPL+license:       AGPL-3 license-file:  LICENSE-tested-with:   GHC == 7.6.3, GHC == 7.8+tested-with:   GHC == 7.6, GHC == 7.8 data-files:    GameDefinition/config.ui.default, GameDefinition/scores,                GameDefinition/PLAYING.md, README.md, LICENSE, CREDITS,                CHANGELOG.md@@ -63,11 +63,11 @@                       Content.TileKind,                       TieKnot,                       Paths_Allure-  build-depends:      LambdaHack >= 0.4.100.0 && < 0.5.1.0,+  build-depends:      LambdaHack >= 0.4.101.1 && < 0.5.1.0,                       template-haskell >= 2.6 && < 3,                        base       >= 4       && < 5,-                      containers >= 0.5     && < 1,+                      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@@ -82,7 +82,7 @@   ghc-options:        -threaded "-with-rtsopts=-C0.005" -rtsopts    if flag(release)-    ghc-options:      -O2 "-with-rtsopts=-N1"+    ghc-options:      -O2 -fno-ignore-asserts "-with-rtsopts=-N1" -- TODO: -N  test-suite test@@ -93,7 +93,7 @@                       template-haskell >= 2.6 && < 3,                        base       >= 4       && < 5,-                      containers >= 0.5     && < 1,+                      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@@ -108,5 +108,5 @@   ghc-options:        -threaded "-with-rtsopts=-C0.005" -rtsopts    if flag(release)-    ghc-options:      -O2 "-with-rtsopts=-N1"+    ghc-options:      -O2 -fno-ignore-asserts "-with-rtsopts=-N1" -- TODO: -N
CHANGELOG.md view
@@ -1,4 +1,31 @@-## [v0.4.100.0, aka 'The last interstellar thaw'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.99.0..v0.4.100.0)+## [v0.4.101.1, aka 'Officially fun'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.100.0...v0.4.101.1)++- the game is now officially fun to play, with a seal of the Galactic Council+- introduce unique boss monsters and unique artifact items+- add animals that heal the player, in particular as a mid-game reset for HP+- move spaceship airlock to level 10 and beef up spaceship crew+- let AI gang up, attempt stealth and react to player aggressiveness+- spawn actors fast, close to the enemy and in large numbers+- spawn actors less and less often on a given level, but with growing depth+- prefer weapons with effects, if recharged+- make the bracing melee bonus additive, not multiplicative+- let explosions buffet actors around+- make braced actors immune to translocation effects+- make actor domination yet less common and deadly+- use mouse for movement, actor selection, aiming+- don't run straight with selected actors, but go-to cross-hair with them+- speed up default frame rate, slow down projectiles visually+- rework item manipulation UI+- you can pick up many items at once and it costs only one turn+- allow actors to apply and project from the shared stash+- reverse messages shown in player diary+- display actor organs and stats+- split highscore tables wrt game modes+- move score calculation formula to content+- don't keep the default/example config file commented out; was misleading+- update vs the naughtily changed v0.5.0.0 of LambdaHack content API++## [v0.4.100.0, aka 'The last interstellar thaw'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.99.0...v0.4.100.0)  - update vs the unexpectedly thawed v0.5.0.0 of LambdaHack content API - unexpectedly add items with timeouts and temporary effects
GameDefinition/Client/UI/Content/KeyKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -32,7 +32,7 @@       , ("CTRL-k", ([CmdMenu], GameRestart "skirmish"))       , ("CTRL-m", ([CmdMenu], GameRestart "ambush"))       , ("CTRL-b", ([CmdMenu], GameRestart "battle"))-      , ("CTRL-a", ([CmdMenu], GameRestart "campaign"))+      , ("CTRL-n", ([CmdMenu], GameRestart "campaign"))       , ("CTRL-d", ([CmdMenu], GameDifficultyCycle))        -- Movement and terrain alteration@@ -58,63 +58,65 @@            [ TriggerFeature { verb = "descend"                             , object = "10 levels"                             , feature = TK.Cause (IK.Ascend (-10)) } ]))-      , ("semicolon", ([CmdMove], StepToTarget))-      , ("colon", ([CmdMove], Macro "go to target for 100 steps"-                                    ["semicolon", "V"]))-      , ("CTRL-colon", ([CmdMove], Macro "go to target for 10 steps"-                                         ["semicolon", "CTRL-V"]))-      , ("x", ([CmdMove], Macro "explore the closest unknown spot"-                                [ "BackSpace"-                                , "CTRL-question", "semicolon", "V" ]))-      , ("X", ([CmdMove], Macro "autoexplore 100 times"-                                [ "BackSpace"-                                , "'", "CTRL-question", "semicolon", "'"-                                , "V" ]))-      , ("CTRL-X", ([CmdMove], Macro "autoexplore 10 times"-                                      [ "BackSpace"-                                      , "'", "CTRL-question", "semicolon", "'"-                                      , "CTRL-V" ]))+      , ("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 10 times)"+      , ("CTRL-R", ([CmdMove], Macro "rest (wait 25 times)"                                      ["KP_Begin", "CTRL-V"]))-      , ("c", ([CmdMove], AlterDir+      , ("c", ([CmdMove, CmdMinimal], AlterDir            [ AlterFeature { verb = "close"                           , object = "door"                           , feature = TK.CloseTo "closed door" }            ]))-      , ("CTRL-KP_Begin", ([CmdMove], Macro "" ["KP_Begin"]))-      , ("period", ([CmdMove], Macro "" ["KP_Begin"]))-      , ("KP_5", ([CmdMove], Macro "" ["KP_Begin"]))-      , ("CTRL-KP_5", ([CmdMove], Macro "" ["KP_Begin"]))-      , ("i", ([CmdMove], Macro "" ["KP_Begin"]))        -- Item use       --       -- For later:       -- ApplyItem {verb = "eat", object = "food", symbol = ','}-      -- ApplyItem {verb = "activate", object = "emitter", symbol = '_'}+      -- ApplyItem {verb = "apply", object = "emitter", symbol = '_'}       -- ApplyItem {verb = "use", object = "tool", symbol = '~'}       ---      , ("E", ([CmdItem], DescribeItem CEqp))-      , ("P", ([CmdItem], DescribeItem CInv))-      , ("S", ([CmdItem], DescribeItem CSha))-      , ("G", ([CmdItem], DescribeItem CGround))-      , ("A", ([CmdItem], AllOwned))+      , ("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") "an item" True))+               MoveItem [CGround] CEqp (Just "get") "items" True))       , ("d", ([CmdItem], MoveItem [CEqp, CInv, CSha] CGround-                                   Nothing "an item" False))-      , ("e", ([CmdItem], MoveItem [CInv, CSha] CEqp-                                   Nothing "an item" False))-      , ("p", ([CmdItem], MoveItem [CEqp, CSha] CInv-                                   Nothing "an item into inventory backpack"+                                   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 [CInv, CEqp] CSha-                                   Nothing "and share an item" False))+      , ("s", ([CmdItem], MoveItem [CGround, CInv, CEqp] CSha+                                   Nothing "and share items" False))       , ("a", ([CmdItem, CmdMinimal], Apply-           [ ApplyItem { verb = "activate"-                       , object = "applicable item"+           [ ApplyItem { verb = "apply"+                       , object = "consumable"                        , symbol = ' ' }            , ApplyItem { verb = "quaff"                        , object = "drink"@@ -131,7 +133,7 @@                                            , symbol = '?' }]))       , ("f", ([CmdItem, CmdMinimal], Project            [ApplyItem { verb = "fling"-                      , object = "projectable item"+                      , object = "projectile"                       , symbol = ' ' }]))       , ("t", ([CmdItem], Project [ ApplyItem { verb = "throw"                                               , object = "missile"@@ -139,21 +141,22 @@                                   , ApplyItem { verb = "throw"                                               , object = "missile"                                               , symbol = '{' } ]))-      , ("z", ([CmdItem], Project [ApplyItem { verb = "zap"-                                             , object = "mechanism"-                                             , symbol = '-' }]))+--      , ("z", ([CmdItem], Project [ApplyItem { verb = "zap"+--                                             , object = "mechanism"+--                                             , symbol = '-' }]))        -- Targeting-      , ("KP_Multiply", ([CmdTgt, CmdMinimal], TgtEnemy))+      , ("KP_Multiply", ([CmdTgt], TgtEnemy))       , ("backslash", ([CmdTgt], Macro "" ["KP_Multiply"]))-      , ("slash", ([CmdTgt], TgtFloor))-      , ("plus", ([CmdTgt], EpsIncr True))+      , ("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))-      , ("CTRL-question", ([CmdTgt], TgtUnknown))-      , ("CTRL-I", ([CmdTgt], TgtItem))-      , ("CTRL-braceleft", ([CmdTgt], TgtStair True))-      , ("CTRL-braceright", ([CmdTgt], TgtStair False))        -- Automation       , ("equal", ([CmdAuto], SelectActor))@@ -161,27 +164,49 @@       , ("v", ([CmdAuto], Repeat 1))       , ("V", ([CmdAuto], Repeat 100))       , ("CTRL-v", ([CmdAuto], Repeat 1000))-      , ("CTRL-V", ([CmdAuto], Repeat 10))+      , ("CTRL-V", ([CmdAuto], Repeat 25))       , ("apostrophe", ([CmdAuto], Record))       , ("CTRL-T", ([CmdAuto], Tactic))       , ("CTRL-A", ([CmdAuto], Automate))        -- Assorted       , ("question", ([CmdMeta], Help))-      , ("D", ([CmdMeta], History))-      , ("T", ([CmdMeta], MarkSuspect))+      , ("D", ([CmdMeta, CmdMinimal], History))+      , ("T", ([CmdMeta, CmdMinimal], MarkSuspect))       , ("Z", ([CmdMeta], MarkVision))       , ("C", ([CmdMeta], MarkSmell))       , ("Tab", ([CmdMeta], MemberCycle))-      , ("ISO_Left_Tab", ([CmdMeta], MemberBack))+      , ("ISO_Left_Tab", ([CmdMeta, CmdMinimal], MemberBack))       , ("space", ([CmdMeta], Clear))       , ("Escape", ([CmdMeta, CmdMinimal], Cancel))-      , ("Return", ([CmdMeta], Accept))+      , ("Return", ([CmdMeta, CmdTgt], Accept)) +      -- Mouse+      , ("LeftButtonPress",+         ([CmdMouse], macroLeftButtonPress))+      , ("SHIFT-LeftButtonPress",+         ([CmdMouse], macroShiftLeftButtonPress))+      , ("MiddleButtonPress", ([CmdMouse], CursorPointerEnemy))+      , ("SHIFT-MiddleButtonPress", ([CmdMouse], CursorPointerFloor))+      , ("CTRL-MiddleButtonPress",+         ([CmdInternal], Macro "" ["SHIFT-MiddleButtonPress"]))+      , ("RightButtonPress", ([CmdMouse], TgtPointerEnemy))+       -- Debug and others not to display in help screens       , ("CTRL-s", ([CmdDebug], GameSave))+      , ("CTRL-i", ([CmdDebug], GameRestart "battle survival"))       , ("CTRL-f", ([CmdDebug], GameRestart "safari"))+      , ("CTRL-r", ([CmdDebug], GameRestart "safari survival"))       , ("CTRL-e", ([CmdDebug], GameRestart "defense"))-      , ("CTRL-O", ([CmdDebug], DescribeItem COrgan))-      ]+      , ("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))+     ]   }
GameDefinition/Content/CaveKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -21,9 +21,9 @@   , validateSingle = validateSingleCaveKind   , validateAll = validateAllCaveKind   , content =-      [rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena, shallow1empty]+      [rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena]   }-rogue,        arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena, shallow1empty :: CaveKind+rogue,        arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena :: CaveKind  rogue = CaveKind   { csymbol       = 'R'@@ -35,16 +35,16 @@   , cminPlaceSize = DiceXY (2 * d 2 + 2) 4   , cmaxPlaceSize = DiceXY 15 10   , cdarkChance   = d 54 + dl 20-  , cnightChance  = 51+  , cnightChance  = 51  -- always night   , cauxConnects  = 1%3   , cmaxVoid      = 1%6   , cminStairDist = 30   , cdoorChance   = 1%2   , copenChance   = 1%10   , chidden       = 8-  , cactorCoeff   = 20-  , cactorFreq    = [("alien", 33), ("animal", 33), ("robot", 33)]-  , citemNum      = 15 * d 2+  , cactorCoeff   = 150  -- the maze requires time to explore+  , cactorFreq    = [("alien", 50), ("animal", 25), ("robot", 25)]+  , citemNum      = 10 * d 2   , citemFreq     = [("useful", 50), ("treasure", 50)]   , cplaceFreq    = [("rogue", 100)]   , cpassable     = False@@ -59,16 +59,18 @@ arena = rogue   { csymbol       = 'A'   , cname         = "Recreational deck"-  , cfreq         = [("campaign random", 100), ("caveArena", 1)]+  , cfreq         = [("campaign random", 50), ("caveArena", 1)]   , cgrid         = DiceXY (2 * d 2) (2 * d 2)   , cminPlaceSize = DiceXY (2 * d 2 + 3) 4-  , cdarkChance   = d 80 + dl 60-  , cnightChance  = 0+  , 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-  , cactorCoeff   = 40-  , cactorFreq    = [("alien", 15), ("animal", 80), ("robot", 5)]-  , citemNum      = 11 * d 2  -- few rooms+  , cactorCoeff   = 100+  , cactorFreq    = [("alien", 25), ("animal", 70), ("robot", 5)]+  , citemNum      = 9 * d 2  -- few rooms   , cpassable     = True   , cdefTile      = "arenaSet"   , cdarkCorTile  = "trailLit"  -- let trails give off light@@ -77,19 +79,19 @@ empty = rogue   { csymbol       = 'E'   , cname         = "Construction site"-  , cfreq         = [("campaign random", 100), ("caveEmpty", 1)]+  , 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-  , cnightChance  = 0+  , cnightChance  = 0  -- always day   , cauxConnects  = 1   , cmaxVoid      = 1%2   , cminStairDist = 50   , chidden       = 1000-  , cactorCoeff   = 50-  , cactorFreq    = [("alien", 5), ("animal", 15), ("robot", 80)]-  , citemNum      = 9 * d 2  -- few rooms+  , cactorCoeff   = 80+  , cactorFreq    = [("alien", 25), ("animal", 5), ("robot", 70)]+  , citemNum      = 7 * d 2  -- few rooms   , cpassable     = True   , cdefTile      = "emptySet"   , cdarkCorTile  = "floorArenaDark"@@ -102,13 +104,16 @@   , cgrid         = DiceXY (2 + d 2) 3   , cminPlaceSize = DiceXY 12 5   , cmaxPlaceSize = DiceXY 24 15-  , cnightChance  = d 80 + dl 80+  , cdarkChance   = 0  -- few rooms, so all lit+  -- 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-  , cactorCoeff   = 30-  , cactorFreq    = [("alien", 80), ("animal", 5), ("robot", 15)]-  , citemNum      = 16 * d 2  -- an incentive to explore the labyrinth+  , cactorCoeff   = 150  -- the maze requires time to explore+  , cactorFreq    = [("alien", 70), ("animal", 15), ("robot", 15)]+  , citemNum      = 12 * d 2  -- an incentive to explore the labyrinth   , cpassable     = True   , cplaceFreq    = [("noise", 100)]   , cdefTile      = "noiseSet"@@ -123,7 +128,7 @@   , cminPlaceSize = DiceXY 4 4   , cmaxPlaceSize = DiceXY 9 7   , cdarkChance   = 0-  , cnightChance  = 100+  , cnightChance  = 51  -- always night   , cmaxVoid      = 0   , cdoorChance   = 2%10   , copenChance   = 9%10@@ -166,14 +171,14 @@   , cminPlaceSize = DiceXY 3 3   , cmaxPlaceSize = DiceXY 5 5   , cdarkChance   = 0-  , cnightChance  = 100+  , cnightChance  = 51  -- always night   , cauxConnects  = 1   , cdoorChance   = 1%10   , copenChance   = 9%10   , chidden       = 1000   , cactorFreq    = []   , citemNum      = 22 * d 2-  , citemFreq     = [("useful", 100), ("light source", 200)]+  , citemFreq     = [("useful", 100)]   , cplaceFreq    = [("ambush", 100)]   , cpassable     = True   , cdefTile      = "ambushSet"@@ -193,33 +198,35 @@   , cdarkChance   = 0   , cmaxVoid      = 1%10   , cactorFreq    = []  -- safe, nothing spawns+  , citemNum      = 15 * d 2  -- lure them in with loot   , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq arena   , cdarkCorTile  = "emergency walkway"   , clitCorTile   = "emergency walkway"   } shallow2rogue = rogue-  { cfreq         = [("shallow random 2", 100)]+  { cfreq         = [("shallow random 2", 50)]+  , cactorCoeff   = cactorCoeff rogue `div` 2   , cactorFreq    = filter ((/= "alien") . fst) $ cactorFreq rogue   , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq rogue   } 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   } shallow2empty = empty-  { cfreq         = [("shallow random 2", 100)]+  { cfreq         = [("shallow random 2", 20)]   , cactorFreq    = filter ((/= "alien") . fst) $ cactorFreq empty+  , cactorCoeff   = cactorCoeff empty `div` 2   , citemFreq     = filter ((/= "treasure") . fst) $ citemFreq empty   }-shallow1arena = shallow2arena  -- TODO: replace some rooms with oriels?+shallow1arena = shallow2empty  -- TODO: replace some rooms with oriels?   { cname         = "Outermost deck"   , cfreq         = [("shallow random 1", 100)]   , cminPlaceSize = DiceXY (2 * d 2 + 3) 3-  , couterFenceTile = "oriels fence"-  }-shallow1empty = shallow2empty  -- TODO: add oriel areas or glass on floor-  { cname         = "Outermost deck"-  , cfreq         = [("shallow random 1", 100)]+  , cactorCoeff   = 3  -- mostly immobile actors anyway+  , cactorFreq    = [("animal", 8), ("robot", 2), ("immobile robot", 90)]   , couterFenceTile = "oriels fence"   }
GameDefinition/Content/ItemKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -6,12 +6,14 @@ -- | 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@@ -31,9 +33,9 @@  items :: [ItemKind] items =-  [dart, dart200, canOfGlue, harpoon, net, needle, jumpingPole, honingSteel, candle, oilLamp, crankSpotlight, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, contactLens, ring1, ring2, ring3, ring4, ring5, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, 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, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, 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] -dart,    dart200, canOfGlue, harpoon, net, needle, jumpingPole, honingSteel, candle, oilLamp, crankSpotlight, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, contactLens, ring1, ring2, ring3, ring4, ring5, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, 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, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, currency :: ItemKind+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 @@ -61,7 +63,7 @@ symbolHafted     = '\\' symbolWand       = '-'  -- magical rod, transmitter, pistol, rifle _symbolStaff     = '_'  -- scanner-_symbolFood      = ','+_symbolFood      = ','  -- too easy to miss?  -- * Thrown weapons @@ -70,12 +72,12 @@   , iname    = "steak knife"   , ifreq    = [("useful", 100), ("any arrow", 100)]   , iflavour = zipPlain [BrCyan]-  , icount   = 3 * d 3-  , irarity  = [(1, 20), (10, 10)]-  , iverbHit = "prick"+  , icount   = 4 * d 3+  , irarity  = [(1, 10), (10, 20)]+  , iverbHit = "nick"   , iweight  = 100-  , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]-  , ieffects = [Hurt (3 * d 1)]+  , 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     = []@@ -85,12 +87,12 @@   , iname    = "billiard ball"   , ifreq    = [("useful", 100), ("any arrow", 50)]  -- TODO: until arrows added   , iflavour = zipPlain [BrWhite]-  , icount   = 3 * d 3-  , irarity  = [(4, 20), (10, 10)]+  , icount   = 4 * d 3+  , irarity  = [(1, 20), (10, 10)]   , iverbHit = "strike"   , iweight  = 300-  , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]-  , ieffects = [Hurt (2 * d 1)]+  , 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     = []@@ -98,19 +100,19 @@  -- * Exotic thrown weapons -canOfGlue = ItemKind+paralizingProj = ItemKind   { isymbol  = symbolProjectile   , iname    = "can"   , ifreq    = [("useful", 100), ("can of sticky foam", 1)]   , iflavour = zipPlain [Magenta]-  , icount   = dl 4+  , 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]  -- unwieldy+  , ifeature = [toVelocity 50, Identified, Fragile]  -- unwieldy   , idesc    = "A can of liquid, fast-setting, construction foam."   , ikit     = []   }@@ -123,7 +125,7 @@   , irarity  = [(5, 5), (10, 5)]   , iverbHit = "hook"   , iweight  = 4000-  , iaspects = [AddHurtRanged ((d 2 + 2 * dl 5) |*| 10)]+  , iaspects = [AddHurtRanged (d 2 + dl 5 |*| 20)]   , ieffects = [Hurt (4 * d 1), PullActor (ThrowMod 200 50)]   , ifeature = []   , 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."@@ -148,13 +150,13 @@ needle = ItemKind   { isymbol  = symbolProjectile   , iname    = "needle"-  , ifreq    = []+  , ifreq    = [("needle", 1)]  -- special   , iflavour = zipPlain [BrBlue]   , icount   = 9 * d 3-  , irarity  = []+  , irarity  = [(1, 1)]   , iverbHit = "prick"   , iweight  = 1-  , iaspects = [AddHurtRanged ((d 3 + dl 3) |*| 10)]+  , 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."@@ -169,16 +171,16 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [White]   , icount   = 1-  , irarity  = [(1, 2), (10, 1)]+  , irarity  = [(1, 2)]   , iverbHit = "prod"   , iweight  = 10000-  , iaspects = [Timeout $ (d 2 + 2 - dl 2) |*| 10]+  , 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     = []   }-honingSteel = ItemKind+sharpeningTool = ItemKind   { isymbol  = symbolTool   , iname    = "honing steel"   , ifreq    = [("useful", 100)]@@ -193,33 +195,49 @@   , 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 -candle = ItemKind+light1 = ItemKind   { isymbol  = symbolLight   , iname    = "candle"   , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [Brown]-  , icount   = 1-  , irarity  = [(1, 8), (3, 6)]+  , icount   = d 2+  , irarity  = [(1, 10)]   , iverbHit = "scorch"   , iweight  = 500   , iaspects = [ AddLight 3                , AddSight (-2) ]-  , ieffects = [Burn 3]+  , 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     = []   }-oilLamp = ItemKind+light2 = ItemKind   { isymbol  = symbolLight   , iname    = "oil lamp"   , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(5, 5), (10, 5)]+  , irarity  = [(6, 7)]   , iverbHit = "burn"   , iweight  = 1000   , iaspects = [AddLight 3, AddSight (-1)]@@ -229,13 +247,13 @@   , idesc    = "A sizable glass lamp filled with plant oil feeding a wick."   , ikit     = []   }-crankSpotlight = ItemKind+light3 = ItemKind   { isymbol  = symbolLight   , iname    = "crank spotlight"   , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [BrWhite]   , icount   = 1-  , irarity  = [(10, 3)]+  , irarity  = [(10, 5)]   , iverbHit = "snag"   , iweight  = 2400   , iaspects = [AddLight 4, AddArmorRanged $ - d 3]  -- noise and busy hands@@ -249,20 +267,21 @@  gorget = ItemKind   { isymbol  = symbolNecklace-  , iname    = "gorget"+  , iname    = "Old Gorget"   , ifreq    = [("useful", 100)]   , iflavour = zipFancy [BrCyan]   , icount   = 1-  , irarity  = [(4, 1), (10, 2)]+  , irarity  = [(4, 3), (10, 3)]  -- weak, shallow   , iverbHit = "whip"   , iweight  = 30-  , iaspects = [ Periodic-               , Timeout $ (d 3 + 3 - dl 3) |*| 10-               , AddArmorMelee 1-               , AddArmorRanged 1 ]+  , iaspects = [ Unique+               , Periodic+               , Timeout $ d 3 + 3 - dl 3 |*| 10+               , AddArmorMelee $ 2 + d 3+               , AddArmorRanged $ 2 + d 3 ]   , ieffects = [Recharging (RefillCalm 1)]-  , ifeature = [ Durable, Precious, EqpSlot EqpSlotPeriodic "", Identified-               , toVelocity 50 ]  -- not dense enough+  , 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     = []   }@@ -272,7 +291,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipFancy stdCol ++ zipPlain brightCol   , icount   = 1-  , irarity  = [(10, 3)]+  , irarity  = [(10, 2)]   , iverbHit = "whip"   , iweight  = 30   , iaspects = [Periodic]@@ -283,55 +302,75 @@   , ikit     = []   } necklace1 = necklace-  { iaspects = (Timeout $ (d 3 + 4 - dl 3) |*| 10) : iaspects necklace-  , ieffects = [Recharging (RefillHP 1)]+  { 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-  { irarity  = [(2, 0), (10, 1)]-  , iaspects = (Timeout $ (d 3 + 3 - dl 3) |*| 10) : iaspects necklace-  , ieffects = [ Recharging (Impress)+  { 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+  { 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 3 |*| 3)]+  { 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 $ 12 + d 3 |*| 3)]+  { 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-  { irarity  = [(4, 0), (10, 2)]-  , iaspects = [AddSpeed $ d 2, Timeout $ (d 3 + 3 + dl 3) |*| 2]+  { ifreq    = [("treasure", 100)]+  , iaspects = [ Unique, AddMaxHP $ 10 + d 10+               , AddArmorMelee 20, AddArmorRanged 20+               , Timeout $ d 2 + 5 - dl 3 ]                ++ iaspects necklace-  , ieffects = [Recharging (RefillHP (-1))]+  , 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 -contactLens = ItemKind+sightSharpening = ItemKind   { isymbol  = symbolRing-  , iname    = "contact lens"-  , ifreq    = [("useful", 100)]+  , iname    = "Autozoom Contact Lens"+  , ifreq    = [("treasure", 100)]   , iflavour = zipPlain [White]   , icount   = 1-  , irarity  = [(5, 0), (10, 1)]+  , irarity  = [(7, 3), (10, 3)]  -- medium weak, medium shallow   , iverbHit = "rap"   , iweight  = 50-  , iaspects = [AddSight $ d 2, AddHurtMelee $ d 2 |*| 3]+  , iaspects = [Unique, AddSight $ 1 + d 2, AddHurtMelee $ d 2 |*| 3]   , ieffects = []-  , ifeature = [Precious, Identified, Durable, EqpSlot EqpSlotAddSight ""]-  , idesc    = "Advanced design. Never needs to be taken off."+  , 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@@ -347,40 +386,64 @@   , iverbHit = "knock"   , iweight  = 15   , iaspects = []-  , ieffects = [Explode "blast 2"]+  , 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 $ d 2, AddMaxHP $ dl 3 - 5 - d 3]+  , iaspects = [AddSpeed $ d 2, AddMaxHP $ dl 5 - 5 - d 5]   , ieffects = [Explode "distortion"]  -- strong magic   , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddSpeed ""]   } ring2 = ring-  { iaspects = [AddMaxHP $ 3 + dl 5, AddMaxCalm $ dl 6 - 15 - d 6]+  { iaspects = [AddMaxHP $ 10 + dl 10, AddMaxCalm $ dl 5 - 20 - d 5]   , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxHP ""]   } ring3 = ring-  { iaspects = [AddMaxCalm $ 10 + dl 10]+  { iaspects = [AddMaxCalm $ 15 + dl 15]   , 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, 6), (10, 6)]-  , iaspects = [AddHurtMelee $ (d 5 + dl 5) |*| 3, AddMaxHP $ dl 3 - 4 - d 2]+  , 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)]+  { irarity  = [(5, 0), (10, 1)]   , 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) ""]+  } --- * Exploding consumables, often intended to be thrown+-- * Ordinary exploding consumables, often intended to be thrown  potion = ItemKind   { isymbol  = symbolPotion@@ -399,49 +462,69 @@   , ikit     = []   } potion1 = potion-  { ieffects = [ NoEffect "of rose water", Impress-               , OnSmash (ApplyPerfume), OnSmash (Explode "fragrance") ]+  { ieffects = [ NoEffect "of rose water", Impress, RefillCalm (-3)+               , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ]   } potion2 = potion-  { ifreq    = [("useful", 10)]  -- extremely rare-  , irarity  = [(1, 1)]-  , ieffects = [ NoEffect "of attraction", OnSmash (Explode "pheromone")]+  { ifreq    = [("treasure", 100)]+  , irarity  = [(6, 10), (10, 10)]+  , iaspects = [Unique]+  , ieffects = [ NoEffect "of Attraction", Impress, OverfillCalm (-20)+               , OnSmash (Explode "pheromone") ]   } potion3 = potion-  { irarity  = [(1, 5), (10, 5)]-  , ieffects = [RefillHP 5, OnSmash (Explode "healing mist")]+  { irarity  = [(1, 10)]+  , ieffects = [ RefillHP 5, DropItem COrgan "poisoned" True+               , OnSmash (Explode "healing mist") ]   } potion4 = potion-  { irarity  = [(10, 5)]-  , ieffects = [RefillHP 10, OnSmash (Explode "healing mist 2")]+  { irarity  = [(10, 10)]+  , ieffects = [ RefillHP 10, DropItem COrgan "poisoned" True+               , OnSmash (Explode "healing mist 2") ]   } potion5 = potion-  { ieffects = [ OneOf [Impress, DropBestWeapon, RefillHP 5, Burn 3]+  { 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 = [ OneOf [ Dominate, DropBestWeapon, RefillHP 20, Burn 9-                       , InsertMove 4 ]+  , ieffects = [ Impress+               , OneOf [ OverfillCalm (-60)+                       , OverfillHP 20, OverfillHP 10, Burn 10+                       , toOrganActorTurn "fast 20" (20 + d 5) ]                , OnSmash (OneOf [ Explode "healing mist 2"-                                , Explode "healing mist 2"-                                , Explode "pheromone"+                                , Explode "calming mist"+                                , Explode "distressing odor"                                 , Explode "distortion"  -- outlier, OK+                                , Explode "smelly droplet"                                 , Explode "blast 20" ]) ]   } potion7 = potion-  { ieffects = [ DropItem COrgan "poisoned" True, RefillHP 1+  { irarity  = [(1, 15), (10, 5)]+  , ieffects = [ DropItem COrgan "poisoned" True                , OnSmash (Explode "antidote mist") ]   } potion8 = potion-  { ieffects = [ DropItem COrgan "temporary conditions" True, RefillHP 2+  { 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+-- * 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"@@ -449,7 +532,7 @@ flask = ItemKind   { isymbol  = symbolFlask   , iname    = "flask"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("flask", 100)]   , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol   , icount   = 1   , irarity  = [(1, 9), (10, 6)]@@ -466,6 +549,7 @@   { irarity  = [(10, 5)]   , ieffects = [ NoEffect "of strength brew"                , toOrganActorTurn "strengthened" (20 + d 5)+               , toOrganNone "regenerating"                , OnSmash (Explode "strength mist") ]   } flask2 = flask@@ -493,31 +577,35 @@   { 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 "eye drop") ]+               , OnSmash (Explode "blast 10") ]   } flask8 = flask   { irarity  = [(10, 3)]   , ieffects = [ NoEffect "of smelly concoction"                , toOrganActorTurn "keen-smelling" (20 + d 5)-               , OnSmash (Explode "smelly droplet") ]+               , OnSmash (Explode "blast 10") ]   } flask9 = flask-  { ieffects = [ NoEffect "of bait cocktail", toOrganActorTurn "drunk" (5 + d 5)+  { 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)-               , Burn 2, RefillHP 4, OnSmash (Explode "whiskey spray") ]+  { ieffects = [ NoEffect "of whiskey"+               , toOrganActorTurn "drunk" (20 + d 5)+               , Impress, Burn 2, RefillHP 4+               , OnSmash (Explode "whiskey spray") ]   } flask11 = flask-  { irarity  = [(1, 20), (10, 6)]+  { irarity  = [(1, 20), (10, 10)]   , ieffects = [ NoEffect "of regeneration brew"                , toOrganNone "regenerating"                , OnSmash (Explode "healing mist") ]@@ -533,7 +621,7 @@                , toOrganNone "slow resistant"                , OnSmash (Explode "anti-slow mist") ]   }-flask14 = flask  -- but not flask of Calm depletion, since Calm reduced often+flask14 = flask   { irarity  = [(10, 5)]   , ieffects = [ NoEffect "of poison resistance"                , toOrganNone "poison resistant"@@ -570,29 +658,31 @@   , ikit     = []   } scroll1 = scroll-  { irarity  = [(3, 6), (10, 6)]-  , ieffects = [CallFriend 1]+  { 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  = [(1, 7), (10, 5)]-  , ieffects = [NoEffect "of fireworks", Explode "firecracker 7"]+  { irarity  = []+  , ieffects = []   } scroll3 = scroll   { irarity  = [(1, 5), (10, 3)]   , ieffects = [Ascend 1]   } scroll4 = scroll-  { ieffects = [ OneOf [ Teleport $ d 3 |*| 3, RefillCalm 10, RefillCalm (-10)-                       , InsertMove 3, Paralyze 10, Identify CGround ] ]+  { ieffects = [OneOf [ Teleport 5, RefillCalm 5, RefillCalm (-5)+                      , InsertMove 5, Paralyze 10 ]]   } scroll5 = scroll   { irarity  = [(10, 15)]-  , ieffects = [ OneOf [ Summon standardSummon $ d 2-                       , CallFriend 1, Ascend (-1), Ascend 1-                       , RefillCalm 30, RefillCalm (-30)-                       , CreateItem CGround "useful" TimerNone-                       , PolyItem CGround ] ]-               -- TODO: ask player: Escape 1+  , 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]@@ -604,17 +694,26 @@   { irarity  = [(10, 3)]   , ieffects = [InsertMove $ 1 + d 2 + dl 2]   }-scroll9 = scroll-  { irarity  = [(1, 15)]-  , ieffects = [Identify CGround]  -- TODO: ask player: AskPlayer cstore eff?+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+scroll10 = scroll  -- TODO: firecracker only if an item really polymorphed?+                   -- But currently server can't tell.   { irarity  = [(10, 10)]-  , ieffects = [PolyItem CGround]+  , 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 = [ ("alien", 20)+standardSummon = [ ("mobile alien", 20)                  , ("mobile animal", 50)                  , ("mobile robot", 30) ] @@ -630,8 +729,8 @@   , iverbHit = "thud"   , iweight  = 7000   , iaspects = [ AddHurtMelee (-3)-               , AddArmorMelee $ (d 2 + dl 3) |*| 5-               , AddArmorRanged $ (d 2 + dl 3) |*| 5 ]+               , 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 ]@@ -644,8 +743,8 @@   , irarity  = [(6, 9), (10, 3)]   , iweight  = 12000   , iaspects = [ AddHurtMelee (-3)-               , AddArmorMelee $ (1 + d 2 + dl 4) |*| 5-               , AddArmorRanged $ (1 + d 2 + dl 4) |*| 5 ]+               , 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@@ -657,7 +756,7 @@   , irarity  = [(5, 9), (10, 9)]   , iverbHit = "flap"   , iweight  = 100-  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) * 3+  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) |*| 3                , AddArmorRanged $ d 2 |*| 5 ]   , ieffects = []   , ifeature = [ toVelocity 30  -- flaps and flutters@@ -670,18 +769,19 @@   , iflavour = zipPlain [BrCyan]   , irarity  = [(1, 9), (10, 3)]   , iweight  = 300-  , iaspects = [ AddArmorMelee $ (1 + dl 2) |*| 5-               , AddArmorRanged $ (1 + dl 2) |*| 5 ]+  , 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"+  { iname    = "Welding Handgear"   , iflavour = zipFancy [BrRed]   , irarity  = [(1, 3), (10, 3)]   , iweight  = 500-  , iaspects = [ AddHurtMelee $ (dl 4 - 6) |*| 3-               , AddArmorMelee $ (2 + dl 2) |*| 5-               , AddArmorRanged $ (2 + dl 2) |*| 5 ]+  , 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."   } @@ -700,23 +800,24 @@   , iweight  = 2000   , iaspects = [ AddArmorMelee 40                , AddHurtMelee (-30)-               , Timeout $ (d 3 + 3 - dl 3) |*| 2 ]-  , ieffects = []  -- [Recharging (PushActor (ThrowMod 200 50))]-  , ifeature = [ toVelocity 30  -- unwieldy to throw and blunt+               , 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  = [(7, 5)]+  , irarity  = [(8, 3)]   , iflavour = zipPlain [Green]   , iweight  = 3000   , iaspects = [ AddArmorMelee 80                , AddHurtMelee (-70)-               , Timeout $ (d 3 + 6 - dl 3) |*| 2 ]-  , ieffects = []  -- [Recharging (PushActor (ThrowMod 400 50))]-  , ifeature = [ toVelocity 20  -- unwieldy to throw and blunt+               , 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."   }@@ -729,10 +830,12 @@   , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrCyan]   , icount   = 1-  , irarity  = [(1, 12), (10, 4)]+  , irarity  = [(1, 20)]   , iverbHit = "stab"   , iweight  = 1000-  , iaspects = [AddHurtMelee $ (d 3 + dl 3) |*| 3, AddArmorMelee $ d 2 |*| 5]+  , 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 ]@@ -740,8 +843,9 @@   , ikit     = []   } daggerDropBestWeapon = dagger-  { ifreq    = [("useful", 30)]-  , irarity  = [(1, 1), (10, 2)]+  { 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,@@ -750,8 +854,9 @@   -- 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 ++ [Recharging DropBestWeapon]+  , 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@@ -760,10 +865,11 @@   , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrMagenta]   , icount   = 1-  , irarity  = [(4, 12), (10, 2)]+  , irarity  = [(5, 15)]   , iverbHit = "club"   , iweight  = 1500-  , iaspects = [AddHurtMelee $ (d 2 + dl 2) |*| 3]+  , 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 ]@@ -771,16 +877,17 @@   , ikit     = []   } hammerParalyze = hammer-  { ifreq    = [("useful", 30)]-  , irarity  = [(4, 1), (10, 2)]-  , iaspects = iaspects hammer ++ [Timeout $ (d 2 + 3 - dl 2) |*| 2]+  { 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    = "smithhammer"-  , ifreq    = [("useful", 30)]-  , irarity  = [(4, 1), (10, 2)]-  , iaspects = iaspects hammer ++ [Timeout $ (d 4 + 4 - dl 4) |*| 2]+  { 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@@ -789,30 +896,34 @@   , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrBlue]   , icount   = 1-  , irarity  = [(3, 1), (6, 16), (10, 8)]+  , irarity  = [(4, 1), (5, 15)]   , iverbHit = "slash"   , iweight  = 2000   , iaspects = []   , ieffects = [Hurt (10 * d 1)]-  , ifeature = [ toVelocity 20  -- ensuring it hits with the tip costs speed+  , 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    = "an antique sword"-  , ifreq    = [("useful", 30)]-  , irarity  = [(3, 1), (10, 2)]-  , iaspects = iaspects sword ++ [Timeout $ (d 4 + 5 - dl 4) |*| 2]+  , 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-  { ifreq    = [("useful", 30)]-  , irarity  = [(3, 0), (10, 1)]-  , iaspects = iaspects sword ++ [Timeout $ (d 4 + 5 - dl 4) |*| 2]-  , ieffects = ieffects sword ++ [Recharging $ DropItem COrgan "temporary conditions" True]+  { 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@@ -824,18 +935,18 @@   , irarity  = [(7, 1), (10, 10)]   , iverbHit = "impale"   , iweight  = 3000-  , iaspects = [AddArmorMelee $ (1 + dl 3) |*| 5]+  , iaspects = [AddArmorMelee $ 1 + dl 3 |*| 5]   , ieffects = [Hurt (12 * d 1)]-  , ifeature = [ toVelocity 20  -- not balanced+  , 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    = "halberd"-  , ifreq    = [("useful", 30)]-  , irarity  = [(7, 1), (10, 2)]-  , iaspects = iaspects halberd ++ [Timeout $ (d 5 + 5 - dl 5) |*| 2]+  { 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."   }@@ -870,34 +981,45 @@ gem = ItemKind   { isymbol  = symbolGem   , iname    = "gem"-  , ifreq    = [("treasure", 100)]+  , ifreq    = [("treasure", 100), ("gem", 1)]   , iflavour = zipPlain $ delete BrYellow brightCol  -- natural, so not fancy   , icount   = 1   , irarity  = []   , iverbHit = "tap"   , iweight  = 50-  , iaspects = [AddLight 1, AddSpeed (-1)]  -- reflects strongly, distracts+  , 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  = [(2, 0), (10, 10)]+  { irarity  = [(3 * 10/12, 0), (10, 12)]   } gem2 = gem-  { irarity  = [(4, 0), (10, 15)]+  { irarity  = [(5 * 10/12, 0), (10, 14)]   } gem3 = gem-  { irarity  = [(6, 0), (10, 20)]+  { 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", 1)]   , iflavour = zipPlain [BrYellow]   , icount   = 10 + d 20 + dl 20-  , irarity  = [(1, 10), (6, 25), (10, 10)]+  , irarity  = [(1, 25), (10, 10)]   , iverbHit = "tap"   , iweight  = 1   , iaspects = []
GameDefinition/Content/ItemKindActor.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -16,54 +16,64 @@  actors :: [ItemKind] actors =-  [warrior, pilot, engineer, doctor, soldier, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot]+  [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,    pilot, engineer, doctor, soldier, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot :: ItemKind+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  -- * Hunams  warrior = ItemKind   { isymbol  = '@'   , iname    = "mercenary"  -- modified if in hero faction-  , ifreq    = [("hero", 100), ("civilian", 100)]+  , ifreq    = [("hero", 100), ("civilian", 100), ("mobile", 1)]   , iflavour = zipPlain [BrBlack]  -- modified if in hero faction   , icount   = 1   , irarity  = [(1, 5)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 60  -- partially from clothes and assumed first aid+  , iaspects = [ AddMaxHP 80  -- partially from clothes and assumed first aid+                              -- also possibly from artificial skin                , AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.fromList [(AbProject, 1), (AbApply, 1)]-                   -- TODO: on a ring?-               , AddSight 3 ]  -- not via eyes, but feel, hearing, etc.+               , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 4", COrgan)]+  , ikit     = [ ("fist", COrgan), ("foot", COrgan), ("eye 5", COrgan)+               , ("sapient brain", COrgan) ]   }-pilot = warrior+warrior2 = warrior   { iname    = "pilot" }-engineer = warrior+warrior3 = warrior   { iname    = "engineer" }-doctor = warrior+warrior4 = warrior   { iname    = "doctor" }  soldier = warrior   { iname    = "soldier"-  , ifreq    = [("soldier", 100)]+  , ifreq    = [("soldier", 100), ("mobile", 1)]   , ikit     = ikit warrior ++ [("starting weapon", CEqp)]   }+sniper = warrior+  { iname    = "sniper"+  , ifreq    = [("sniper", 100), ("mobile", 1)]+  , ikit     = ikit warrior+               ++ [ ("ring of opportunity sniper", CEqp)+                  , ("any arrow", CInv), ("any arrow", CInv)+                  , ("any arrow", CInv), ("any arrow", CInv)+                  , ("flask", CInv), ("light source", CInv)+                  , ("light source", CInv), ("light source", CInv) ]+  } -clerk = warrior+civilian = warrior   { iname    = "clerk"-  , ifreq    = [("civilian", 100)] }-hairdresser = clerk+  , ifreq    = [("civilian", 100), ("mobile", 1)] }+civilian2 = civilian   { iname    = "hairdresser" }-lawyer = clerk+civilian3 = civilian   { iname    = "lawyer" }-peddler = clerk+civilian4 = civilian   { iname    = "peddler" }-taxCollector = clerk+civilian5 = civilian   { iname    = "tax collector" }  -- * Aliens@@ -71,92 +81,159 @@ eye = ItemKind   { isymbol  = 'w'   , iname    = "beckoning walker"-  , ifreq    = [("alien", 100), ("horror", 100)]-  , iflavour = zipPlain [BrRed]+  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , iflavour = zipFancy [BrRed]   , icount   = 1-  , irarity  = [(3, 4), (10, 10)]+  , irarity  = [(4, 6), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.fromList [(AbProject, 1), (AbApply, 1)]-               , AddSight 4 ]+  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 20+               , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ]   , 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), ("tentacle", COrgan)-               , ("tentacle", COrgan)-               , ("eye 4", COrgan) ]+  , ikit     = [ ("foot", COrgan), ("tentacle", COrgan)+               , ("eye 5", COrgan)+               , ("sapient brain", COrgan) ]   } fastEye = ItemKind   { isymbol  = 'b'   , iname    = "crawling biter"-  , ifreq    = [("alien", 100), ("horror", 100)]-  , iflavour = zipPlain [BrBlue]+  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , iflavour = zipFancy [BrBlue]   , icount   = 1-  , irarity  = [(3, 2), (10, 8)]+  , irarity  = [(4, 3), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 5, AddMaxCalm 60, AddSpeed 30-               , AddSight 4 ]+  , iaspects = [ AddMaxHP 5, AddMaxCalm 60, AddSpeed 30 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "It bites as blindingly fast as it runs. Or rolls? Or crawls? Also, cuts and pierces."-  , ikit     = [ ("tentacle", COrgan), ("tentacle", COrgan)-               , ("tentacle", COrgan), ("tentacle", COrgan)-               , ("jaw", COrgan)-               , ("eye 4", COrgan), ("speed gland 10", COrgan) ]+  , ikit     = [ ("tentacle", COrgan), ("jaw", COrgan)+               , ("eye 4", COrgan), ("speed gland 10", COrgan)+               , ("sapient brain", COrgan) ]   }-nose = ItemKind+nose = ItemKind  -- depends solely on smell   { isymbol  = 'h'   , iname    = "tentacled horror"-  , ifreq    = [("alien", 100), ("horror", 100)]-  , iflavour = zipPlain [BrGreen]+  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , iflavour = zipFancy [BrGreen]   , icount   = 1-  , irarity  = [(3, 4), (10, 6)]+  , irarity  = [(4, 5), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 30, AddSpeed 18-               , AddSkills $ EM.fromList [(AbProject, -1), (AbApply, -1)]-               , AddSmell 3 ]  -- depends solely on smell+  , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 18+               , AddSkills $ EM.fromList [(AbProject, -1)] ]   , ieffects = []   , ifeature = [Durable, Identified]-  , idesc    = "A blind, slimy mass of clawing, stinging and burning. You'd think it's mindless, but as soon as it touches your trembling body, it's always one step ahead."-  , ikit     = [ ("smallClaw", COrgan)-               , ("tentacle", COrgan), ("tentacle", COrgan)+  , 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), ("claw", COrgan)                , ("tentacle", COrgan), ("tentacle", COrgan)-               , ("thorn", COrgan), ("sting", COrgan) ]+               , ("thorn", COrgan), ("sting", COrgan)+               , ("sapient brain", COrgan) ]   } elbow = ItemKind   { isymbol  = 's'   , iname    = "creepy shooter"-  , ifreq    = [("alien", 100), ("horror", 100)]-  , iflavour = zipPlain [BrMagenta]+  , ifreq    = [("alien", 100), ("horror", 100), ("mobile alien", 100)]+  , iflavour = zipFancy [BrMagenta]   , icount   = 1-  , irarity  = [(6, 1), (10, 5)]+  , irarity  = [(6, 1), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 12, AddMaxCalm 90, AddSpeed 26+  , iaspects = [ AddMaxHP 12, AddMaxCalm 90, AddSpeed 21                , AddSkills-                 $ EM.fromList [(AbProject, 1), (AbApply, 1), (AbMelee, -1)]-               , AddSight 15 ]+                 $ EM.fromList [(AbProject, 2), (AbApply, 1), (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)                , ("any arrow", CInv), ("any arrow", CInv)-               , ("any arrow", CInv), ("any arrow", CInv) ]+               , ("any arrow", CInv), ("any arrow", CInv)+               , ("sapient brain", COrgan) ]   }+torsor = ItemKind+  { isymbol  = 'M'+  , iname    = "The Maker of Contact"+  , ifreq    = [("alien", 100), ("mobile", 1)]+  , iflavour = zipFancy [BrCyan]+  , icount   = 1+  , irarity  = [(11 * 10/12, 0), (10, 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 = []+  , 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)+               , ("gem", CInv), ("gem", CInv), ("gem", CInv), ("gem", CInv)+               , ("sapient brain", COrgan) ]+  }  -- * Animals  -- They need rather strong melee, because they don't use items. -- Unless/until they level up. -animalSkillMalus :: Skills-animalSkillMalus =-  EM.fromList $ zip [AbDisplace, AbMoveItem, AbProject, AbApply] [-1, -1..]-+goldenJackal = ItemKind  -- basically a much smaller and slower hyena+  { isymbol  = 'j'+  , iname    = "golden jackal"+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 50)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "thud"+  , iweight  = 13000+  , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 22 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  , ikit     = [ ("small jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan)+               , ("animal brain", COrgan) ]+  }+griffonVulture = ItemKind+  { isymbol  = 'v'+  , iname    = "griffon vulture"+  , ifreq    = [("animal", 100), ("horror", 100), ("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) ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  , ikit     = [ ("screeching beak", COrgan)  -- in reality it grunts and hisses+               , ("claw", COrgan), ("eye 6", COrgan)+               , ("animal brain", COrgan) ]+  }+skunk = ItemKind+  { isymbol  = 's'+  , iname    = "hog-nosed skunk"+  , ifreq    = [("animal", 100), ("horror", 100), ("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) ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  , ikit     = [ ("scent gland", COrgan)+               , ("small claw", COrgan), ("snout", COrgan)+               , ("nostril", COrgan), ("eye 2", COrgan)+               , ("animal brain", COrgan) ]+  } armadillo = ItemKind   { isymbol  = 'a'   , iname    = "giant armadillo"@@ -167,13 +244,13 @@   , iverbHit = "thud"   , iweight  = 80000   , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 18-               , AddSkills $ EM.insert AbAlter (-1) animalSkillMalus-               , AddSight 3 ]+               , AddSkills $ EM.singleton AbAlter (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("claw", COrgan), ("snout", COrgan), ("armored skin", COrgan)-               , ("nostril", COrgan) ]+               , ("nostril", COrgan), ("eye 2", COrgan)+               , ("animal brain", COrgan) ]   } gilaMonster = ItemKind   { isymbol  = 'g'@@ -184,66 +261,66 @@   , irarity  = [(2, 5), (10, 3)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 15-               , AddSkills $ EM.insert AbAlter (-1) animalSkillMalus-               , AddSight 3 ]+  , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 15+               , AddSkills $ EM.singleton AbAlter (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("venom tooth", COrgan), ("small claw", COrgan)-               , ("eye 4", COrgan), ("nostril", COrgan) ]+               , ("eye 5", COrgan), ("nostril", COrgan)+               , ("animal brain", COrgan) ]   } rattlesnake = ItemKind-  { isymbol  = 'r'+  { isymbol  = 's'   , iname    = "rattlesnake"   , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1-  , irarity  = [(3, 2), (10, 4)]+  , irarity  = [(3, 3), (10, 5)]   , iverbHit = "thud"   , iweight  = 80000   , iaspects = [ AddMaxHP 25, AddMaxCalm 60, AddSpeed 15-               , AddSkills $ EM.insert AbAlter (-1) animalSkillMalus-               , AddSight 3 ]+               , AddSkills $ EM.singleton AbAlter (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = [ ("venom fang", COrgan)-               , ("eye 4", COrgan), ("nostril", COrgan) ]+               , ("eye 5", COrgan), ("nostril", COrgan)+               , ("animal brain", COrgan) ]   }-komodoDragon = ItemKind  -- bad hearing+komodoDragon = ItemKind  -- bad hearing; regeneration makes it very powerful   { isymbol  = 'k'   , iname    = "Komodo dragon"   , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(5, 5), (10, 7)]+  , irarity  = [(7, 0), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 40, AddMaxCalm 60, AddSpeed 16-               , AddSkills animalSkillMalus, AddSight 3 ]+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 16 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("large tail", COrgan), ("jaw", COrgan), ("small claw", COrgan)+  , ikit     = [ ("large tail", COrgan), ("jaw", COrgan), ("claw", COrgan)                , ("speed gland 4", COrgan), ("armored skin", COrgan)-               , ("eye 2", COrgan), ("nostril", COrgan) ]+               , ("eye 2", COrgan), ("nostril", COrgan)+               , ("animal brain", COrgan) ]   } hyena = ItemKind   { isymbol  = 'h'   , iname    = "spotted hyena"-  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]-  , iflavour = zipPlain [Red]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 20)]+  , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(4, 6), (10, 6)]+  , irarity  = [(4, 1), (10, 8)]   , iverbHit = "thud"-  , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 30-               , AddSkills animalSkillMalus, AddSight 3 ]+  , iweight  = 60000+  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 30 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [("jaw", COrgan), ("eye 4", COrgan), ("nostril", COrgan)]+  , ikit     = [ ("jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan)+               , ("animal brain", COrgan) ]   } alligator = ItemKind   { isymbol  = 'a'@@ -251,76 +328,105 @@   , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(10, 8)]+  , irarity  = [(6, 1), (10, 9)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 30, AddMaxCalm 60, AddSpeed 17-               , AddArmorMelee 30, AddArmorRanged 30-               , AddSkills animalSkillMalus, AddSight 3 ]+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 15 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [ ("large jaw", COrgan), ("large tail", COrgan), ("claw", COrgan)-               , ("armored skin", COrgan), ("eye 4", COrgan) ]+  , ikit     = [ ("large jaw", COrgan), ("large tail", COrgan)+               , ("small claw", COrgan)+               , ("armored skin", COrgan), ("eye 5", COrgan)+               , ("animal brain", COrgan) ]   }+rhinoceros = ItemKind+  { isymbol  = 'R'+  , iname    = "The Maddened Rhinoceros"+  , ifreq    = [("animal", 100), ("mobile", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 1+  , irarity  = [(1 * 10/12, 1000), (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 = []+  , ifeature = [Durable, Identified]+  , idesc    = "The last of its kind. Blind with rage. Charges at deadly speed."+  , ikit     = [ ("armored skin", COrgan), ("eye 2", COrgan)+               , ("horn", COrgan), ("snout", COrgan)+               , ("animal brain", COrgan) ]+  }  -- * Non-animal animals +beeSwarm = ItemKind+  { isymbol  = 'b'+  , iname    = "bee swarm"+  , ifreq    = [("animal", 100), ("horror", 100)]+  , iflavour = zipPlain [Brown]+  , icount   = 1+  , irarity  = [(1, 3), (10, 6)]+  , iverbHit = "thud"+  , iweight  = 1000+  , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30+               , AddSkills $ EM.singleton AbAlter (-1) ]  -- armor in sting+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  , ikit     = [ ("bee sting", COrgan), ("vision 4", COrgan)+               , ("insect mortality", COrgan), ("animal brain", COrgan) ]+  } hornetSwarm = ItemKind   { isymbol  = 'h'   , iname    = "hornet swarm"   , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1-  , irarity  = [(5, 1), (10, 5)]+  , irarity  = [(5, 1), (10, 10)]   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 5, AddMaxCalm 60, AddSpeed 30, AddSight 2-               , AddSkills $ EM.insert AbAlter (-1) animalSkillMalus-               , AddArmorMelee 90, AddArmorRanged 90 ]+  , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30+               , AddSkills $ EM.singleton AbAlter (-1)+               , AddArmorMelee 80, AddArmorRanged 80 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [("sting", COrgan)]+  , ikit     = [ ("sting", COrgan), ("vision 4", COrgan)+               , ("insect mortality", COrgan), ("animal brain", COrgan) ]   } thornbush = ItemKind-  { isymbol  = 'b'-  , iname    = "rose bush"+  { isymbol  = 't'+  , iname    = "thornbush"   , ifreq    = [("animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1-  , irarity  = [(1, 1)]+  , irarity  = [(1, 3)]   , iverbHit = "thud"   , iweight  = 80000   , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20-               , AddSkills-                 $ EM.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList (zip [AbWait, AbMelee] [1, 1..])-               , AddArmorMelee 30, AddArmorRanged 30 ]+               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""-  , ikit     = [("thorn", COrgan)]+  , ikit     = [("thorn", COrgan), ("armored skin", COrgan)]   }  -- * Robots -robotSkillMalus :: Skills-robotSkillMalus = EM.fromList $ zip [AbApply] [-1]- razorwireFence = ItemKind   { isymbol  = 'f'   , iname    = "razorwire fence"-  , ifreq    = [("robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [Cyan]   , icount   = 1-  , irarity  = [(1, 1)]+  , irarity  = [(3 * 10/12, 0), (4, 2)]   , iverbHit = "thud"   , iweight  = 80000   , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20-               , AddSkills-                 $ EM.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList (zip [AbWait, AbMelee] [1, 1..])+               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])                , AddArmorMelee 50, AddArmorRanged 50 ]   , ieffects = []   , ifeature = [Durable, Identified]@@ -330,16 +436,14 @@ electricFence = ItemKind   { isymbol  = 'f'   , iname    = "electric fence"-  , ifreq    = [("robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(1, 1)]+  , irarity  = [(3 * 10/12, 0), (4, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 50-               , AddSkills-                 $ EM.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList (zip [AbWait, AbMelee] [1, 1..])+  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 40+               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])                , AddArmorMelee 50, AddArmorRanged 50 ]   , ieffects = []   , ifeature = [Durable, Identified]@@ -349,60 +453,88 @@ activeFence = ItemKind   { isymbol  = 'f'   , iname    = "active fence"-  , ifreq    = [("robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 100)]   , iflavour = zipPlain [Red]   , icount   = 1-  , irarity  = [(4, 0), (5, 1)]+  , irarity  = [(3 * 10/12, 0), (4, 1)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20, AddSight 6-               , AddSkills-                 $ EM.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList [(AbWait, 1), (AbProject, 2)]+  , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20+               , AddSkills $ EM.fromList [(AbWait, 1), (AbProject, 3)]                , AddArmorMelee 50, AddArmorRanged 50 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Makeshift, mostly non-lethal, autonomous perimeter defense outpost."-  , ikit     = [ ("needle", CInv), ("can of sticky foam", CInv)-               , ("can of sticky foam", CInv), ("can of sticky foam", CInv) ]+  , ikit     = [ ("vision 6", COrgan)+               , ("needle", CInv), ("can of sticky foam", CInv) ]   } steamFaucet = ItemKind   { isymbol  = 'f'   , iname    = "steam faucet"-  , ifreq    = [("robot", 100)]+  , ifreq    = [("robot", 50), ("immobile robot", 50)]   , iflavour = zipPlain [BrWhite]   , icount   = 1-  , irarity  = [(1, 1)]+  , irarity  = [(5, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 5-               , AddSkills-                 $ EM.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList (zip [AbWait, AbMelee] [1, 1..])+  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 10+               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])                , AddArmorMelee 80, AddArmorRanged 80 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A cracked valve on one of the superheated water pipes spreading radially outward from the tokamak level."-  , ikit     = [("boiling vent", COrgan), ("fissure", COrgan)]+  , ikit     = [("boiling vent", COrgan), ("boiling fissure", COrgan)]   } biogasFaucet = ItemKind   { isymbol  = 'f'   , iname    = "biogas faucet"-  , ifreq    = [("robot", 33)]  -- very rare+  , ifreq    = [("robot", 50), ("immobile robot", 100)]   , iflavour = zipPlain [BrGreen]   , icount   = 1-  , irarity  = [(3, 0), (4, 1)]+  , irarity  = [(5, 2)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 5+  , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3+               , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "An emergency pressure-release vent on a smelly biogas pipe."+  , ikit     = [("biogas vent", COrgan), ("biogas fissure", COrgan)]+  }+medbotFaucet = ItemKind+  { isymbol  = 'f'+  , iname    = "nano medbot faucet"+  , ifreq    = [("robot", 50), ("immobile robot", 400)]+  , 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..]) ]+  , 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."+  , ikit     = [("medbot vent", COrgan), ("medbot fissure", COrgan)]+  }+surveillanceDrone = ItemKind+  { isymbol  = 'd'+  , iname    = "surveillance drone"+  , ifreq    = [("robot", 100), ("horror", 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.fromDistinctAscList (zip [minBound..maxBound] [-1, -1..])-                   `addSkills` EM.fromList (zip [AbWait] [1, 1..])+                 $ EM.fromList+                 $ zip [AbDisplace, AbMoveItem, AbProject, AbMelee] [-1, -1..]                , AddArmorMelee 80, AddArmorRanged 80 ]   , ieffects = []   , ifeature = [Durable, Identified]-  , idesc    = "An emergency pressure-release vent on a liquefied biogas pipe."-  , ikit     = [("explosion vent", COrgan)]+  , 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."+  , ikit     = [ ("vision 14", COrgan), ("robot brain", COrgan) ]   } shepherdDrone = ItemKind   { isymbol  = 'd'@@ -410,18 +542,19 @@   , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [BrRed]   , icount   = 1-  , irarity  = [(1, 2)]+  , irarity  = [(1, 7)]   , iverbHit = "thud"   , iweight  = 1000-  , iaspects = [ AddMaxHP 2, AddMaxCalm 60, AddSpeed 30, AddSight 4+  , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 30                , AddSkills                  $ EM.fromList-                 $ zip [AbApply, AbDisplace, AbMoveItem, AbProject] [-1, -1..]-               , AddArmorMelee 90, AddArmorRanged 90 ]+                 $ zip [AbDisplace, AbMoveItem, AbProject] [-1, -1..]+               , AddArmorMelee 80, AddArmorRanged 80 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "A shabby drone for bringing cows home."-  , ikit     = [("eye2", COrgan), ("live wire", COrgan)]+  , ikit     = [ ("eye 4", COrgan), ("live wire", COrgan)+               , ("robot brain", COrgan) ]   } huntingDrone = ItemKind   { isymbol  = 'd'@@ -429,18 +562,19 @@   , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Green]   , icount   = 1-  , irarity  = [(4, 0), (5, 1), (10, 2)]+  , irarity  = [(3, 0), (5, 2), (10, 4)]   , iverbHit = "thud"   , iweight  = 500-  , iaspects = [ AddMaxHP 2, AddMaxCalm 60, AddSpeed 40, AddSight 4+  , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 40                , AddSkills                  $ EM.fromList-                 $ zip [AbApply, AbDisplace, AbMoveItem, AbMelee] [-1, -1..]-               , AddArmorMelee 90, AddArmorRanged 90 ]+                 $ zip [AbDisplace, AbMoveItem, AbMelee] [-1, -1..]+               , AddArmorMelee 80, AddArmorRanged 80 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Originally designed for hunting down and putting to sleep stray animals. The sleeping agent has long since dried up."-  , ikit     = [("eye2", COrgan), ("needle", CInv)]+  , ikit     = [ ("eye 5", COrgan), ("needle", CInv)+               , ("robot brain", COrgan) ]   } homeRobot = ItemKind   { isymbol  = 'r'@@ -449,16 +583,16 @@   , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1-  , irarity  = [(1, 10), (10, 6)]+  , irarity  = [(1, 20), (10, 6)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 10, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.insert AbProject (-1) robotSkillMalus-               , AddSmell 2 ]+  , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20+               , AddSkills $ EM.singleton AbProject (-1) ]   , ieffects = []   , ifeature = [Durable, Identified]-  , idesc    = "Once a timid household robot, it magnificently adapted to the deadly environment."-  , ikit     = [("fist", COrgan), ("eye2", COrgan)]+  , idesc    = "Once a timid household robot, now sufficiently adapted to survive in the deadly environment."+  , ikit     = [ ("fist", COrgan), ("eye 2", COrgan), ("nostril", COrgan)+               , ("robot brain", COrgan) ]   } wasteRobot = ItemKind   { isymbol  = 'r'@@ -470,14 +604,14 @@   , irarity  = [(1, 10), (10, 6)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 15-               , AddSmell 2 ]+  , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 15 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "You are not in its database, hence you are waste."   , ikit     = [ ("jaw", COrgan), ("tentacle", COrgan)-               , ("waste container", COrgan)-               , ("armored skin", COrgan), ("eye3", COrgan) ]+               , ("waste container", COrgan), ("armored skin", COrgan)+               , ("eye 2", COrgan), ("nostril", COrgan)+               , ("robot brain", COrgan) ]   } lightRobot = ItemKind   { isymbol  = 'r'@@ -486,17 +620,17 @@                , ("construction robot", 1) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(1, 8), (10, 8)]+  , irarity  = [(3, 1), (10, 10)]   , iverbHit = "thud"   , iweight  = 80000-  , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 30-               , AddSkills $ EM.insert AbProject 1 robotSkillMalus-               , AddSight 3, AddLight 3 ]  -- light can't be turned off+  , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 30+               , AddSkills $ EM.singleton AbProject 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Interior and exterior decoration robot. Strongly fancies deep reds recently."-  , ikit     = [ ("claw", COrgan), ("tentacle", COrgan)-               , ("armored skin", COrgan), ("eye4", COrgan) ]+  , ikit     = [ ("claw", COrgan), ("tentacle", COrgan), ("spotlight", COrgan)+               , ("armored skin", COrgan), ("eye 5", COrgan)+               , ("robot brain", COrgan) ]   } heavyRobot = ItemKind   { isymbol  = 'r'@@ -505,16 +639,39 @@                , ("construction robot", 100) ]   , iflavour = zipPlain [BrRed]   , icount   = 1-  , irarity  = [(1, 4), (10, 10)]+  , irarity  = [(5, 1), (10, 10)]   , iverbHit = "thud"   , iweight  = 800000-  , iaspects = [ AddMaxHP 80, AddMaxCalm 60, AddSpeed 20-               , AddSkills $ EM.insert AbProject 1 robotSkillMalus-               , AddSight 3, AddLight 4 ]  -- light can't be turned off+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 20+               , AddSkills $ EM.singleton AbProject 2 ]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = "Heavy multi-purpose construction robot. Excels at discharging, dismantling and demolition."-  , ikit     = [ ("largeJaw", COrgan), ("claw", COrgan)+  , ikit     = [ ("large jaw", COrgan), ("small claw", COrgan), ("spotlight", COrgan)                , ("construction hooter", CInv)-               , ("armored skin", COrgan), ("eye3", COrgan) ]+               , ("armored skin", COrgan), ("eye 5", COrgan)+               , ("robot brain", COrgan) ]+  }+cleanerRobot = ItemKind+  { isymbol  = 'C'+  , iname    = "The Void Cleaner Robot"+  , ifreq    = [("robot", 100), ("mobile", 1)]+  , iflavour = zipPlain [BrGreen]+  , icount   = 1+  , irarity  = [(9 * 10/12, 0), (10 * 10/12, 1000), (11 * 10/12, 0)]+                 -- 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 = []+  , 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)+               , ("eye 2", COrgan), ("nostril", COrgan), ("spotlight", COrgan)+               , ("currency", CInv), ("currency", CInv), ("currency", CInv)+               , ("robot brain", COrgan) ]   }
GameDefinition/Content/ItemKindBlast.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -15,9 +15,9 @@  blasts :: [ItemKind] blasts =-  [burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, redPaint, 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, 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, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, redPaint, 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, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, vulnerabilityBalm, hasteSpray, slownessSpray, eyeDrop, smellyDroplet, whiskeySpray :: ItemKind  -- * Parameterized immediate effect blasts @@ -27,13 +27,12 @@   , iname    = "burning oil"   , ifreq    = [(toGroupName $ "burning oil" <+> tshow n, 1)]   , iflavour = zipFancy [BrYellow]-  , icount   = intToDice (n * 4)+  , icount   = intToDice (n * 5)   , irarity  = [(1, 1)]   , iverbHit = "burn"   , iweight  = 1   , iaspects = [AddLight 2]-  , ieffects = [ Burn (n `div` 2)-               , Paralyze (intToDice $ n `div` 2) ]  -- tripping on oil+  , ieffects = [Burn 1, Paralyze 1]  -- tripping on oil   , ifeature = [ toVelocity (min 100 $ n * 7)                , Fragile, Identified ]   , idesc    = "Sticky oil, burning brightly."@@ -48,15 +47,15 @@   , iname    = "blast"   , ifreq    = [(toGroupName $ "blast" <+> tshow n, 1)]   , iflavour = zipPlain [BrRed]-  , icount   = 12  -- strong, but few, so not always hits target+  , icount   = 15  -- strong, but few, so not always hits target   , irarity  = [(1, 1)]   , iverbHit = "tear apart"   , iweight  = 1   , iaspects = [AddLight $ intToDice n]   , ieffects = [RefillHP (- n `div` 2)]-               ++ [DropBestWeapon | n > 2]+               ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)]                ++ [DropItem COrgan "temporary conditions" True | n >= 10]-  , ifeature = [Fragile, toLinger 10, Identified]+  , ifeature = [Fragile, toLinger 20, Identified]   , idesc    = ""   , ikit     = []   }@@ -74,7 +73,8 @@   , iverbHit = "crack"   , iweight  = 1   , iaspects = [AddLight $ intToDice $ n `div` 2]-  , ieffects = [ Burn 1 | n > 5 ]+  , ieffects = [ RefillCalm (-1) | n >= 5 ]+               ++ [ DropBestWeapon | n >= 5]                ++ [ OnSmash (Explode $ toGroupName                              $ "firecracker" <+> tshow (n - 1))                   | n > 2 ]@@ -97,13 +97,15 @@   , iname    = "fragrance"   , ifreq    = [("fragrance", 1)]   , iflavour = zipFancy [Magenta]-  , icount   = 15+  , icount   = 20   , irarity  = [(1, 1)]   , iverbHit = "engulf"   , iweight  = 1   , iaspects = []   , ieffects = [Impress]-  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps+  -- 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 ]   , idesc    = ""   , ikit     = []@@ -113,23 +115,55 @@   , iname    = "musky whiff"   , ifreq    = [("pheromone", 1)]   , iflavour = zipFancy [BrMagenta]-  , icount   = 8+  , icount   = 18   , irarity  = [(1, 1)]   , iverbHit = "tempt"   , iweight  = 1   , iaspects = []-  , ieffects = [Dominate]+  , ieffects = [Impress, OverfillCalm (-20)]   , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps                , Fragile, Identified ]   , idesc    = ""   , ikit     = []   }+mistCalming = ItemKind+  { isymbol  = '\''+  , iname    = "mist"+  , ifreq    = [("calming mist", 1)]+  , iflavour = zipFancy [White]+  , icount   = 19+  , irarity  = [(1, 1)]+  , iverbHit = "sooth"+  , iweight  = 1+  , iaspects = []+  , ieffects = [RefillCalm 2]+  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+odorDistressing = ItemKind+  { isymbol  = '\''+  , iname    = "distressing whiff"+  , ifreq    = [("distressing odor", 1)]+  , iflavour = zipFancy [BrRed]+  , icount   = 10+  , irarity  = [(1, 1)]+  , iverbHit = "distress"+  , iweight  = 1+  , iaspects = []+  , ieffects = [OverfillCalm (-20)]+  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  } mistHealing = ItemKind   { isymbol  = '\''   , iname    = "mist"   , ifreq    = [("healing mist", 1)]   , iflavour = zipFancy [White]-  , icount   = 11+  , icount   = 9   , irarity  = [(1, 1)]   , iverbHit = "revitalize"   , iweight  = 1@@ -145,7 +179,7 @@   , iname    = "mist"   , ifreq    = [("healing mist 2", 1)]   , iflavour = zipFancy [White]-  , icount   = 12+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "revitalize"   , iweight  = 1@@ -161,7 +195,7 @@   , iname    = "mist"   , ifreq    = [("wounding mist", 1)]   , iflavour = zipFancy [White]-  , icount   = 13+  , icount   = 7   , irarity  = [(1, 1)]   , iverbHit = "devitalize"   , iweight  = 1@@ -177,7 +211,7 @@   , iname    = "vortex"   , ifreq    = [("distortion", 1)]   , iflavour = zipFancy [White]-  , icount   = 4+  , icount   = 6   , irarity  = [(1, 1)]   , iverbHit = "engulf"   , iweight  = 1@@ -193,13 +227,13 @@   , iname    = "waste"   , ifreq    = [("waste", 1)]   , iflavour = zipPlain [Brown]-  , icount   = 10+  , icount   = 18   , irarity  = [(1, 1)]   , iverbHit = "splosh"   , iweight  = 50   , iaspects = []   , ieffects = [RefillHP (-1)]-  , ifeature = [ ToThrow $ ThrowMod 28 50+  , ifeature = [ ToThrow $ ThrowMod 28 10  -- 2 steps, one turn                , Fragile, Identified ]   , idesc    = ""   , ikit     = []@@ -209,7 +243,7 @@   , iname    = "glass piece"   , ifreq    = [("glass piece", 1)]   , iflavour = zipPlain [BrBlue]-  , icount   = 17+  , icount   = 18   , irarity  = [(1, 1)]   , iverbHit = "cut"   , iweight  = 10@@ -239,7 +273,7 @@   , iname    = "boiling water"   , ifreq    = [("boiling water", 1)]   , iflavour = zipPlain [BrWhite]-  , icount   = 10+  , icount   = 21   , irarity  = [(1, 1)]   , iverbHit = "boil"   , iweight  = 5@@ -254,7 +288,7 @@   , iname    = "sticky foam"   , ifreq    = [("glue", 1)]   , iflavour = zipPlain [BrYellow]-  , icount   = 14+  , icount   = 20   , irarity  = [(1, 1)]   , iverbHit = "glue"   , iweight  = 20@@ -269,7 +303,7 @@   , iname    = "spark"   , ifreq    = [("spark", 1)]   , iflavour = zipPlain [BrYellow]-  , icount   = 18+  , icount   = 17   , irarity  = [(1, 1)]   , iverbHit = "burn"   , iweight  = 1@@ -284,7 +318,7 @@   , iname    = "mist"   , ifreq    = [("anti-slow mist", 1)]   , iflavour = zipPlain [BrRed]-  , icount   = 11+  , icount   = 7   , irarity  = [(1, 1)]   , iverbHit = "propel"   , iweight  = 1@@ -300,7 +334,7 @@   , iname    = "mist"   , ifreq    = [("antidote mist", 1)]   , iflavour = zipPlain [BrBlue]-  , icount   = 11+  , icount   = 8   , irarity  = [(1, 1)]   , iverbHit = "cure"   , iweight  = 1@@ -319,7 +353,7 @@   , iname    = "mist"   , ifreq    = [("strength mist", 1)]   , iflavour = zipFancy [Red]-  , icount   = 11+  , icount   = 6   , irarity  = [(1, 1)]   , iverbHit = "strengthen"   , iweight  = 1@@ -335,7 +369,7 @@   , iname    = "mist"   , ifreq    = [("weakness mist", 1)]   , iflavour = zipFancy [Blue]-  , icount   = 12+  , icount   = 5   , irarity  = [(1, 1)]   , iverbHit = "weaken"   , iweight  = 1@@ -362,7 +396,7 @@   , idesc    = ""   , ikit     = []   }-redPaint = ItemKind+vulnerabilityBalm = ItemKind   { isymbol  = '\''   , iname    = "red paint"   , ifreq    = [("red paint", 1)]
GameDefinition/Content/ItemKindOrgan.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -6,6 +6,9 @@ -- | Organ definitions. module Content.ItemKindOrgan ( organs ) where +import qualified Data.EnumMap.Strict as EM++import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour@@ -15,9 +18,9 @@  organs :: [ItemKind] organs =-  [fist, foot, claw, smallClaw, snout, jaw, largeJaw, tentacle, thorn, razor, fissure, sting, venomTooth, venomFang, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, nostril, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, boilingVent, explosionVent, wasteContainer, bonusHP]+  [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, claw, smallClaw, snout, jaw, largeJaw, tentacle, thorn, razor, fissure, sting, venomTooth, venomFang, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, nostril, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, boilingVent, explosionVent, wasteContainer, bonusHP :: ItemKind+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  -- Weapons @@ -34,7 +37,7 @@   , iweight  = 2000   , iaspects = []   , ieffects = [Hurt (4 * d 1)]-  , ifeature = [Durable, EqpSlot EqpSlotWeapon "", Identified]+  , ifeature = [Durable, Identified]   , idesc    = ""   , ikit     = []   }@@ -53,8 +56,9 @@   { iname    = "claw"   , ifreq    = [("claw", 50)]   , icount   = 2  -- even if more, only the fore claws used for fighting-  , iverbHit = "slash"-  , ieffects = [Hurt (6 * d 1)]+  , iverbHit = "hook"+  , iaspects = [Timeout $ 4 + d 4]+  , ieffects = [Hurt (2 * d 1), Recharging (toOrganGameTurn "slow 10" 2)]   , idesc    = ""   } smallClaw = fist@@ -62,7 +66,7 @@   , ifreq    = [("small claw", 50)]   , icount   = 2   , iverbHit = "slash"-  , ieffects = [Hurt (3 * d 1)]+  , ieffects = [Hurt (2 * d 1)]   , idesc    = ""   } snout = fist@@ -72,12 +76,20 @@   , ieffects = [Hurt (2 * d 1)]   , idesc    = ""   }+smallJaw = fist+  { iname    = "small jaw"+  , ifreq    = [("small jaw", 20)]+  , icount   = 1+  , iverbHit = "rip"+  , ieffects = [Hurt (3 * d 1)]+  , idesc    = ""+  } jaw = fist   { iname    = "jaw"   , ifreq    = [("jaw", 20)]   , icount   = 1   , iverbHit = "rip"-  , ieffects = [Hurt (4 * d 1)]+  , ieffects = [Hurt (5 * d 1)]   , idesc    = ""   } largeJaw = fist@@ -88,6 +100,14 @@   , ieffects = [Hurt (12 * d 1)]   , idesc    = ""   }+horn = fist+  { iname    = "horn"+  , ifreq    = [("horn", 20)]+  , icount   = 2+  , iverbHit = "impale"+  , ieffects = [Hurt (8 * d 1)]+  , idesc    = ""+  }  -- * Monster weapon organs @@ -102,15 +122,6 @@  -- * Special weapon organs -thorn = fist-  { iname    = "thorn"-  , ifreq    = [("thorn", 100)]-  , icount   = 7-  , iverbHit = "impale"-  , ieffects = [Hurt (1 * d 1)]-  , ifeature = [EqpSlot EqpSlotWeapon "", Identified]  -- not Durable-  , idesc    = ""-  } razor = fist   { iname    = "razor"   , ifreq    = [("razor", 100)]@@ -119,22 +130,54 @@   , ieffects = [Hurt (2 * d 1)]   , idesc    = ""   }-fissure = fist+thorn = fist+  { iname    = "thorn"+  , ifreq    = [("thorn", 100)]+  , icount   = 2 + d 3+  , iverbHit = "impale"+  , ieffects = [Hurt (2 * d 1)]+  , ifeature = [Identified]  -- not Durable+  , idesc    = ""+  }+boilingFissure = fist   { iname    = "fissure"-  , ifreq    = [("fissure", 100)]-  , icount   = 2+  , ifreq    = [("boiling fissure", 100)]+  , icount   = 5 + d 5   , iverbHit = "hiss at"-  , ieffects = [Burn 1]+  , ieffects = [Burn $ 1 * d 1]+  , ifeature = [Identified]  -- not Durable   , idesc    = ""   }+biogasFissure = boilingFissure+  { iname    = "fissure"+  , ifreq    = [("biogas fissure", 100)]+  , icount   = 2 + d 2+  , ieffects = [Burn $ 1 * d 1, toOrganGameTurn "weakened" (2 + d 2)]+  }+medbotFissure = boilingFissure+  { iname    = "fissure"+  , ifreq    = [("medbot fissure", 100)]+  , icount   = 2 + d 2+  , ieffects = [Burn $ 1 * d 1, 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 10, RefillHP 5]+  , ifeature = [Identified]  -- not Durable+  , idesc    = "Painful, but beneficial."+  } sting = fist   { iname    = "sting"   , ifreq    = [("sting", 100)]   , icount   = 1   , iverbHit = "sting"   , iaspects = [Timeout $ 1 + d 5]-  , ieffects = [Burn 1, Recharging (Paralyze 3)]-  , idesc    = ""+  , ieffects = [Burn $ 1 * d 1, Recharging (Paralyze 3)]+  , idesc    = "Painful, debilitating and harmful."   } venomTooth = fist   { iname    = "venom tooth"@@ -142,7 +185,7 @@   , icount   = 2   , iverbHit = "bite"   , iaspects = [Timeout $ 5 + d 3]-  , ieffects = [ Hurt (3 * d 1)+  , ieffects = [ Hurt (2 * d 1)                , Recharging (toOrganGameTurn "slow 10" (3 + d 3)) ]   , idesc    = ""   }@@ -154,10 +197,20 @@   , icount   = 2   , iverbHit = "bite"   , iaspects = [Timeout $ 7 + d 5]-  , ieffects = [ Hurt (3 * d 1)+  , ieffects = [ Hurt (2 * d 1)                , Recharging (toOrganNone "poisoned") ]   , idesc    = ""   }+screechingBeak = armoredSkin+  { iname    = "screeching beak"+  , ifreq    = [("screeching beak", 100)]+  , icount   = 1+  , iverbHit = "peck"+  , iaspects = [Timeout $ 5 + d 5]+  , ieffects = [ Recharging (Summon [("scavenger", 1)] $ 1 + dl 2)+               , Hurt (2 * d 1) ]+  , idesc    = ""+  } largeTail = fist   { iname    = "large tail"   , ifreq    = [("large tail", 50)]@@ -170,10 +223,13 @@ liveWire = fist   { iname    = "live wire"   , ifreq    = [("live wire", 100)]-  , icount   = 4+  , icount   = 2   , iverbHit = "shock"-  , iaspects = [Timeout $ 2 + d 2]-  , ieffects = [Hurt (1 * d 1), Recharging (DropItem COrgan "temporary conditions" True)]+  , iaspects = [Timeout $ 5 + d 5]+  , ieffects = [ Hurt (1 * d 1)+               , Recharging (DropItem COrgan "temporary conditions" True)+               , Recharging $ RefillHP (-2)+               ]   , idesc    = ""   } @@ -212,17 +268,73 @@ eye3 = eye 3 eye4 = eye 4 eye5 = eye 5+eye6 = eye 6+eye7 = eye 7+eye8 = eye 8+vision :: Int -> ItemKind+vision n = armoredSkin+  { iname    = "vision"+  , ifreq    = [(toGroupName $ "vision" <+> tshow n, 100)]+  , icount   = 1+  , iverbHit = "visualize"+  , iaspects = [AddSight (intToDice n)]+  , idesc    = ""+  }+vision4 = vision 4+vision6 = vision 6+vision8 = vision 8+vision10 = vision 10+vision12 = vision 12+vision14 = vision 14+vision16 = vision 16 nostril = armoredSkin   { iname    = "nostril"   , ifreq    = [("nostril", 100)]   , icount   = 2   , iverbHit = "snuff"-  , iaspects = [AddSmell 1]+  , iaspects = [AddSmell 2]   , idesc    = ""   }  -- * Assorted +insectMortality = fist+  { iname    = "insect mortality"+  , ifreq    = [("insect mortality", 100)]+  , icount   = 1+  , iverbHit = "age"+  , iaspects = [Periodic, Timeout $ 40 + d 10]+  , ieffects = [Recharging (RefillHP (-1))]+  , idesc    = ""+  }+sapientBrain = armoredSkin+  { iname    = "sapient brain"+  , ifreq    = [("sapient brain", 100)]+  , icount   = 1+  , iverbHit = "outbrain"+  , iaspects = [AddSkills unitSkills]+  , 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]+  , idesc    = ""+  } speedGland :: Int -> ItemKind speedGland n = armoredSkin   { iname    = "speed gland"@@ -240,33 +352,63 @@ speedGland6 = speedGland 6 speedGland8 = speedGland 8 speedGland10 = speedGland 10+scentGland = armoredSkin  -- TODO: cone attack, 3m away, project? apply?+  { iname    = "scent gland"+  , ifreq    = [("scent gland", 100)]+  , icount   = 2+  , iverbHit = "spray at"+  , iaspects = [Periodic, Timeout $ 10 + d 2 |*| 5 ]+  , ieffects = [ Recharging (Explode "distressing odor")+               , Recharging ApplyPerfume ]+  , idesc    = ""+  } boilingVent = armoredSkin   { iname    = "vent"   , ifreq    = [("boiling vent", 100)]+  , iflavour = zipPlain [BrBlue]   , icount   = 1   , iverbHit = "menace"-  , iaspects = [Periodic, Timeout $ (3 + d 4) |*| 5]+  , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]   , ieffects = [Recharging (Explode "boiling water")]   , idesc    = ""   }-explosionVent = armoredSkin+biogasVent = armoredSkin   { iname    = "vent"-  , ifreq    = [("explosion vent", 100)]+  , ifreq    = [("biogas vent", 100)]+  , iflavour = zipPlain [BrGreen]   , icount   = 1   , iverbHit = "menace"-  , iaspects = [Periodic, Timeout $ (2 + d 4) |*| 5]-  , ieffects = [Recharging (Explode "blast 20")]+  , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]+  , ieffects = [Recharging (Explode "weakness mist")]   , idesc    = ""   }+medbotVent = 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")]+  , idesc    = ""+  } wasteContainer = armoredSkin   { iname    = "waste container"   , ifreq    = [("waste container", 100)]   , icount   = 1   , iverbHit = "spill over"-  , iaspects = [Periodic, Timeout $ (5 + d 5) |*| 10]+  , iaspects = [Periodic, Timeout $ 5 + d 5 |*| 10]   , ieffects = [ Recharging (Summon [("mobile animal", 1)] $ 1 + dl 2)                , Recharging (RefillHP 1)                , Recharging (Explode "waste") ]+  , idesc    = ""+  }+spotlight = armoredSkin+  { iname    = "spotlight"+  , ifreq    = [("spotlight", 100)]+  , icount   = 1+  , iverbHit = "blind"+  , iaspects = [AddLight 3]   , idesc    = ""   } bonusHP = armoredSkin
GameDefinition/Content/ItemKindTemporary.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -17,23 +17,23 @@  temporaries :: [ItemKind] temporaries =-  [tmpStrengthened, tmpWeakened, tmpProtected, tmpPaintedRed, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResitant]+  [tmpStrengthened, tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant] -tmpStrengthened,    tmpWeakened, tmpProtected, tmpPaintedRed, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResitant :: ItemKind+tmpStrengthened,    tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant :: ItemKind  -- 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 name aspects = ItemKind-  { isymbol  = '.'+  { isymbol  = '+'   , iname    = name   , ifreq    = [(toGroupName name, 1), ("temporary conditions", 1)]   , iflavour = zipPlain [BrWhite]   , icount   = 1   , irarity  = [(1, 1)]   , iverbHit = "affect"-  , iweight  = 1-  , iaspects = [Periodic, Timeout 1]  -- activates and vanishes soon,+  , iweight  = 0+  , iaspects = [Periodic, Timeout 0]  -- activates and vanishes soon,                                       -- depending on initial timer setting                ++ aspects   , ieffects = let tmp = Temporary $ "be no longer" <+> name@@ -47,12 +47,12 @@ tmpWeakened = tmpAs "weakened" [AddHurtMelee (-20)] tmpProtected = tmpAs "protected" [ AddArmorMelee 30                                  , AddArmorRanged 30 ]-tmpPaintedRed = tmpAs "painted red" [ AddArmorMelee (-30)+tmpVulnerable = tmpAs "painted red" [ AddArmorMelee (-30)                                     , AddArmorRanged (-30) ] tmpFast20 = tmpAs "fast 20" [AddSpeed 20] tmpSlow10 = tmpAs "slow 10" [AddSpeed (-10)] tmpFarSighted = tmpAs "far-sighted" [AddSight 5]-tmpKeenSmelling = tmpAs "keen-smelling" [AddSmell 1]+tmpKeenSmelling = tmpAs "keen-smelling" [AddSmell 2] tmpDrunk = tmpAs "drunk" [ AddHurtMelee 30  -- fury                          , AddArmorMelee (-20)                          , AddArmorRanged (-20)@@ -61,20 +61,20 @@ tmpRegenerating =   let tmp = tmpAs "regenerating" []   in tmp { icount = 7 + d 5-         , ieffects = [Recharging (RefillHP 1)] ++ ieffects tmp+         , ieffects = Recharging (RefillHP 1) : ieffects tmp          } tmpPoisoned =   let tmp = tmpAs "poisoned" []   in tmp { icount = 7 + d 5-         , ieffects = [Recharging (RefillHP (-1))] ++ ieffects tmp+         , 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+         , ieffects = Recharging (DropItem COrgan "slow 10" True) : ieffects tmp          }-tmpPoisonResitant =+tmpPoisonResistant =   let tmp = tmpAs "poison resistant" []   in tmp { icount = 7 + d 5-         , ieffects = [Recharging (DropItem COrgan "poisoned" True)] ++ ieffects tmp+         , ieffects = Recharging (DropItem COrgan "poisoned" True) : ieffects tmp          }
GameDefinition/Content/ModeKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -10,6 +10,7 @@  import Content.ModeKindPlayer import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind @@ -21,17 +22,17 @@   , validateSingle = validateSingleModeKind   , validateAll = validateAllModeKind   , content =-      [campaign, duel, skirmish, ambush, battle, safari, pvp, coop, defense, screensaver]+      [campaign, duel, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver]   }-campaign,        duel, skirmish, ambush, battle, safari, pvp, coop, defense, screensaver :: ModeKind+campaign,        duel, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver :: ModeKind  campaign = ModeKind-  { msymbol = 'a'+  { msymbol = 'n'   , 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 at the giant spaceship's uppermost deck. There are animal cries down below and ominous silence up above."+  , 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."   }  duel = ModeKind@@ -49,7 +50,7 @@   , mfreq   = [("skirmish", 1)]   , mroster = rosterSkirmish   , mcaves  = cavesSkirmish-  , mdesc   = "You owe restorative surgery to one of our crew: if we win, we take all you have; if you win, you take ours old giant spaceship (if you still want it when you see it)."+  , mdesc   = "You owe restorative surgery to one of our crew: if we win, we take all you have; if you win, you take our old giant spaceship (if you still want it when you see it)."   }  ambush = ModeKind@@ -70,6 +71,15 @@   , mdesc   = "Not even the unexplained ruin of the largest and tightest security Neptune's moon spaceport will prevent you from claiming your prize."   } +battleSurvival = ModeKind+  { msymbol = 'i'+  , mname   = "battle survival"+  , mfreq   = [("battle survival", 1)]+  , mroster = rosterBattleSurvival+  , mcaves  = cavesBattle+  , mdesc   = "Odds are stacked for those that breathe mathematics."+  }+ safari = ModeKind   { msymbol = 'f'   , mname   = "safari"@@ -79,6 +89,15 @@   , 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)."   } +safariSurvival = ModeKind+  { msymbol = 'n'+  , mname   = "safari survival"+  , mfreq   = [("safari survival", 1)]+  , mroster = rosterSafariSurvival+  , mcaves  = cavesSafari+  , 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"@@ -111,13 +130,14 @@   , mfreq   = [("screensaver", 1), ("starting", 1)]   , mroster = rosterSafari       { rosterList = (head (rosterList rosterSafari))-                       {fleaderMode = LeaderAI $ AutoLeader False False }+                       -- changing leader by client needed, because of TFollow+                       {fleaderMode = LeaderAI $ AutoLeader True False}                      : tail (rosterList rosterSafari)       }   }  -rosterCampaign, rosterDuel, rosterSkirmish, rosterAmbush, rosterBattle, rosterSafari, rosterPvP, rosterCoop, rosterDefense :: Roster+rosterCampaign, rosterDuel, rosterSkirmish, rosterAmbush, rosterBattle, rosterBattleSurvival, rosterSafari, rosterSafariSurvival, rosterPvP, rosterCoop, rosterDefense :: Roster  rosterCampaign = Roster   { rosterList = [ playerHero@@ -133,10 +153,12 @@  rosterDuel = Roster   { rosterList = [ playerHero { fname = "Spacefarer Crew"-                              , fentryLevel = 3+                              , fhiCondPoly = hiDweller+                              , fentryLevel = 4                               , finitialActors = 1 }                  , playerAntiHero { fname = "Red Collars"-                                  , fentryLevel = 3+                                  , fhiCondPoly = hiDweller+                                  , fentryLevel = 4                                   , finitialActors = 1 }                  , playerHorror ]   , rosterEnemy = [ ("Spacefarer Crew", "Red Collars")@@ -146,29 +168,36 @@  rosterSkirmish = rosterDuel   { rosterList = [ playerHero { fname = "Spacefarer Crew"-                              , fentryLevel = 3 }+                              , fhiCondPoly = hiDweller+                              , fentryLevel = 4 }                  , playerAntiHero { fname = "Red Collars"-                                  , fentryLevel = 3 }+                                  , fhiCondPoly = hiDweller+                                  , fentryLevel = 4 }                  , playerHorror ] }  rosterAmbush = rosterDuel-  { rosterList = [ playerHero { fname = "Spacefarer Crew"-                              , fentryLevel = 5 }-                 , playerAntiHero { fname = "Red Collars"-                                  , fentryLevel = 5 }-                 , playerHorror {fentryLevel = 5} ] }+  { 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 { finitialActors = 5-                                 , fentryLevel = 5 }-                 , playerMobileMonster { finitialActors = 35-                                       , fentryLevel = 5+  { rosterList = [ playerSoldier { fhiCondPoly = hiDweller+                                 , fentryLevel = 7+                                 , finitialActors = 5 }+                 , playerMobileMonster { fentryLevel = 7+                                       , finitialActors = 35                                        , fneverEmpty = True }-                 , playerMobileAnimal { finitialActors = 20-                                      , fentryLevel = 5+                 , playerMobileAnimal { fentryLevel = 7+                                      , finitialActors = 20                                       , fneverEmpty = True }-                 , playerMobileRobot { finitialActors = 15-                                     , fentryLevel = 5+                 , playerMobileRobot { fentryLevel = 7+                                     , finitialActors = 15                                      , fneverEmpty = True } ]   , rosterEnemy = [ ("Armed Spacefarer Crew", "Alien Hierarchy")                   , ("Armed Spacefarer Crew", "Animal Kingdom")@@ -177,42 +206,91 @@                 , ("Alien Hierarchy", "Robot Anarchy")                 , ("Robot Anarchy", "Animal Kingdom") ] } -rosterSafari = Roster-  { rosterList = [ playerAntiMonster { fname = "Alien Tourist Office"-                                     , fcanEscape = True-                                     , fneverEmpty = True-                                     -- Follow-the-guide, as tourists do.-                                     , ftactic = TFollow-                                     , fentryLevel = 4+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-                                     , fleaderMode =-                                         -- no spawning and TFollow-                                         LeaderUI $ AutoLeader False False }-                 , playerCivilian { fname = "Hunam Convict Pack"-                                  , fentryLevel = 4 }-                 , playerMobileAnimal { fname =-                                          "Animal Magnificent Specimen Variety"-                                      , fneverEmpty = True-                                      , fentryLevel = 7-                                      , finitialActors = 10 }-                 , playerMobileAnimal { fname =-                                          "Animal Exquisite Herds and Packs"-                                      , fneverEmpty = True-                                      , fentryLevel = 10-                                      , finitialActors = 30 } ]-  , rosterEnemy = [ ("Alien Tourist Office", "Hunam Convict Pack")-                  , ("Alien Tourist Office",-                     "Animal Magnificent Specimen Variety")-                  , ("Alien Tourist Office",-                     "Animal Exquisite Herds and Packs") ]-  , rosterAlly = [( "Animal Magnificent Specimen Variety"-                  , "Animal Exquisite Herds and Packs" )] }+                                     , fneverEmpty = True+                                     , fhasUI = True } ] } +playerMonsterTourist, playerHunamConvict, playerAnimalMagnificent, playerAnimalExquisite :: Player Dice++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 }++playerHunamConvict =+  playerCivilian { fname = "Hunam Convict Pack"+                 , fentryLevel = 4 }++playerAnimalMagnificent =+  playerMobileAnimal { fname = "Animal Magnificent Specimen Variety"+                     , fneverEmpty = True+                     , fentryLevel = 7+                     , finitialActors = 10+                     , fleaderMode =  -- move away from stairs+                         LeaderAI $ AutoLeader True False }++playerAnimalExquisite =+  playerMobileAnimal { fname = "Animal Exquisite Herds and Packs"+                     , fneverEmpty = True+                     , fentryLevel = 10+                     , finitialActors = 30 }++rosterSafari = Roster+  { rosterList = [ playerMonsterTourist+                 , playerHunamConvict+                 , playerAnimalMagnificent+                 , playerAnimalExquisite+                 ]+  , rosterEnemy = [ ( "Alien Tourist Office", "Hunam Convict Pack")+                  , ( "Alien Tourist Office"+                    , "Animal Magnificent Specimen Variety" )+                  , ( "Alien Tourist Office"+                    , "Animal Exquisite Herds and Packs" ) ]+  , 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" ) ] }++rosterSafariSurvival = rosterSafari+  { rosterList = [ playerMonsterTourist+                     { fleaderMode = LeaderAI $ AutoLeader True False+                     , fhasUI = False }+                 , playerHunamConvict+                 , playerAnimalMagnificent+                     { fleaderMode = LeaderUI $ AutoLeader False False+                     , fhasUI = True }+                 , playerAnimalExquisite+                 ] }+ rosterPvP = Roster   { rosterList = [ playerHero { fname = "Red"-                              , fentryLevel = 3 }+                              , fhiCondPoly = hiDweller+                              , fentryLevel = 4 }                  , playerHero { fname = "Blue"-                              , fentryLevel = 3 }+                              , fhiCondPoly = hiDweller+                              , fentryLevel = 4 }                  , playerHorror ]   , rosterEnemy = [ ("Red", "Blue")                   , ("Red", "Horror Den")@@ -242,18 +320,11 @@                  , ("Green", "Alien Hierarchy")                  , ("Green", "Leaderless Alien Hierarchy") ] } -rosterDefense = Roster-  { rosterList = [ playerAntiMonster-                 , playerAntiHero {fname = "Yellow"}+rosterDefense = rosterCampaign+  { rosterList = [ playerAntiHero+                 , playerAntiMonster                  , playerAnimal-                 , playerRobot ]-  , rosterEnemy = [ ("Yellow", "Alien Hierarchy")-                  , ("Yellow", "Animal Kingdom")-                  , ("Yellow", "Robot Anarchy") ]-  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                 , ("Alien Hierarchy", "Robot Anarchy")-                 , ("Robot Anarchy", "Animal Kingdom") ] }-+                 , playerRobot ] }  cavesCampaign, cavesSkirmish, cavesAmbush, cavesBattle, cavesSafari :: Caves @@ -262,14 +333,16 @@                   ++ [(2, ("shallow random 2", Nothing))]                   ++ [(3, ("caveBridge", Nothing))]                   ++ [(4, ("caveNoise", Nothing))]-                  ++ zip [5..11] (repeat ("campaign random", Nothing))-                  ++ [(12, ("caveNoise", Just True))]+                  ++ zip [5..9] (repeat ("campaign random", Nothing))+                  ++ [(10, ("caveEmpty", Just False))]+                  ++ [(11, ("campaign random", Nothing))]+                  ++ [(12, ("caveNoise", Nothing))] -cavesSkirmish = IM.fromList [(3, ("caveSkirmish", Nothing))]+cavesSkirmish = IM.fromList [(4, ("caveSkirmish", Nothing))] -cavesAmbush = IM.fromList [(5, ("caveAmbush", Nothing))]+cavesAmbush = IM.fromList [(7, ("caveAmbush", Nothing))] -cavesBattle = IM.fromList [(5, ("caveBattle", Nothing))]+cavesBattle = IM.fromList [(7, ("caveBattle", Nothing))]  cavesSafari = IM.fromList [ (4, ("caveSafari1", Nothing))                           , (7, ("caveSafari2", Nothing))
GameDefinition/Content/ModeKindPlayer.hs view
@@ -1,23 +1,28 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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. -- -- | Basic players definitions. module Content.ModeKindPlayer-  ( playerHero, playerSoldier, playerAntiHero, playerCivilian, playerMonster-  , playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal-  , playerRobot, playerMobileRobot, playerHorror+  ( playerHero, playerSoldier, playerSniper+  , playerAntiHero, playerAntiSniper, playerCivilian+  , playerMonster, playerMobileMonster, playerAntiMonster+  , playerAnimal, playerMobileAnimal+  , playerRobot, playerMobileRobot+  , playerHorror+  , hiHero, hiDweller   ) where  import qualified Data.EnumMap.Strict as EM+import Data.List  import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind -playerHero, playerSoldier, playerAntiHero, playerCivilian, playerMonster, playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal, playerRobot, playerMobileRobot, playerHorror :: Player Dice+playerHero, playerSoldier, playerSniper, playerAntiHero, playerAntiSniper, playerCivilian, playerMonster, playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal, playerRobot, playerMobileRobot, playerHorror :: Player Dice  playerHero = Player   { fname = "Spacefarer Crew"@@ -25,6 +30,7 @@   , fskillsOther = meleeAdjacent   , fcanEscape = True   , fneverEmpty = True+  , fhiCondPoly = hiHero   , fhasNumbers = True   , fhasGender = True   , ftactic = TExplore@@ -39,17 +45,28 @@   , 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"-  , fskillsOther = unitSkills  -- not coordinated by any leadership+  , fskillsOther = zeroSkills  -- not coordinated by any leadership   , fcanEscape = False   , fneverEmpty = True+  , fhiCondPoly = hiDweller   , fhasNumbers = False   , fhasGender = True   , ftactic = TPatrol@@ -62,15 +79,19 @@ playerMonster = Player   { fname = "Alien Hierarchy"   , fgroup = "alien"-  , fskillsOther = unitSkills+  , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False+  , fhiCondPoly = hiDweller   , fhasNumbers = False   , fhasGender = False   , ftactic = TExplore   , fentryLevel = 4   , finitialActors = 0-  , fleaderMode = LeaderAI $ AutoLeader True True+  , fleaderMode =+      -- No point changing leader on level, since all move and they+      -- don't follow the leader.+      LeaderAI $ AutoLeader True True   , fhasUI = False   } @@ -84,14 +105,15 @@ playerAnimal = Player   { fname = "Animal Kingdom"   , fgroup = "animal"-  , fskillsOther = unitSkills+  , 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 = 1 + d 2+  , finitialActors = 2 + d 2   , fleaderMode = LeaderNull   , fhasUI = False   }@@ -102,14 +124,16 @@ playerRobot = Player   { fname = "Robot Anarchy"   , fgroup = "robot"-  , fskillsOther = unitSkills+  , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False+  , fhiCondPoly = hiDweller   , fhasNumbers = False   , fhasGender = False-  , ftactic = TFollow  -- coordinated via net, follow alien leader (TODO)+  , ftactic = TRoam  -- TODO: TFollow+                        -- coordinated via net, follow alien leader   , fentryLevel = 3-  , finitialActors = 1 + d 2+  , finitialActors = 2 + d 2   , fleaderMode = LeaderNull   , fhasUI = False   }@@ -126,26 +150,49 @@ playerHorror = Player   { fname = "Horror Den"   , fgroup = "horror"-  , fskillsOther = unitSkills+  , fskillsOther = zeroSkills   , fcanEscape = False   , fneverEmpty = False+  , fhiCondPoly = []   , fhasNumbers = False   , fhasGender = False   , ftactic = TPatrol  -- disoriented-  , fentryLevel = 3+  , fentryLevel = 4   , finitialActors = 0   , fleaderMode = LeaderNull   , fhasUI = False   } -minusHundred, meleeAdjacent, _meleeAndRanged :: Skills+victoryOutcomes :: [Outcome]+victoryOutcomes = [Conquer, Escape] --- To make sure weak items can't override move-only-leader, etc.-minusHundred = EM.fromList $ zip [minBound..maxBound] [-100, -100..]+hiHero, hiDweller :: HiCondPoly -meleeAdjacent = addSkills minusHundred-                $ EM.fromList $ zip [AbWait, AbMelee] [101, 101..]+-- Heroes rejoice in loot.+hiHero = [ ( [(HiLoot, 1)]+           , [minBound..maxBound] )+         , ( [(HiConst, 1000), (HiLoss, -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+              , victoryOutcomes )+            , ( [(HiConst, 1000), (HiLoss, -10)]+              , victoryOutcomes )+            , ( [(HiBlitz, -100)]+              , victoryOutcomes )+            , ( [(HiSurvival, 100)]+              , [minBound..maxBound] \\ victoryOutcomes )+            ]++minusTen, meleeAdjacent, _meleeAndRanged :: Skills++-- To make sure only a lot of weak items can override move-only-leader, etc.+minusTen = EM.fromList $ zip [minBound..maxBound] [-10, -10..]++meleeAdjacent = EM.delete AbWait $ EM.delete AbMelee minusTen+ -- Melee and reaction fire.-_meleeAndRanged = addSkills minusHundred-                  $ EM.fromList $ zip [AbWait, AbMelee, AbProject] [101, 101..]+_meleeAndRanged = EM.delete AbProject $ meleeAdjacent
GameDefinition/Content/PlaceKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.
GameDefinition/Content/RuleKind.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE TemplateHaskell #-}--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -75,6 +75,5 @@   , rleadLevelClips = 100   , rscoresFile = "scores"   , rsavePrefix = "save"-  , rsharedStash = True-  , rnearby = 10+  , rnearby = 20   }
GameDefinition/Content/TileKind.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -266,7 +266,7 @@                  darkFeat (HideAs t) = Just $ HideAs $ darkText t                  darkFeat (RevealAs t) = Just $ RevealAs $ darkText t                  darkFeat OftenItem = Nothing  -- items not common in the dark-                 darkFeat feat = Just $ feat+                 darkFeat feat = Just feat              in k { tfreq    = darkFrequency                   , tfeature = Dark : mapMaybe darkFeat (tfeature k)                   }
GameDefinition/Main.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.
GameDefinition/PLAYING.md view
@@ -14,8 +14,8 @@ Once the few basic command keys and on-screen symbols are learned, mastery and enjoyment of the game is the matter of tactical skill and literary imagination. To be honest, a lot of imagination is required-at this stage, but the game is already playable and winnable.-Contributions are welcome.+at this stage of game development, but the game is already playable+and winnable. Contributions are welcome.   Heroes@@ -32,37 +32,40 @@      *@12 Adventurer  4d1+5% Calm: 20/60 HP: 33/50 Target: basilisk  [**___] -The line starts with the list of party members (unless only one member-resides on the currently displayed level) and the shortened name of the team.-Then comes the damage of the leader's weapon (but regardless of the figures,-each attack inflicts at least 1 damage), 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.+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. -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+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. -The second status line describes the current dungeon location in relation+The second status line describes the current level in relation to the party. -    5  Lofty hall   [33% seen] Cursor: exact spot (71,12)  p15 l10+    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 'cursor' is the common target of the whole party,-directly manipulated with movement keys in the targeting mode.-At the end comes the length of the shortest path from the leader-to the cursor position and the straight-line distance between the two points.+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+between the two points.   Spaceship --------- -The spaceship of the campaign mode game consists of decks on many levels-and each deck consists of a large number of tiles. The basic tile kinds-are as follows.+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 basic tile kinds are as follows.                 terrain type                       on-screen symbol                floor                              .@@ -81,10 +84,10 @@ Commands -------- -You move throughout the level using the numerical 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).+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).                  7 8 9          7 8 9          y k u                  \|/            \|/            \|/@@ -92,125 +95,81 @@                  /|\            /|\            /|\                 1 2 3          j k l          b j n -In targeting mode the keys above move the targeting cursor. In normal mode,+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-(and currently selected party members, if any) run in the indicated-direction, until anything of interest is spotted.-The '5', '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).+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`).  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 more general commands-or as building blocks for more complex convenience commands,+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 `BACKSPACE`, `CTRL-?`, `;` and `V`.--Below are the remaining keys for terrain exploration and alteration.--                keys           command-                <              ascend a level-                CTRL-<         ascend 10 levels-                >              descend a level-                CTRL->         descend 10 levels-                ;              make one step towards the target-                :              go to target for 100 steps-                CTRL-:         go to target for 10 steps-                x              explore the closest unknown spot-                X              autoexplore 100 times-                CTRL-X         autoexplore 10 times-                R              rest (wait 100 times)-                CTRL-R         rest (wait 10 times)-                c              close door--Item-use related keys are as follows.--                keys           command-                E              describe equipment of the leader-                P              describe backpack inventory of the leader-                S              describe the shared party stash-                G              describe items on the ground-                A              describe all owned items-                g and ,        get an item-                d              drop an item-                e              equip an item-                p              pack an item into inventory backpack-                s              stash and share an item-                a              activate applicable item-                q              quaff potion-                r              read scroll-                f              fling projectable item-                t              throw missile-                z              zap wand--To make a ranged attack, as in the last few commands above,-you need to set your target first (however, initial target is set-automatically as soon as a monster comes into view). Once in targeting mode,-you can move the targeting cursor with arrow keys and switch focus-among enemies with `*` (or among friends, projectiles and enemies, depending-on targeting mode toggled by `/`). The details of the shared cursor position-and of the personal target are described in the status lines, at the bottom-of the screen. All targeting keys are listed below.+by the player as a macro using `CTRL-?`, `CTRL-.` and `V`. -                keys           command-                KEYPAD_* and \ target enemy-                /              cycle targeting mode-                +              swerve targeting line-                -              unswerve targeting line-                BACKSPACE      clear target/cursor-                CTRL-?         target the closest unknown spot-                CTRL-I         target the closest item-                CTRL-{         target the closest stairs up-                CTRL-}         target the closest stairs down+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. -Here are the commands for automating the actions of one or more members-of the team.+        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 -                keys           command-                =              select (or deselect) a party member-                _              deselect (or select) all on the level-                v              voice again the recorded commands-                V              voice the recorded commands 100 times-                CTRL-v         voice the recorded commands 1000 times-                CTRL-V         voice the recorded commands 10 times-                '              start recording commands-                CTRL-T         cycle tactic of non-leader team members (WIP)-                CTRL-A         automate faction (ESC to retake control)+The only activity not possible with the commands above is the management+of non-leader party members. The defaults should usually suffice,+especially if your non-leader heroes can only melee or wait+and none have found the equipment that enables opportunity fire.+If there's a need, 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. -Assorted remaining keys and commands follow.+        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 -                keys           command-                ?              display help-                D              display player diary-                T              mark suspect terrain-                Z              mark visible zone-                C              mark smell clues-                TAB            cycle among party members on the level-                SHIFT-TAB      cycle among all party members-                SPACE          clear messages-                ESC            cancel action, open Main Menu-                RET            accept choice-                0--6           pick a new hero leader anywhere in the spaceship+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.  Commands for saving and exiting the current game, starting a new 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 Duel game mode+of any UI-using faction. For a person new to roguelikes, the Duel scenario offers a gentle introduction. The subsequent game modes gradually introduce-squad combat, stealth, asymmetric battles and more game elements.--                keys           command-                CTRL-x         save and exit-                CTRL-u         new Duel game-                CTRL-k         new Skirmish game-                CTRL-m         new Ambush game-                CTRL-b         new Battle game-                CTRL-a         new Campaign game-                CTRL-d         cycle next game difficulty+squad combat, stealth, opportunity fire, asymmetric battles and more.   Monsters@@ -223,36 +182,50 @@ 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. The best equipped weapon or the best fighting organ-of each opponent is taken into account for calculating damage.-The damage the current hero can potentially inflict is displayed-at the bottom of the screen, but the actual damage depends also-on the monster's armor. Heroes and monsters running into one another+melee combat occurs. Heroes and monsters running into one another (with the `SHIFT` key) do not inflict damage, but change places. This gives the opponent a free blow, but can improve the tactical situation-or aid escape.+or aid escape. In some circumstances actors are immune to the displacing,+e.g., when both parties form a continuous front-line. -Flinging a missile at a target wounds it, consuming the weapon in the process.-You may propel any item in your equipment, inventory and on the ground-(press `?` to see appropriate items in a menu and press it again-for a non-standard choice). Only items of a few kinds inflict any damage,-but some have other effects. Whenever the monster's or hero's hit points-reach zero, the combatant dies. When the last hero dies, the game ends-in defeat.+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). +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.+The current leader's melee bonus, armor modifier and other detailed+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.++Whenever the monster's or hero's hit points reach zero, the combatant dies.+When the last hero dies, the scenario ends in defeat.++ On Winning and Dying -------------------- -You win the game if you escape the spaceship alive or, in game modes with-no exit opportunity, if you eliminate all opposition. In the former case,-your score is based on the gold and precious gems you've plundered,-plus a bonus based on the number of heroes you lost. In the latter case,-your score is based on the number of turns you spent overcoming your foes-and, as a bonus, the number of enemies you've subdued.+You win the scenario if you escape the spaceship 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+that were lost, are awarded if you win. -If all your heroes fall, you are awarded a score for your valiant deeds,-but no winning bonus. When, invariably, a new overconfident party-of adventurers storms the spaceship, they start from a new entrance,-with no experience and no equipment, and new, undaunted enemies-bar their way.+If all your heroes fall, you will invariably see a new foolhardy party+of adventurers clamoring to be led into the spaceship. They start+their conquest from a new entrance, with no experience and no equipment,+and new, undaunted enemies bar their way. Lead them to fame, wealth and glory!
GameDefinition/TieKnot.hs view
@@ -1,4 +1,4 @@--- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+-- 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.@@ -14,28 +14,40 @@ import qualified Content.PlaceKind import qualified Content.RuleKind import qualified Content.TileKind-import Game.LambdaHack.Client (exeFrontend)+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 (mainSer)+import Game.LambdaHack.Server  -- | Tie the LambdaHack engine client, server and frontend code -- with the game-specific content definitions, and run the game. tieKnot :: [String] -> IO ()-tieKnot args =+tieKnot args = do   let -- Common content operations, created from content definitions.-      copsServer = Kind.COps-        { cocave    = Kind.createOps Content.CaveKind.cdefs-        , coitem    = Kind.createOps Content.ItemKind.cdefs-        , comode    = Kind.createOps Content.ModeKind.cdefs-        , coplace   = Kind.createOps Content.PlaceKind.cdefs-        , corule    = Kind.createOps Content.RuleKind.cdefs-        , cotile    = Kind.createOps Content.TileKind.cdefs+      -- Evaluated fully to discover errors ASAP and free memory.+      !copsSlow = Kind.COps+        { cocave  = Kind.createOps Content.CaveKind.cdefs+        , coitem  = Kind.createOps Content.ItemKind.cdefs+        , comode  = Kind.createOps Content.ModeKind.cdefs+        , coplace = Kind.createOps Content.PlaceKind.cdefs+        , corule  = Kind.createOps Content.RuleKind.cdefs+        , cotile  = Kind.createOps Content.TileKind.cdefs         }+      !copsShared = speedupCOps False copsSlow       -- Client content operations.       copsClient = Content.KeyKind.standardKeys-      -- A single frontend is currently started by the server,-      -- instead of each client starting it's own.-      startupFrontend = exeFrontend executorCli executorCli copsClient-  in mainSer args copsServer executorSer startupFrontend+  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
GameDefinition/config.ui.default view
@@ -1,45 +1,45 @@-; ; Copyright (c) 2008--2011 Andres Loeh, 2010--2014 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.-; ;-; ; This is a commented out copy of the default UI settings config file-; ; that is embedded in the game binary. A user config file can override-; ; these options. Option names are case-sensitive and only ';' for comments-; ; is permitted.-; ;-; ; The game looks for the config file at the same path where saved games-; ; directory is located. E.g. on Linux the file is at-; ; ~/.Allure/config.ui.ini-; ; and on Windows it can be at-; ; C:\Documents And Settings\user\Application Data\Allure\config.ui.ini-; ; or at-; ; C:\Users\<username>\AppData\Roaming\Allure\config.ui.ini-; ; or elsewhere.+; 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.+;+; This is a copy of the default UI settings config file+; that is embedded in the game binary. A user config file can override+; these options. Option names are case-sensitive and only ';' for comments+; is permitted.+;+; The game looks for the config file at the same path where saved games+; directory is located. E.g. on Linux the file is at+; ~/.Allure/config.ui.ini+; and on Windows it can be at+; C:\Documents And Settings\user\Application Data\Allure\config.ui.ini+; or at+; C:\Users\<username>\AppData\Roaming\Allure\config.ui.ini+; 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"]))+[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"])) -; [hero_names]-; HeroName_0 = ("Haskell Alvin", "he")-; HeroName_1 = ("Alonzo Barkley", "he")-; HeroName_2 = ("Ines Galenti", "she")-; HeroName_3 = ("Ernst Abraham", "he")-; HeroName_4 = ("Samuel Saunders", "he")-; HeroName_5 = ("Roger Robin", "he")-; HeroName_6 = ("Christopher Flatt", "he")+[hero_names]+HeroName_0 = ("Haskell Alvin", "he")+HeroName_1 = ("Alonzo Barkley", "he")+HeroName_2 = ("Ines Galenti", "she")+HeroName_3 = ("Ernst Abraham", "he")+HeroName_4 = ("Samuel Saunders", "he")+HeroName_5 = ("Roger Robin", "he")+HeroName_6 = ("Christopher Flatt", "he") -; [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 16"-; colorIsBold = True-; historyMax = 5000-; maxFps = 15-; noAnim = False-; runStopMsgs = False-[dummy]+[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 16"+;font = "Terminus,DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace normal normal normal normal 20"+colorIsBold = True+historyMax = 5000+maxFps = 30+noAnim = False+runStopMsgs = False
GameDefinition/scores view

binary file changed (335 → 80 bytes)

Makefile view
@@ -1,4 +1,4 @@-# Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+# 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.@@ -18,7 +18,7 @@ 	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --dumpInitRngs  xcfrontendCampaign:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign --difficulty 1  xcfrontendSkirmish: 	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish@@ -29,121 +29,24 @@ xcfrontendBattle: 	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 +xcfrontendBattleSurvival:+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival" --difficulty 8+ xcfrontendSafari: 	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 -xcfrontendDefense:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode defense --difficulty 8--xcbenchCampaign:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --gameMode campaign --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS--xcbenchBattle:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS--xcbenchFrontendCampaign:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --gameMode campaign --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS--xcbenchFrontendBattle:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS--xcbenchNull: xcbenchCampaign xcbenchBattle--xcbench: xcbenchCampaign xcbenchFrontendCampaign xcbenchBattle xcbenchFrontendBattle---xctest-travis-short: xctest-short--xctest-travis: xctest-short xctest-medium--xctest-travis-long: xctest-short xctest-long--xctest-travis-long-no-safari: xctest-short xctest-long-no-safari--xctest: xctest-short xctest-medium xctest-long--xctest-short: xctest-short-new xctest-short-load--xctest-medium: xctestCampaign-medium xctestSkirmish-medium xctestAmbush-medium xctestBattle-medium xctestSafari-medium xctestPvP-medium xctestCoop-medium xctestDefense-medium--xctest-long: xctestCampaign-long xctestSkirmish-medium xctestAmbush-medium xctestBattle-long xctestSafari-long xctestPvP-medium xctestDefense-long--xctest-long-no-safari: xctestCampaign-long xctestSkirmish-medium xctestAmbush-medium xctestBattle-long xctestPvP-medium xctestDefense-long--xctestCampaign-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2 > /tmp/stdtest.log--xctestCampaign-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2 > /tmp/stdtest.log--xctestSkirmish-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode skirmish > /tmp/stdtest.log--xctestSkirmish-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode skirmish > /tmp/stdtest.log--xctestAmbush-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode ambush > /tmp/stdtest.log--xctestAmbush-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode ambush > /tmp/stdtest.log--xctestBattle-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 > /tmp/stdtest.log--xctestBattle-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 > /tmp/stdtest.log--xctestSafari-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 > /tmp/stdtest.log--xctestSafari-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 > /tmp/stdtest.log--xctestPvP-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode PvP > /tmp/stdtest.log--xctestPvP-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode PvP > /tmp/stdtest.log--xctestCoop-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode Coop --difficulty 2 > /tmp/stdtest.log--xctestCoop-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --gameMode Coop --difficulty 2 > /tmp/stdtest.log--xctestDefense-long:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode defense --difficulty 8 > /tmp/stdtest.log--xctestDefense-medium:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --gameMode defense --difficulty 8 > /tmp/stdtest.log--xctest-short-new:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix campaign --dumpInitRngs --automateAll --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix skirmish --dumpInitRngs --automateAll --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix ambush --dumpInitRngs --automateAll --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix battle --dumpInitRngs --automateAll --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix safari --dumpInitRngs --automateAll --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix PvP --dumpInitRngs --automateAll --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix Coop --dumpInitRngs --automateAll --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix defense --dumpInitRngs --automateAll --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+xcfrontendSafariSurvival:+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival" --difficulty 8 -xctest-short-load:-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix campaign --dumpInitRngs --automateAll --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix skirmish --dumpInitRngs --automateAll --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix ambush --dumpInitRngs --automateAll --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix battle --dumpInitRngs --automateAll --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix safari --dumpInitRngs --automateAll --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix PvP --dumpInitRngs --automateAll --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix Coop --dumpInitRngs --automateAll --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix defense --dumpInitRngs --automateAll --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+xcfrontendDefense:+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode defense --difficulty 9   play: 	dist/build/Allure/Allure --dbgMsgSer --dumpInitRngs  frontendCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign --difficulty 1  frontendSkirmish: 	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish@@ -154,23 +57,29 @@ frontendBattle: 	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 +frontendBattleSurvival:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival" --difficulty 8+ frontendSafari: 	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 +frontendSafariSurvival:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival" --difficulty 8+ frontendDefense:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode defense --difficulty 8+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 60 --dumpInitRngs --automateAll --gameMode defense --difficulty 9  benchCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --gameMode campaign --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --difficulty 1 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS  benchBattle:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS  benchFrontendCampaign:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --gameMode campaign --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --difficulty 1 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS  benchFrontendBattle:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --difficulty 2 --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS  benchNull: benchCampaign benchBattle @@ -179,8 +88,10 @@  test-travis-short: test-short -test-travis: test-short test-medium+test-travis-medium: test-short test-medium +test-travis-medium-no-safari: test-short test-medium-no-safari+ test-travis-long: test-short test-long  test-travis-long-no-safari: test-short test-long-no-safari@@ -189,94 +100,135 @@  test-short: test-short-new test-short-load -test-medium: testCampaign-medium testSkirmish-medium testAmbush-medium testBattle-medium testSafari-medium testPvP-medium testCoop-medium testDefense-medium+test-medium: testCampaign-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testSafari-medium testSafariSurvival-medium testPvP-medium testCoop-medium testDefense-medium -test-long: testCampaign-long testSkirmish-medium testAmbush-medium testBattle-long testSafari-long testPvP-medium testDefense-long+test-medium-no-safari: testCampaign-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testPvP-medium testCoop-medium testDefense-medium -test-long-no-safari: testCampaign-long testSkirmish-medium testAmbush-medium testBattle-long testPvP-medium testDefense-long+test-long: testCampaign-long testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testSafari-long testSafariSurvival-long testPvP-medium testDefense-long +test-long-no-safari: testCampaign-long testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testPvP-medium testDefense-long+ testCampaign-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --difficulty 1 > /tmp/stdtest.log  testCampaign-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --gameMode campaign --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --difficulty 1 > /tmp/stdtest.log  testSkirmish-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode skirmish > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log  testSkirmish-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode skirmish > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log  testAmbush-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode ambush > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log  testAmbush-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode ambush > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log  testBattle-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode battle --difficulty 2 > /tmp/stdtest.log  testBattle-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --gameMode battle --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode battle --difficulty 2 > /tmp/stdtest.log +testBattleSurvival-long:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --difficulty 8 > /tmp/stdtest.log++testBattleSurvival-medium:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --difficulty 8 > /tmp/stdtest.log+ testSafari-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode safari --difficulty 2 > /tmp/stdtest.log  testSafari-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --gameMode safari --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode safari --difficulty 2 > /tmp/stdtest.log +testSafariSurvival-long:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --difficulty 8 > /tmp/stdtest.log++testSafariSurvival-medium:+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --difficulty 8 > /tmp/stdtest.log++ testPvP-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --gameMode PvP > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --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 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --gameMode PvP > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --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 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode Coop --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --difficulty 2 > /tmp/stdtest.log  testCoop-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --gameMode Coop --difficulty 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --difficulty 2 > /tmp/stdtest.log  testDefense-long:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --gameMode defense --difficulty 8 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode defense --difficulty 9 > /tmp/stdtest.log  testDefense-medium:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --gameMode defense --difficulty 8 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode defense --difficulty 9 > /tmp/stdtest.log  test-short-new:-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix campaign --dumpInitRngs --automateAll --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix skirmish --dumpInitRngs --automateAll --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix ambush --dumpInitRngs --automateAll --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix battle --dumpInitRngs --automateAll --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix safari --dumpInitRngs --automateAll --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix PvP --dumpInitRngs --automateAll --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix Coop --dumpInitRngs --automateAll --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix defense --dumpInitRngs --automateAll --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix skirmish --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix PvP --dumpInitRngs --automateAll --keepAutomated --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix Coop --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix defense --dumpInitRngs --automateAll --keepAutomated --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log  test-short-load:-	dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --dumpInitRngs --automateAll --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix skirmish --dumpInitRngs --automateAll --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix ambush --dumpInitRngs --automateAll --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix battle --dumpInitRngs --automateAll --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix safari --dumpInitRngs --automateAll --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix PvP --dumpInitRngs --automateAll --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix Coop --dumpInitRngs --automateAll --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log-	dist/build/Allure/Allure --dbgMsgSer --savePrefix defense --dumpInitRngs --automateAll --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log+	dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --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   build-binary:-	cabal configure -frelease --prefix=/usr/local+	cabal configure -frelease --prefix=/ 	cabal build Allure-	rm -rf /tmp/Allure-	cabal copy --destdir=/tmp/Allure-	tar -czf /tmp/Allure_x_ubuntu-12.04-amd64.tar.gz -C /tmp --exclude=Allure/usr/local/lib --exclude=Allure/usr/local/share/doc 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=/usr/local --ghc-option="-optc-m32" --ghc-option="-opta-m32" --ghc-option="-optl-m32" --ld-option="-melf_i386"-	cabal build exe:Allure-	rm -rf /tmp/Allure-	cabal copy --destdir=/tmp/Allure-	tar -czf /tmp/Allure_x_ubuntu-12.04-i386.tar.gz -C /tmp --exclude=Allure/usr/local/lib --exclude=Allure/usr/local/share/doc Allure+	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  # TODO: figure out, whey this must be so different from Linux build-binary-windows-i386:@@ -297,18 +249,3 @@ 	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---# The rest of the makefile is unmaintained at the moment.--default : dist/setup-config-	runghc Setup build--dist/setup-config : Allure.cabal-	runghc Setup configure --user--clean :-	runghc Setup clean--ghci :-	ghci -XCPP -idist/build/autogen:GameDefinition
README.md view
@@ -33,7 +33,7 @@ ---------------------------------  The game UI can be configured via a config file.-The commented out version of this file with the default settings is in+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@@ -41,29 +41,29 @@ (or `C:\Documents And Settings\user\Application Data\Allure\config.ui.ini` or something else altogether) on Windows. -Screen font can be changed and enlarged by uncommenting and editing-the config file at its official location or by right-clicking-on the game window.+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.  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. When you turn NumLock on,+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 for the error-prone step by step walking.+and requiring SHIFT (or CONTROL) for the error-prone step by step walking. -If you don't have a numeric keypad, you can use laptop keys (uk8o79jl)+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.   Compilation from source ----------------------- -The game is best compiled and installed via 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].+If you want to compile your own 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]. @@ -71,7 +71,7 @@ compiled and installed automatically by Cabal from [Hackage] [3] as follows      cabal install gtk2hs-buildtools-    cabal install Allure+    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]@@ -80,23 +80,23 @@ Compatibility notes ------------------- -The current code was tested with GHC 7.6 and 7.8,-but should also work with other GHC versions, with minor modifications.--If you are using the terminal frontends, numerical keypad may not work+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 run in an xterm,+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.-Laptop (uk8o79jl) and Vi keys (hjklyubn, if enabled in config.ui.ini)-should work everywhere regardless. GTK works fine, too.+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.-Many tests that use the screensaver game modes (AI vs. AI)+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. Test commands with prefix `frontend` start AI vs. AI games@@ -123,7 +123,7 @@ Copyright --------- -Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski+Copyright (c) 2008--2011 Andres Loeh, 2010--2015 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
test/test.hs view
@@ -1,6 +1,6 @@ import TieKnot  main :: IO ()-main = do+main =   tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --gameMode campaign --setDungeonRng 42 --setMainRng 42"   -- tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --gameMode battle --setDungeonRng 42 --setMainRng 42"