packages feed

Allure 0.4.14 → 0.4.99.0

raw patch · 20 files changed

+641/−595 lines, 20 filesdep −arraydep −assert-failuredep −asyncdep ~LambdaHack

Dependencies removed: array, assert-failure, async, binary, bytestring, deepseq, directory, ghc-prim, hashable, hsini, keys, miniutter, mtl, old-time, pretty-show, random, stm, transformers, unordered-containers, vector, vector-binary-instances, zlib

Dependency ranges changed: LambdaHack

Files

Allure.cabal view
@@ -1,11 +1,17 @@-name:          Allure-version:       0.4.14-synopsis:      Near-future roguelike game in early development-description:   This is an alpha release of Allure of the Stars,-               a near-future Sci-Fi roguelike and tactical squad game.+name:           Allure+-- The package version. See the Haskell package versioning policy (PVP)+-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary: +-+------- breaking API changes+--              | | +----- non-breaking API additions+--              | | |  +--- code changes with no API change+version:        0.4.99.0+synopsis:       Near-future Sci-Fi roguelike and tactical squad game+description:   Allure of the Stars+               is a near-future Sci-Fi roguelike and tactical squad game.                See the wiki for design notes and contribute.                .-               <<GameDefinition/screenshot.png>>+               <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/safari1.png>>                .                Please see the changelog file for recent improvements                and the issue tracker for short-term plans. Long term goals@@ -20,11 +26,11 @@ license:       OtherLicense license-file:  LICENSE tested-with:   GHC == 7.6.3, GHC == 7.8-data-files:    GameDefinition/config.ui.default,-               GameDefinition/scores-extra-source-files: GameDefinition/PLAYING.md, GameDefinition/MainMenu.ascii,-                    README.md, LICENSE, CREDITS, CHANGELOG.md, Makefile-extra-doc-files: GameDefinition/screenshot.png+data-files:    GameDefinition/config.ui.default, GameDefinition/scores,+               GameDefinition/PLAYING.md, README.md, LICENSE, CREDITS,+               CHANGELOG.md+extra-source-files: GameDefinition/MainMenu.ascii, Makefile+-- extra-doc-files: GameDefinition/screenshot.png author:        Andres Loeh, Mikolaj Konarski and others maintainer:    Mikolaj Konarski <mikolaj.konarski@funktory.com> category:      Game@@ -40,47 +46,25 @@   main-is:            Main.hs   other-modules:      Client.UI.Content.KeyKind,                       Content.CaveKind,-                      Content.FactionKind,                       Content.ItemKind,                       Content.ItemKindActor,                       Content.ItemKindOrgan,                       Content.ItemKindShrapnel,                       Content.ModeKind,+                      Content.ModeKindPlayer,                       Content.PlaceKind,                       Content.RuleKind,                       Content.TileKind,                       TieKnot,                       Paths_Allure-  build-depends:      LambdaHack >= 0.2.14 && <= 0.2.15,+  build-depends:      LambdaHack >= 0.4.99.0 && < 0.5.1.0,                       template-haskell >= 2.6 && < 3, -                      array      >= 0.3.0.3 && < 1,-                      assert-failure >= 0.1 && < 1,-                      async      >= 2       && < 3,                       base       >= 4       && < 5,-                      binary     >= 0.7     && < 1,-                      bytestring >= 0.9.2   && < 1,                       containers >= 0.5     && < 1,-                      deepseq    >= 1.3     && < 2,-                      directory  >= 1.1.0.1 && < 2,                       enummapset-th >= 0.6.0.0 && < 1,                       filepath   >= 1.2.0.1 && < 2,-                      ghc-prim   >= 0.2,-                      hashable   >= 1.1.2.5 && < 2,-                      hsini      >= 0.2     && < 2,-                      keys       >= 3       && < 4,-                      miniutter  >= 0.4.1   && < 2,-                      mtl        >= 2.0.1   && < 3,-                      old-time   >= 1.0.0.7 && < 2,-                      pretty-show >= 1.6    && < 2,-                      random     >= 1.0.1   && < 2,-                      stm        >= 2.4     && < 3,-                      text       >= 0.11.2.3 && < 2,-                      transformers >= 0.3   && < 1,-                      unordered-containers >= 0.2.3 && < 1,-                      vector     >= 0.10    && < 1,-                      vector-binary-instances >= 0.2 && < 1,-                      zlib       >= 0.5.3.1 && < 1+                      text       >= 0.11.2.3 && < 2    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings@@ -99,33 +83,11 @@   build-depends:      LambdaHack,                       template-haskell >= 2.6 && < 3, -                      array      >= 0.3.0.3 && < 1,-                      assert-failure >= 0.1 && < 1,-                      async      >= 2       && < 3,                       base       >= 4       && < 5,-                      binary     >= 0.7     && < 1,-                      bytestring >= 0.9.2   && < 1,                       containers >= 0.5     && < 1,-                      deepseq    >= 1.3     && < 2,-                      directory  >= 1.1.0.1 && < 2,                       enummapset-th >= 0.6.0.0 && < 1,                       filepath   >= 1.2.0.1 && < 2,-                      ghc-prim   >= 0.2,-                      hashable   >= 1.1.2.5 && < 2,-                      hsini      >= 0.2     && < 2,-                      keys       >= 3       && < 4,-                      miniutter  >= 0.4.1   && < 2,-                      mtl        >= 2.0.1   && < 3,-                      old-time   >= 1.0.0.7 && < 2,-                      pretty-show >= 1.6    && < 2,-                      random     >= 1.0.1   && < 2,-                      stm        >= 2.4     && < 3,-                      text       >= 0.11.2.3 && < 2,-                      transformers >= 0.3   && < 1,-                      unordered-containers >= 0.2.3 && < 1,-                      vector     >= 0.10    && < 1,-                      vector-binary-instances >= 0.2 && < 1,-                      zlib       >= 0.5.3.1 && < 1+                      text       >= 0.11.2.3 && < 2    default-language:   Haskell2010   default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings
CHANGELOG.md view
@@ -1,3 +1,11 @@+## [v0.4.99.0, aka 'Player escapes through airlock'](https://github.com/LambdaHack/LambdaHack/compare/v0.4.14...v0.4.99.0)++- balance game content a bit (campaign still unbalanced)+- fix a bug where doors can't be closed+- assign AI tactics to players, in particular use follow-the-leader in safari+- specify monster spawn rate per-cave+- generally update content to the new v0.5.0.0 of LambdaHack content API+ ## [v0.4.14, aka 'Out of cosmic balance'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.12...v0.4.14)  - add tons of new (unbalanced) items, actors and descriptions
GameDefinition/Client/UI/Content/KeyKind.hs view
@@ -81,16 +81,7 @@       , ("c", ([CmdMove], AlterDir            [ AlterFeature { verb = "close"                           , object = "door"-                          , feature = F.CloseTo "vertical closed door Lit" }-           , AlterFeature { verb = "close"-                          , object = "door"-                          , feature = F.CloseTo "horizontal closed door Lit" }-           , AlterFeature { verb = "close"-                          , object = "door"-                          , feature = F.CloseTo "vertical closed door Dark" }-           , AlterFeature { verb = "close"-                          , object = "door"-                          , feature = F.CloseTo "horizontal closed door Dark" }+                          , feature = F.CloseTo "closed door" }            ]))       , ("period", ([CmdMove], Macro "" ["KP_Begin"]))       , ("i", ([CmdMove], Macro "" ["KP_Begin"]))@@ -116,7 +107,7 @@       , ("p", ([CmdItem], MoveItem [CEqp, CSha] CInv                                    "pack" "an item into inventory backpack"                                    False))-      , ("s", ([CmdItem], MoveItem [CEqp, CInv] CSha+      , ("s", ([CmdItem], MoveItem [CInv, CEqp] CSha                                    "stash" "and share an item" False))       , ("a", ([CmdItem, CmdMinimal], Apply            [ ApplyItem { verb = "activate"@@ -169,6 +160,7 @@       , ("CTRL-v", ([CmdAuto], Repeat 1000))       , ("CTRL-V", ([CmdAuto], Repeat 10))       , ("apostrophe", ([CmdAuto], Record))+      , ("CTRL-T", ([CmdAuto], Tactic))       , ("CTRL-A", ([CmdAuto], Automate))        -- Assorted
GameDefinition/Content/CaveKind.hs view
@@ -3,7 +3,7 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Cave layouts for Allure of the Stars.+-- | Cave layouts. module Content.CaveKind ( cdefs ) where  import Data.Ratio@@ -18,7 +18,8 @@   { getSymbol = csymbol   , getName = cname   , getFreq = cfreq-  , validate = validateCaveKind+  , validateSingle = validateSingleCaveKind+  , validateAll = validateAllCaveKind   , content =       [rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3]   }@@ -27,7 +28,7 @@ rogue = CaveKind   { csymbol       = 'R'   , cname         = "Storage area"-  , cfreq         = [("dng", 100), ("caveRogue", 1)]+  , cfreq         = [("campaign random", 100), ("caveRogue", 1)]   , cxsize        = fst normalLevelBound + 1   , cysize        = snd normalLevelBound + 1   , cgrid         = DiceXY (3 * d 2) (d 2 + 2)@@ -41,9 +42,10 @@   , cdoorChance   = 1%2   , copenChance   = 1%10   , chidden       = 8+  , cactorCoeff   = 20   , cactorFreq    = [("alien", 33), ("animal", 33), ("robot", 33)]-  , citemNum      = 10 * d 2-  , citemFreq     = [("useful", 70), ("treasure", 30)]+  , citemNum      = 15 * d 2+  , citemFreq     = [("useful", 50), ("treasure", 50)]   , cplaceFreq    = [("rogue", 100)]   , cpassable     = False   , cdefTile        = "fillerWall"@@ -57,15 +59,16 @@ arena = rogue   { csymbol       = 'A'   , cname         = "Recreational deck"-  , cfreq         = [("dng", 100), ("caveArena", 1)]+  , cfreq         = [("campaign random", 100), ("caveArena", 1)]   , cgrid         = DiceXY (2 * d 2) (2 * d 2)   , cminPlaceSize = DiceXY (2 * d 2 + 3) 4   , cdarkChance   = d 80 + dl 60   , cnightChance  = 0-  , cmaxVoid      = 1%3+  , cmaxVoid      = 1%4   , chidden       = 1000+  , cactorCoeff   = 40   , cactorFreq    = [("alien", 15), ("animal", 80), ("robot", 5)]-  , citemNum      = 8 * d 2  -- few rooms+  , citemNum      = 11 * d 2  -- few rooms   , cpassable     = True   , cdefTile      = "arenaSet"   , cdarkCorTile  = "trailLit"  -- let trails give off light@@ -75,18 +78,19 @@ empty = rogue   { csymbol       = 'E'   , cname         = "Construction site"-  , cfreq         = [("dng", 100), ("caveEmpty", 1)]+  , cfreq         = [("campaign random", 100), ("caveEmpty", 1)]   , cgrid         = DiceXY (d 2 + 1) 1   , cminPlaceSize = DiceXY 10 10-  , cmaxPlaceSize = DiceXY 24 12+  , cmaxPlaceSize = DiceXY 24 15   , cdarkChance   = d 80 + dl 80   , cnightChance  = 0   , cauxConnects  = 1   , cmaxVoid      = 1%2   , cminStairDist = 50   , chidden       = 1000+  , cactorCoeff   = 50   , cactorFreq    = [("alien", 5), ("animal", 15), ("robot", 80)]-  , citemNum      = 6 * d 2  -- few rooms+  , citemNum      = 9 * d 2  -- few rooms   , cpassable     = True   , cdefTile      = "emptySet"   , cdarkCorTile  = "floorArenaDark"@@ -96,18 +100,19 @@ noise = rogue   { csymbol       = 'N'   , cname         = "Machine rooms"-  , cfreq         = [("dng", 100), ("caveNoise", 1)]-  , cgrid         = DiceXY 3 3-  , cminPlaceSize = DiceXY 8 4-  , cmaxPlaceSize = DiceXY 24 12-  , cnightChance  = d 100+  , cfreq         = [("campaign random", 50), ("caveNoise", 1)]+  , cgrid         = DiceXY (2 + d 2) 3+  , cminPlaceSize = DiceXY 12 5+  , cmaxPlaceSize = DiceXY 24 15+  , cnightChance  = d 80 + dl 80   , cauxConnects  = 0   , cmaxVoid      = 0   , chidden       = 1000+  , cactorCoeff   = 30   , cactorFreq    = [("alien", 80), ("animal", 5), ("robot", 15)]-  , citemNum      = 12 * d 2  -- an incentive to explore the labyrinth+  , citemNum      = 16 * d 2  -- an incentive to explore the labyrinth   , cpassable     = True-  , cplaceFreq    = [("noise", 50), ("rogue", 50)]+  , cplaceFreq    = [("noise", 100)]   , cdefTile      = "noiseSet"   , cdarkCorTile  = "floorArenaDark"   , clitCorTile   = "floorArenaLit"@@ -117,16 +122,17 @@   , cname         = "Ravaged spaceport"   , cfreq         = [("caveBattle", 1)]   , cgrid         = DiceXY (2 * d 2 + 1) 3-  , cminPlaceSize = DiceXY 3 3+  , cminPlaceSize = DiceXY 4 4   , cmaxPlaceSize = DiceXY 9 7   , cdarkChance   = 0   , cnightChance  = 100+  , cmaxVoid      = 0   , cdoorChance   = 2%10   , copenChance   = 9%10   , chidden       = 1000   , cactorFreq    = []-  , citemNum      = 12 * d 2-  , citemFreq     = [("useful", 100)]+  , citemNum      = 20 * d 2+  , citemFreq     = [("useful", 100), ("light source", 200)]   , cplaceFreq    = [("battle", 50), ("rogue", 50)]   , cpassable     = True   , cdefTile      = "battleSet"@@ -146,7 +152,7 @@   , copenChance   = 0   , chidden       = 1000   , cactorFreq    = []-  , citemNum      = 12 * d 2+  , citemNum      = 20 * d 2   , citemFreq     = [("useful", 100)]   , cplaceFreq    = [("skirmish", 60), ("rogue", 40)]   , cpassable     = True@@ -168,8 +174,8 @@   , copenChance   = 9%10   , chidden       = 1000   , cactorFreq    = []-  , citemNum      = 12 * d 2-  , citemFreq     = [("useful", 100)]+  , citemNum      = 22 * d 2+  , citemFreq     = [("useful", 100), ("light source", 200)]   , cplaceFreq    = [("ambush", 100)]   , cpassable     = True   , cdefTile      = "ambushSet"
− GameDefinition/Content/FactionKind.hs
@@ -1,90 +0,0 @@--- 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.------ | The type of kinds of game factions (heroes, enemies, NPCs, etc.)--- for Allure of the Stars.-module Content.FactionKind ( cdefs ) where--import qualified Data.EnumMap.Strict as EM--import Game.LambdaHack.Common.Ability-import Game.LambdaHack.Common.ContentDef-import Game.LambdaHack.Content.FactionKind--cdefs :: ContentDef FactionKind-cdefs = ContentDef-  { getSymbol = fsymbol-  , getName = fname-  , getFreq = ffreq-  , validate = validateFactionKind-  , content =-      [hero, civilian, alien, animal, robot, horror]-  }-hero,        civilian, alien, animal, robot, horror :: FactionKind--hero = FactionKind-  { fsymbol       = '1'-  , fname         = "hero"-  , ffreq         = [("hero", 1)]-  , fSkillsLeader = allSkills-  , fSkillsOther  = meleeAdjacent-  }--civilian = FactionKind-  { fsymbol       = '@'-  , fname         = "civilian"-  , ffreq         = [("civilian", 1)]-  , fSkillsLeader = allSkills-  , fSkillsOther  = allSkills  -- not coordinated by any leadership-  }---- Includes alien-operated robots, alien-conditioned animals and hybrids.-alien = FactionKind-  { fsymbol       = 'a'-  , fname         = "alien"-  , ffreq         = [("alien", 1)]-  , fSkillsLeader = allSkills-  , fSkillsOther  = allSkills-  }--animal = FactionKind-  { fsymbol       = 'd'-  , fname         = "animal"-  , ffreq         = [("animal", 1)]-  , fSkillsLeader = animalSkills-  , fSkillsOther  = animalSkills-  }---- Autonomous robots.-robot = FactionKind-  { fsymbol       = 'r'-  , fname         = "robot"-  , ffreq         = [("robot", 1)]-  , fSkillsLeader = robotSkills-  , fSkillsOther  = robotSkills-  }--horror = FactionKind-  { fsymbol       = 'h'-  , fname         = "horror"-  , ffreq         = [("horror", 1)]-  , fSkillsLeader = allSkills-  , fSkillsOther  = allSkills-  }---meleeAdjacent, _meleeAndRanged, animalSkills, robotSkills, allSkills :: Skills--meleeAdjacent = EM.fromList $ zip [AbWait, AbMelee] [1, 1..]---- Melee and reaction fire.-_meleeAndRanged = EM.fromList $ zip [AbWait, AbMelee, AbProject] [1, 1..]--animalSkills =-  EM.fromList $ zip [AbMove, AbMelee, AbAlter, AbWait, AbTrigger] [1, 1..]--robotSkills = EM.delete AbApply unitSkills--allSkills = unitSkills
GameDefinition/Content/ItemKind.hs view
@@ -3,7 +3,7 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Weapon and treasure definitions.+-- | Item and treasure definitions. module Content.ItemKind ( cdefs ) where  import Data.List@@ -24,15 +24,16 @@   { getSymbol = isymbol   , getName = iname   , getFreq = ifreq-  , validate = validateItemKind+  , validateSingle = validateSingleItemKind+  , validateAll = validateAllItemKind   , content = items ++ organs ++ shrapnels ++ actors   }  items :: [ItemKind] items =-  [canOfGlue, crankSpotlight, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, jumpingPole, contactLens, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, needle, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, ring1, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, candle, armorLeather, armorMail, honingSteel, constructionHooter]+  [canOfGlue, crankSpotlight, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, jumpingPole, contactLens, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, needle, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, potion11, ring1, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, candle, armorLeather, armorMail, honingSteel, constructionHooter] -canOfGlue,    crankSpotlight, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, jumpingPole, contactLens, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, needle, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, ring1, potion8, potion9, potion10, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, candle, armorLeather, armorMail, honingSteel, constructionHooter :: ItemKind+canOfGlue,    crankSpotlight, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, jumpingPole, contactLens, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, needle, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, ring1, potion8, potion9, potion10, potion11, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, candle, armorLeather, armorMail, honingSteel, constructionHooter :: ItemKind  gem, necklace, potion, ring, scroll, wand :: ItemKind  -- generic templates @@ -67,7 +68,7 @@   , ifreq    = [("useful", 100), ("any arrow", 100)]   , iflavour = zipPlain [BrCyan]   , icount   = 3 * d 3-  , irarity  = [(1, 20)]+  , irarity  = [(1, 20), (10, 10)]   , iverbHit = "prick"   , iweight  = 100   , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]@@ -82,7 +83,7 @@   , ifreq    = [("useful", 100), ("any arrow", 50)]  -- TODO: until arrows added   , iflavour = zipPlain [BrWhite]   , icount   = 3 * d 3-  , irarity  = [(4, 20)]+  , irarity  = [(4, 20), (10, 10)]   , iverbHit = "strike"   , iweight  = 300   , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]@@ -115,7 +116,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [Brown]   , icount   = dl 5-  , irarity  = [(5, 3), (10, 5)]+  , irarity  = [(5, 5), (10, 5)]   , iverbHit = "hook"   , iweight  = 4000   , iaspects = [AddHurtRanged ((d 2 + 2 * dl 5) |*| 10)]@@ -161,10 +162,10 @@ candle = ItemKind   { isymbol  = '~'   , iname    = "candle"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1-  , irarity  = [(1, 10)]+  , irarity  = [(1, 8), (3, 6)]   , iverbHit = "scorch"   , iweight  = 500   , iaspects = [ AddLight 3@@ -178,10 +179,10 @@ oilLamp = ItemKind   { isymbol  = '~'   , iname    = "oil lamp"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(5, 4), (10, 4)]+  , irarity  = [(5, 5), (10, 5)]   , iverbHit = "burn"   , iweight  = 1000   , iaspects = [AddLight 3, AddSight (-1)]@@ -194,10 +195,10 @@ crankSpotlight = ItemKind   { isymbol  = '~'   , iname    = "crank spotlight"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("light source", 100)]   , iflavour = zipPlain [BrWhite]   , icount   = 1-  , irarity  = [(10, 2)]+  , irarity  = [(10, 3)]   , iverbHit = "snag"   , iweight  = 2400   , iaspects = [AddLight 4, AddArmorRanged $ - d 3]  -- noise and busy hands@@ -240,7 +241,7 @@   , ifreq    = [("treasure", 100), ("currency", 1)]   , iflavour = zipPlain [BrYellow]   , icount   = 10 + d 20 + dl 20-  , irarity  = [(1, 0), (5, 20), (10, 10)]+  , irarity  = [(1, 0), (2, 15), (5, 25), (10, 10)]   , iverbHit = "tap"   , iweight  = 1   , iaspects = []@@ -273,7 +274,7 @@   , iname    = "necklace"   , ifreq    = [("useful", 100)]   , iflavour = zipFancy stdCol ++ zipPlain brightCol-  , irarity  = [(4, 2), (10, 5)]+  , irarity  = [(10, 3)]   , icount   = 1   , iverbHit = "whip"   , iweight  = 30@@ -292,7 +293,7 @@   { irarity  = [(2, 0), (10, 1)]   , iaspects = [Periodic $ d 4 + dl 2]   , ieffects = [ Impress-               , Summon [("summonable animal", 1)] $ 1 + dl 2, Explode "waste" ]+               , Summon [("mobile animal", 1)] $ 1 + dl 2, Explode "waste" ]   } necklace3 = necklace   { iaspects = [Periodic $ d 4 + dl 2]@@ -300,11 +301,11 @@   } necklace4 = necklace   { iaspects = [Periodic $ 2 * d 10 + dl 10]-  , ieffects = [Teleport $ 2 + d 3]+  , ieffects = [Teleport $ d 3 |*| 3]   } necklace5 = necklace   { iaspects = [Periodic $ d 4 + dl 2]-  , ieffects = [Teleport $ 10 + d 10]+  , ieffects = [Teleport $ 12 + d 3 |*| 3]   } necklace6 = necklace   { iaspects = [Periodic $ 2 * d 5 + dl 5]@@ -315,7 +316,7 @@   , iaspects = [Periodic $ 2 * d 5 + dl 15]   , ieffects = [InsertMove 1, RefillHP (-1)]   , ifeature = ifeature necklace ++ [Durable]-                 -- evil players would throw before death, to destroy+      -- evil players would throw before death, to destroy       -- TODO: teach AI to wear only for fight; prevent players from meleeing       -- allies with that (Durable)   }@@ -328,10 +329,10 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [White]   , icount   = 1-  , irarity  = [(6, 0), (10, 1)]+  , irarity  = [(5, 0), (10, 1)]   , iverbHit = "rap"   , iweight  = 50-  , iaspects = [AddSight $ dl 3]+  , iaspects = [AddSight $ d 2, AddHurtMelee $ d 2 |*| 3]   , ieffects = []   , ifeature = [Precious, Identified, Durable, EqpSlot EqpSlotAddSight ""]   , idesc    = "Advanced design. Never needs to be taken off."@@ -343,7 +344,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain stdCol ++ zipFancy darkCol   , icount   = 1-  , irarity  = [(6, 2), (10, 5)]+  , irarity  = [(10, 3)]   , iverbHit = "knock"   , iweight  = 15   , iaspects = []@@ -354,7 +355,7 @@   } ring1 = ring   { irarity  = [(2, 0), (10, 2)]-  , iaspects = [AddSpeed 1, AddMaxHP $ dl 3 - 5 - d 3]+  , iaspects = [AddSpeed $ d 2, AddMaxHP $ dl 3 - 5 - d 3]   , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddSpeed ""]   } ring2 = ring@@ -367,14 +368,15 @@   , idesc    = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."   } ring4 = ring  -- TODO: move to level-ups and to timed effects-  { irarity  = [(3, 8), (10, 12)]-  , iaspects = [AddHurtMelee $ 3 * d 4 + dl 15, AddMaxHP $ dl 3 - 4 - d 2]+  { irarity  = [(3, 12), (10, 12)]+  , iaspects = [AddHurtMelee $ (d 5 + dl 5) |*| 3, AddMaxHP $ dl 3 - 4 - d 2]   , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddHurtMelee ""]   } ring5 = ring  -- by the time it's found, probably no space in eqp-  { irarity  = [(5, 0), (10, 1)]+  { irarity  = [(5, 0)]   , iaspects = [AddLight $ d 2]   , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddLight ""]+  , idesc    = "A sturdy ring with a large, shining stone."   }  -- * Exploding consumables, often intended to be thrown@@ -385,7 +387,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain stdCol ++ zipFancy brightCol   , icount   = 1-  , irarity  = [(1, 10), (10, 8)]+  , irarity  = [(1, 15), (10, 12)]   , iverbHit = "splash"   , iweight  = 200   , iaspects = []@@ -396,34 +398,35 @@   , ikit     = []   } potion1 = potion-  { ieffects = [ NoEffect "rose water", Impress+  { ieffects = [ NoEffect "of rose water", Impress                , OnSmash (ApplyPerfume), OnSmash (Explode "fragrance") ]   } potion2 = potion-  { irarity  = [(10, 1)]-  , ieffects = [ NoEffect "musky concoction", Impress, DropBestWeapon+  { ifreq    = [("useful", 1)]  -- extremely rare+  , irarity  = [(1, 1)]+  , ieffects = [ NoEffect "of musky concoction", Impress, DropBestWeapon                , OnSmash (Explode "pheromone")]   } potion3 = potion   { ieffects = [RefillHP 5, OnSmash (Explode "healing mist")]   } potion4 = potion  -- TODO: a bit boring-  { irarity  = [(1, 5)]+  { irarity  = [(1, 7)]   , ieffects = [RefillHP (-5), OnSmash (Explode "wounding mist")]   } potion5 = potion-  { ieffects = [ Explode "explosion blast 10"+  { ieffects = [ Explode "explosion blast 10", Impress                , PushActor (ThrowMod 200 75)                , OnSmash (Explode "explosion blast 10") ]   } potion6 = potion   { irarity  = [(10, 2)]-  , ieffects = [ NoEffect "distortion", Impress+  , ieffects = [ NoEffect "of distortion", Impress                , OnSmash (Explode "distortion")]   } potion7 = potion-  { ieffects = [ NoEffect "bait cocktail", Impress-               , OnSmash (Summon [("summonable animal", 1)] $ 1 + dl 2)+  { ieffects = [ NoEffect "of bait cocktail", Impress+               , OnSmash (Summon [("mobile animal", 1)] $ 1 + dl 2)                , OnSmash (Explode "waste") ]   } potion8 = potion@@ -434,22 +437,27 @@                                 , Explode "explosion blast 10" ]) ]   } potion9 = potion-  { irarity  = [(4, 1), (10, 2)]-  , ieffects = [ OneOf [ Dominate, DropBestWeapon, RefillHP 15, Burn 9+  { irarity  = [(3, 3), (10, 6)]+  , ieffects = [ OneOf [ Dominate, DropBestWeapon, RefillHP 20, Burn 9                        , InsertMove 2]-               , OnSmash (OneOf [ Explode "healing mist"-                                , Explode "healing mist"+               , OnSmash (OneOf [ Explode "healing mist 2"+                                , Explode "healing mist 2"                                 , Explode "pheromone"                                 , Explode "distortion"                                 , Explode "explosion blast 20" ]) ]   }-potion10 = potion+potion10 = potion  -- used only as initial equipmnt; count betray identity   { ifreq    = [("useful", 100), ("potion of glue", 1)]   , irarity  = [(1, 1)]   , icount   = 1 + d 2-  , ieffects = [ NoEffect "sticky foam", Paralyze (5 + d 5)+  , ieffects = [ NoEffect "of sticky foam", Paralyze (5 + d 5)                , OnSmash (Explode "glue")]+  , ifeature = [Identified]   }+potion11 = potion+  { irarity  = [(10, 5)]+  , ieffects = [RefillHP 10, OnSmash (Explode "healing mist 2")]+  }  -- * Non-exploding consumables, not specifically designed for throwing @@ -470,7 +478,7 @@   , ifreq    = [("useful", 100), ("any scroll", 100)]   , iflavour = zipFancy stdCol ++ zipPlain darkCol  -- arcane and old   , icount   = 1-  , irarity  = [(1, 10), (10, 7)]+  , irarity  = [(1, 15), (10, 12)]   , iverbHit = "thump"   , iweight  = 700   , iaspects = []@@ -481,23 +489,23 @@   , ikit     = []   } scroll1 = scroll-  { irarity  = [(10, 2)]+  { irarity  = [(1, 2), (10, 3)]   , ieffects = [CallFriend 1]   } scroll2 = scroll-  { irarity  = [(1, 5), (10, 3)]+  { irarity  = [(1, 7), (10, 5)]   , ieffects = [NoEffect "of fireworks", Explode "firecracker 7"]   } scroll3 = scroll-  { irarity  = [(1, 4), (10, 2)]+  { irarity  = [(1, 5), (10, 3)]   , ieffects = [Ascend 1]   } scroll4 = scroll-  { ieffects = [ OneOf [ Teleport $ 2 + d 5, RefillCalm 10, RefillCalm (-10)+  { ieffects = [ OneOf [ Teleport $ d 3 |*| 3, RefillCalm 10, RefillCalm (-10)                        , InsertMove 4, Paralyze 10, Identify CGround ] ]   } scroll5 = scroll-  { irarity  = [(1, 4), (10, 6)]+  { irarity  = [(3, 3), (10, 6)]   , ieffects = [ OneOf [ Summon standardSummon $ d 2                        , CallFriend 1, Ascend (-1), Ascend 1                        , RefillCalm 30, RefillCalm (-30), CreateItem $ d 2@@ -505,25 +513,25 @@                -- TODO: ask player: Escape 1   } scroll6 = scroll-  { ieffects = [Teleport $ 2 + d 5]+  { ieffects = [Teleport $ d 3 |*| 3]   } scroll7 = scroll-  { irarity  = [(10, 2)]+  { irarity  = [(10, 3)]   , ieffects = [InsertMove $ d 2 + dl 2]   } scroll8 = scroll-  { irarity  = [(3, 6), (10, 3)]+  { irarity  = [(3, 8), (10, 4)]   , ieffects = [Identify CGround]  -- TODO: ask player: AskPlayer cstore eff?   } scroll9 = scroll-  { irarity  = [(3, 3), (10, 9)]+  { irarity  = [(10, 10)]   , ieffects = [PolyItem CGround]   }  standardSummon :: Freqs standardSummon = [ ("alien", 20)-                 , ("summonable animal", 50)-                 , ("summonable robot", 30) ]+                 , ("mobile animal", 50)+                 , ("mobile robot", 30) ]  -- * Armor @@ -533,7 +541,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1-  , irarity  = [(4, 9)]+  , irarity  = [(3, 6), (10, 3)]   , iverbHit = "thud"   , iweight  = 7000   , iaspects = [ AddHurtMelee (-3)@@ -548,11 +556,11 @@ armorMail = armorLeather   { iname    = "bulletproof vest"   , iflavour = zipPlain [Cyan]-  , irarity  = [(7, 9)]+  , irarity  = [(6, 6), (10, 6)]   , iweight  = 12000   , iaspects = [ AddHurtMelee (-3)-               , AddArmorMelee $ (2 + dl 3) |*| 5-               , AddArmorRanged $ (2 + dl 3) |*| 5 ]+               , AddArmorMelee $ (2 + dl 4) |*| 5+               , AddArmorRanged $ (2 + dl 4) |*| 5 ]   , idesc    = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow."   } gloveFencing = ItemKind@@ -561,11 +569,11 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [BrYellow]   , icount   = 1-  , irarity  = [(4, 6), (10, 12)]+  , irarity  = [(5, 8), (10, 8)]   , iverbHit = "flap"   , iweight  = 100-  , iaspects = [ AddHurtMelee $ 2 * (d 3 + 2 * dl 5)-               , AddArmorRanged $ d 2 + dl 2 ]+  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) * 3+               , AddArmorRanged $ d 2 |*| 5 ]   , ieffects = []   , ifeature = [ toVelocity 30  -- flaps and flutters                , Durable, EqpSlot EqpSlotAddArmorRanged "", Identified ]@@ -577,8 +585,8 @@   , irarity  = [(6, 12)]   , iflavour = zipPlain [BrCyan]   , iweight  = 300-  , iaspects = [ AddArmorMelee $ 2 * (d 2 + dl 2)-               , AddArmorRanged $ 2 * (d 2 + dl 2) ]+  , 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@@ -586,9 +594,9 @@   , irarity  = [(6, 6)]   , iflavour = zipFancy [BrRed]   , iweight  = 500-  , iaspects = [ AddHurtMelee $ - 10 - d 5 + dl 5-               , AddArmorMelee $ 2 * (d 2 + dl 3)-               , AddArmorRanged $ 2 * (d 2 + dl 3) ]+  , iaspects = [ 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."   } -- Shield doesn't protect against ranged attacks to prevent@@ -599,7 +607,7 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(4, 7)]+  , irarity  = [(4, 6)]   , iverbHit = "bash"   , iweight  = 2000   , iaspects = [AddArmorMelee 40, AddHurtMelee (-30)]@@ -611,7 +619,7 @@   } shield = buckler   { iname    = "shield"-  , irarity  = [(7, 7)]+  , irarity  = [(7, 5)]   , iflavour = zipPlain [Green]   , iweight  = 3000   , iaspects = [AddArmorMelee 80, AddHurtMelee (-70)]@@ -624,31 +632,31 @@  dagger = ItemKind   { isymbol  = '|'-  , iname    = "kitchen knife"-  , ifreq    = [("useful", 100)]+  , iname    = "cleaver"+  , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrCyan]   , icount   = 1-  , irarity  = [(1, 20), (10, 4)]+  , irarity  = [(1, 12), (10, 4)]   , iverbHit = "stab"   , iweight  = 1000-  , iaspects = [AddHurtMelee $ 2 * (d 3 + 2 * dl 5), AddArmorMelee $ d 4 + dl 4]-  , ieffects = [Hurt (4 * d 1)]+  , iaspects = [AddHurtMelee $ (d 3 + dl 3) |*| 3, AddArmorMelee $ d 2 |*| 5]+  , ieffects = [Hurt (6 * d 1)]   , ifeature = [ toVelocity 40  -- ensuring it hits with the tip costs speed                , Durable, EqpSlot EqpSlotWeapon "", Identified ]-  , idesc    = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and also thrusting and parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."+  , idesc    = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."   , ikit     = []   } hammer = ItemKind   { isymbol  = '\\'   , iname    = "demolition hammer"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrMagenta]   , icount   = 1   , irarity  = [(4, 12), (10, 2)]   , iverbHit = "club"   , iweight  = 1500-  , iaspects = [AddHurtMelee $ d 3 + 2 * dl 5]-  , ieffects = [Hurt (6 * d 1)]+  , iaspects = [AddHurtMelee $ (d 2 + dl 2) |*| 3]+  , ieffects = [Hurt (8 * d 1)]   , ifeature = [ toVelocity 20  -- ensuring it hits with the sharp tip costs                , Durable, EqpSlot EqpSlotWeapon "", Identified ]   , idesc    = "A hammer on a long handle used for construction work. It may not cause grave wounds, but neither does it ricochet or glance off armor. Great sidearm for opportunistic blows against armored foes."@@ -657,14 +665,14 @@ sword = ItemKind   { isymbol  = '/'   , iname    = "sharpened pipe"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("starting weapon", 100)]   , iflavour = zipPlain [BrBlue]   , icount   = 1-  , irarity  = [(3, 1), (6, 20), (10, 10)]+  , irarity  = [(3, 1), (6, 16), (10, 8)]   , iverbHit = "slash"   , iweight  = 2000   , iaspects = []-  , ieffects = [Hurt (9 * d 1)]+  , ieffects = [Hurt (10 * d 1)]   , ifeature = [ toVelocity 20  -- 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."@@ -673,14 +681,14 @@ halberd = ItemKind   { isymbol  = '/'   , iname    = "halberd"-  , ifreq    = [("useful", 100)]+  , ifreq    = [("useful", 100), ("starting weapon", 1)]   , iflavour = zipPlain [BrYellow]   , icount   = 1   , irarity  = [(7, 1), (10, 10)]   , iverbHit = "impale"   , iweight  = 3000-  , iaspects = [AddArmorMelee $ 2 * (d 4 + dl 4)]-  , ieffects = [Hurt (12 * d 1)]+  , iaspects = [AddArmorMelee $ (1 + dl 3) |*| 5]+  , ieffects = [Hurt (14 * d 1)]   , ifeature = [ toVelocity 20  -- not balanced                , Durable, EqpSlot EqpSlotWeapon "", Identified ]   , 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."@@ -737,10 +745,10 @@   , ifreq    = [("useful", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1-  , irarity  = [(5, 5)]-  , iverbHit = "prod"+  , irarity  = [(10, 10)]+  , iverbHit = "smack"   , iweight  = 400-  , iaspects = [AddHurtMelee $ 2 * (d 3 + 2 * dl 5)]+  , iaspects = [AddHurtMelee $ d 10 |*| 3]   , ieffects = []   , ifeature = [EqpSlot EqpSlotAddHurtMelee "", Identified]   , idesc    = "Originally used for realigning the bent or buckled edges of kitchen knives in the local bars. Now it saves lives by letting you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop."
GameDefinition/Content/ItemKindActor.hs view
@@ -17,9 +17,9 @@  actors :: [ItemKind] actors =-  [warrior, pilot, engineer, doctor, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot]+  [warrior, pilot, engineer, doctor, soldier, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot] -warrior,    pilot, engineer, doctor, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot :: ItemKind+warrior,    pilot, engineer, doctor, soldier, clerk, hairdresser, lawyer, peddler, taxCollector, eye, fastEye, nose, elbow, armadillo, gilaMonster, komodoDragon, hyena, alligator, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot :: ItemKind  -- * Hunams @@ -46,6 +46,12 @@ doctor = warrior   { iname    = "doctor" } +soldier = warrior+  { iname    = "soldier"+  , ifreq    = [("soldier", 100)]+  , ikit     = ikit warrior ++ [("starting weapon", CEqp)]+  }+ clerk = warrior   { iname    = "clerk"   , ifreq    = [("civilian", 100)] }@@ -142,7 +148,7 @@ armadillo = ItemKind   { isymbol  = 'a'   , iname    = "giant armadillo"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Brown]   , icount   = 1   , irarity  = [(1, 5)]@@ -160,7 +166,7 @@ gilaMonster = ItemKind   { isymbol  = 'g'   , iname    = "Gila monster"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(2, 5), (10, 3)]@@ -178,7 +184,7 @@ komodoDragon = ItemKind  -- bad hearing   { isymbol  = 'k'   , iname    = "Komodo dragon"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1   , irarity  = [(5, 5), (10, 7)]@@ -196,7 +202,7 @@ hyena = ItemKind   { isymbol  = 'h'   , iname    = "spotted hyena"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Red]   , icount   = 1   , irarity  = [(4, 6), (10, 6)]@@ -212,7 +218,7 @@ alligator = ItemKind   { isymbol  = 'a'   , iname    = "alligator"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Blue]   , icount   = 1   , irarity  = [(10, 8)]@@ -233,7 +239,7 @@ hornetSwarm = ItemKind   { isymbol  = 'h'   , iname    = "hornet swarm"-  , ifreq    = [("animal", 100), ("horror", 100), ("summonable animal", 100)]+  , ifreq    = [("animal", 100), ("horror", 100), ("mobile animal", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(5, 1), (10, 5)]@@ -367,7 +373,7 @@ shepherdDrone = ItemKind   { isymbol  = 'd'   , iname    = "shepherd drone"-  , ifreq    = [("robot", 100), ("horror", 100), ("summonable robot", 100)]+  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [BrRed]   , icount   = 1   , irarity  = [(1, 2)]@@ -386,7 +392,7 @@ huntingDrone = ItemKind   { isymbol  = 'd'   , iname    = "hunting drone"-  , ifreq    = [("robot", 100), ("horror", 100), ("summonable robot", 100)]+  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Green]   , icount   = 1   , irarity  = [(4, 0), (5, 1), (10, 2)]@@ -406,7 +412,7 @@   { isymbol  = 'r'   , iname    = "feral home robot"                -- TODO: name another 'deranged', tertiary imperative: survival-  , ifreq    = [("robot", 100), ("horror", 100), ("summonable robot", 100)]+  , ifreq    = [("robot", 100), ("horror", 100), ("mobile robot", 100)]   , iflavour = zipPlain [Magenta]   , icount   = 1   , irarity  = [(1, 10), (10, 6)]@@ -422,7 +428,7 @@ wasteRobot = ItemKind   { isymbol  = 'r'   , iname    = "waste disposal robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("summonable robot", 100)+  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)                , ("construction robot", 1) ]   , iflavour = zipPlain [Green]   , icount   = 1@@ -441,7 +447,7 @@ lightRobot = ItemKind   { isymbol  = 'r'   , iname    = "decoration robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("summonable robot", 100)+  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)                , ("construction robot", 1) ]   , iflavour = zipPlain [BrYellow]   , icount   = 1@@ -459,7 +465,7 @@ heavyRobot = ItemKind   { isymbol  = 'r'   , iname    = "construction robot"-  , ifreq    = [ ("robot", 100), ("horror", 100), ("summonable robot", 100)+  , ifreq    = [ ("robot", 100), ("horror", 100), ("mobile robot", 100)                , ("construction robot", 100) ]   , iflavour = zipPlain [BrRed]   , icount   = 1
GameDefinition/Content/ItemKindOrgan.hs view
@@ -10,6 +10,7 @@ import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Effect import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind @@ -24,7 +25,7 @@ speedGland :: Int -> ItemKind speedGland n = fist   { iname    = "speed gland"-  , ifreq    = [("speed gland" <+> tshow n, 100)]+  , ifreq    = [(toGroupName $ "speed gland" <+> tshow n, 100)]   , icount   = 1   , iverbHit = "spit at"   , iaspects = [AddSpeed $ intToDice n, Periodic $ intToDice n]@@ -40,7 +41,7 @@ eye :: Int -> ItemKind eye n = fist   { iname    = "eye"-  , ifreq    = [("eye" <+> tshow n, 100)]+  , ifreq    = [(toGroupName $ "eye" <+> tshow n, 100)]   , icount   = 2   , iverbHit = "glare at"   , iaspects = [AddSight (intToDice n)]@@ -204,7 +205,7 @@   , ifreq    = [("armored skin", 100)]   , icount   = 1   , iverbHit = "bash"-  , iaspects = [AddArmorMelee 33, AddArmorRanged 33]+  , iaspects = [AddArmorMelee 30, AddArmorRanged 30]   , ieffects = []   , ifeature = [Durable, Identified]   , idesc    = ""@@ -251,7 +252,7 @@   , icount   = 1   , iverbHit = "spill over"   , iaspects = [Periodic 1]-  , ieffects = [ Summon [("summonable animal", 1)] $ 1 + dl 2, RefillHP 1+  , ieffects = [ Summon [("mobile animal", 1)] $ 1 + dl 2, RefillHP 1                , Explode "waste" ]   , ifeature = [Durable, Identified]   , idesc    = ""
GameDefinition/Content/ItemKindShrapnel.hs view
@@ -10,14 +10,15 @@ import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Effect import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind  shrapnels :: [ItemKind] shrapnels =-  [fragrance, pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistWounding, distortion, waste, burningOil2, burningOil3, burningOil4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue]+  [fragrance, pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistHealing2, mistWounding, distortion, waste, burningOil2, burningOil3, burningOil4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue] -fragrance,    pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistWounding, distortion, waste, burningOil2, burningOil3, burningOil4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue :: ItemKind+fragrance,    pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistHealing2, mistWounding, distortion, waste, burningOil2, burningOil3, burningOil4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue :: ItemKind  -- * Parameterized shrapnel @@ -25,7 +26,7 @@ burningOil n = ItemKind   { isymbol  = '*'   , iname    = "burning oil"-  , ifreq    = [("burning oil" <+> tshow n, 1)]+  , ifreq    = [(toGroupName $ "burning oil" <+> tshow n, 1)]   , iflavour = zipFancy [BrYellow]   , icount   = intToDice (n * 4)   , irarity  = [(1, 1)]@@ -46,7 +47,7 @@ explosionBlast n = ItemKind   { isymbol  = '*'   , iname    = "explosion blast"-  , ifreq    = [("explosion blast" <+> tshow n, 1)]+  , ifreq    = [(toGroupName $ "explosion blast" <+> tshow n, 1)]   , iflavour = zipPlain [BrRed]   , icount   = 12  -- strong, but few, so not always hits target   , irarity  = [(1, 1)]@@ -64,14 +65,14 @@ firecracker n = ItemKind   { isymbol  = '*'   , iname    = "firecracker"-  , ifreq    = [("firecracker" <+> tshow n, 1)]+  , ifreq    = [(toGroupName $ "firecracker" <+> tshow n, 1)]   , iflavour = zipPlain [stdCol !! (n `mod` length stdCol)]   , icount   = intToDice $ 2 * n   , irarity  = [(1, 1)]   , iverbHit = "crack"   , iweight  = 1   , iaspects = [AddLight $ intToDice $ n `div` 2]-  , ieffects = [Burn 1, Explode $ "firecracker" <+> tshow (n - 1)]+  , ieffects = [Burn 1, Explode $ toGroupName $ "firecracker" <+> tshow (n - 1)]   , ifeature = [ ToThrow $ ThrowMod (n * 10) 20                , Fragile, Identified ]   , idesc    = ""@@ -129,6 +130,22 @@   , iweight  = 1   , iaspects = [AddLight 1]   , ieffects = [RefillHP 2]+  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+mistHealing2 = ItemKind+  { isymbol  = '\''+  , iname    = "mist"+  , ifreq    = [("healing mist 2", 1)]+  , iflavour = zipFancy [White]+  , icount   = 12+  , irarity  = [(1, 1)]+  , iverbHit = "revitalize"+  , iweight  = 1+  , iaspects = [AddLight 2]+  , ieffects = [RefillHP 4]   , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)                , Fragile, Identified ]   , idesc    = ""
GameDefinition/Content/ModeKind.hs view
@@ -3,11 +3,12 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | The type of kinds of game modes for Allure of the Stars.+-- | Game mode definitions. module Content.ModeKind ( cdefs ) where  import qualified Data.IntMap.Strict as IM +import Content.ModeKindPlayer import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Content.ModeKind @@ -16,302 +17,243 @@   { getSymbol = msymbol   , getName = mname   , getFreq = mfreq-  , validate = validateModeKind+  , validateSingle = validateSingleModeKind+  , validateAll = validateAllModeKind   , content =       [campaign, duel, skirmish, ambush, battle, safari, pvp, coop, defense]   } campaign,        duel, skirmish, ambush, battle, safari, pvp, coop, defense :: ModeKind  campaign = ModeKind-  { msymbol  = 'a'-  , mname    = "campaign"-  , mfreq    = [("campaign", 1)]-  , mplayers = playersCampaign-  , mcaves   = cavesCampaign-  , mdesc    = "You got stranded looting a once luxurious cruise liner and your current plan is to fight through, gathering your spoils, to the bridge at the giant spaceship's opposite end."+  { msymbol = 'a'+  , mname   = "campaign"+  , mfreq   = [("campaign", 1)]+  , mroster = rosterCampaign+  , mcaves  = cavesCampaign+  , mdesc   = "You got stranded looting a once luxurious cruise liner and your current plan is to fight through, gathering your spoils, to the bridge at the giant spaceship's opposite end."   }  duel = ModeKind-  { msymbol  = 'u'-  , mname    = "duel"-  , mfreq    = [("duel", 1)]-  , mplayers = playersDuel-  , mcaves   = cavesSkirmish-  , mdesc    = "Let's settle the argument about this noble lady outside, in the woody biosphere behind the saloon."+  { msymbol = 'u'+  , mname   = "duel"+  , mfreq   = [("duel", 1)]+  , mroster = rosterDuel+  , mcaves  = cavesSkirmish+  , mdesc   = "Let's settle the argument about this noble lady outside, in the woody biosphere behind the saloon."   }  skirmish = ModeKind-  { msymbol  = 'k'-  , mname    = "skirmish"-  , mfreq    = [("skirmish", 1)]-  , mplayers = playersSkirmish-  , 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)."+  { msymbol = 'k'+  , mname   = "skirmish"+  , 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)."   }  ambush = ModeKind-  { msymbol  = 'm'-  , mname    = "ambush"-  , mfreq    = [("ambush", 1)]-  , mplayers = playersSkirmish-  , mcaves   = cavesAmbush-  , mdesc    = "Conveniently, on the path to the Triton's spaceport, passengers can relax in a shady park."+  { msymbol = 'm'+  , mname   = "ambush"+  , mfreq   = [("ambush", 1)]+  , mroster = rosterAmbush+  , mcaves  = cavesAmbush+  , mdesc   = "Conveniently, on the path to the Triton's spaceport, passengers can relax in a shady park."   }  battle = ModeKind-  { msymbol  = 'b'-  , mname    = "battle"-  , mfreq    = [("battle", 1)]-  , mplayers = playersBattle-  , mcaves   = cavesBattle-  , mdesc    = "Not even the unexplained ruin of the largest and tightest security Neptune's moon spaceport will prevent you from claiming your prize."+  { msymbol = 'b'+  , mname   = "battle"+  , mfreq   = [("battle", 1)]+  , mroster = rosterBattle+  , mcaves  = cavesBattle+  , mdesc   = "Not even the unexplained ruin of the largest and tightest security Neptune's moon spaceport will prevent you from claiming your prize."   }  safari = ModeKind-  { msymbol  = 'f'-  , mname    = "safari"-  , mfreq    = [("safari", 1)]-  , mplayers = playersSafari-  , mcaves   = cavesSafari-  , mdesc    = "In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent (exit at the bottommost level)."+  { msymbol = 'f'+  , mname   = "safari"+  , mfreq   = [("safari", 1)]+  , mroster = rosterSafari+  , mcaves  = cavesSafari+  , mdesc   = "In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent (exit at the bottommost level)."   }  pvp = ModeKind-  { msymbol  = 'v'-  , mname    = "PvP"-  , mfreq    = [("PvP", 1)]-  , mplayers = playersPvP-  , mcaves   = cavesSkirmish-  , mdesc    = "(Not usable right now.) This is a fight to the death between two human-controlled teams."+  { msymbol = 'v'+  , mname   = "PvP"+  , mfreq   = [("PvP", 1)]+  , mroster = rosterPvP+  , mcaves  = cavesSkirmish+  , mdesc   = "(Not usable right now.) This is a fight to the death between two human-controlled teams."   }  coop = ModeKind-  { msymbol  = 'o'-  , mname    = "Coop"-  , mfreq    = [("Coop", 1)]-  , mplayers = playersCoop-  , mcaves   = cavesCampaign-  , mdesc    = "(This mode is intended solely for automated testing.)"+  { msymbol = 'o'+  , mname   = "Coop"+  , mfreq   = [("Coop", 1)]+  , mroster = rosterCoop+  , mcaves  = cavesCampaign+  , mdesc   = "(This mode is intended solely for automated testing.)"   }  defense = ModeKind-  { msymbol  = 'e'-  , mname    = "defense"-  , mfreq    = [("defense", 1)]-  , mplayers = playersDefense-  , mcaves   = cavesCampaign-  , mdesc    = "Don't let the half-witted humans derail your operation and flee, like the puny, naked, tentacled-less beasts that they are!"+  { msymbol = 'e'+  , mname   = "defense"+  , mfreq   = [("defense", 1)]+  , mroster = rosterDefense+  , mcaves  = cavesCampaign+  , mdesc   = "Don't let the half-witted humans derail your operation and flee, like the puny, naked, tentacle-less beasts that they are!"   }  -playersCampaign, playersDuel, playersSkirmish, playersBattle, playersSafari, playersPvP, playersCoop, playersDefense :: Players--playersCampaign = Players-  { playersList = [ playerHero-                  , playerAlien-                  , playerAnimal-                  , playerRobot ]-  , playersEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")-                   , ("Spacefarer Crew", "Animal Kingdom")-                   , ("Spacefarer Crew", "Robot Anarchy") ]- , playersAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                 , ("Alien Hierarchy", "Robot Anarchy")-                 , ("Robot Anarchy", "Animal Kingdom") ] }--playersDuel = Players-  { playersList = [ playerHero { playerName = "Spacefarer Crew"-                               , playerInitial = 1 }-                  , playerAntiHero { playerName = "Red Collars"-                                   , playerInitial = 1 }-                  , playerHorror ]-  , playersEnemy = [ ("Spacefarer Crew", "Red Collars")-                   , ("Spacefarer Crew", "Horror Den")-                   , ("Red Collars", "Horror Den") ]-  , playersAlly = [] }--playersSkirmish = playersDuel-  { playersList = [ playerHero {playerName = "Spacefarer Crew"}-                  , playerAntiHero {playerName = "Red Collars"}-                  , playerHorror ] }--playersBattle = Players-  { playersList = [ playerHero {playerInitial = 5}-                  , playerAlien { playerInitial = 15-                                , playerIsSpawn = False }-                  , playerAnimal { playerInitial = 5-                                 , playerIsSpawn = False }-                  , playerRobot { playerInitial = 5-                                 , playerIsSpawn = False } ]-  , playersEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")-                   , ("Spacefarer Crew", "Animal Kingdom")-                   , ("Spacefarer Crew", "Robot Anarchy") ]- , playersAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                 , ("Alien Hierarchy", "Robot Anarchy")-                 , ("Robot Anarchy", "Animal Kingdom") ] }--playersSafari = Players-  { playersList = [ playerAlien { playerName = "Alien Tourist Office"-                                , playerIsSpawn = False-                                , playerEntry = 4-                                , playerInitial = 10-                                , playerAI = False-                                , playerUI = True }-                  , playerCivilian { playerName = "Hunam Convict Pack"-                                   , playerEntry = 4 }-                  , playerAnimal { playerName =-                                     "Animal Magnificent Specimen Variety"-                                 , playerIsSpawn = False-                                 , playerEntry = 7-                                 , playerInitial = 7 }-                  , playerAnimal { playerName =-                                     "Animal Exquisite Herds and Packs"-                                 , playerIsSpawn = False-                                 , playerEntry = 10-                                 , playerInitial = 20 } ]-  , playersEnemy = [ ("Alien Tourist Office", "Hunam Convict Pack")-                   , ("Alien Tourist Office",-                      "Animal Magnificent Specimen Variety")-                   , ("Alien Tourist Office",-                      "Animal Exquisite Herds and Packs") ]-  , playersAlly = [( "Animal Magnificent Specimen Variety"-                   , "Animal Exquisite Herds and Packs" )] }--playersPvP = Players-  { playersList = [ playerHero {playerName = "Red"}-                  , playerHero {playerName = "Blue"}-                  , playerHorror ]-  , playersEnemy = [ ("Red", "Blue")-                   , ("Red", "Horror Den")-                   , ("Blue", "Horror Den") ]-  , playersAlly = [] }--playersCoop = Players-  { playersList = [ playerAntiHero { playerName = "Coral" }-                  , playerAntiHero { playerName = "Amber"-                                   , playerLeader = False }-                  , playerAntiHero { playerName = "Green" }-                  , playerAnimal { playerUI = True }-                  , playerAlien { playerName = "Alien Hierarchy" }-                  , playerAlien { playerName = "Leaderless Alien Hierarchy"-                                  , playerLeader = False }-                  , playerRobot ]-  , playersEnemy = [ ("Coral", "Alien Hierarchy")-                   , ("Amber", "Alien Hierarchy")-                   , ("Animal Kingdom", "Leaderless Alien Hierarchy") ]-  , playersAlly = [ ("Coral", "Amber")-                  , ("Coral", "Green")-                  , ("Amber", "Green")-                  , ("Green", "Animal Kingdom")-                  , ("Green", "Robot Anarchy")-                  , ("Green", "Alien Hierarchy")-                  , ("Green", "Leaderless Alien Hierarchy") ] }+rosterCampaign, rosterDuel, rosterSkirmish, rosterAmbush, rosterBattle, rosterSafari, rosterPvP, rosterCoop, rosterDefense :: Roster -playersDefense = Players-  { playersList = [ playerAlien { playerInitial = 1-                                , playerAI = False-                                , playerUI = True }-                  , playerAntiHero { playerName = "Yellow"-                                   , playerInitial = 10 }-                  , playerAnimal-                  , playerRobot ]-  , playersEnemy = [ ("Yellow", "Alien Hierarchy")-                   , ("Yellow", "Animal Kingdom")-                   , ("Yellow", "Robot Anarchy") ]-  , playersAlly = [ ("Alien Hierarchy", "Animal Kingdom")-                  , ("Alien Hierarchy", "Robot Anarchy")-                  , ("Robot Anarchy", "Animal Kingdom") ] }+rosterCampaign = Roster+  { rosterList = [ playerHero+                 , playerMonster+                 , playerAnimal+                 , playerRobot ]+  , rosterEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")+                  , ("Spacefarer Crew", "Animal Kingdom")+                  , ("Spacefarer Crew", "Robot Anarchy") ]+ , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")+                , ("Alien Hierarchy", "Robot Anarchy")+                , ("Robot Anarchy", "Animal Kingdom") ] } -playerHero, playerAntiHero, playerCivilian, playerAlien, playerAnimal, playerRobot, playerHorror :: Player+rosterDuel = Roster+  { rosterList = [ playerHero { fname = "Spacefarer Crew"+                              , fentryLevel = 3+                              , finitialActors = 1 }+                 , playerAntiHero { fname = "Red Collars"+                                  , fentryLevel = 3+                                  , finitialActors = 1 }+                 , playerHorror ]+  , rosterEnemy = [ ("Spacefarer Crew", "Red Collars")+                  , ("Spacefarer Crew", "Horror Den")+                  , ("Red Collars", "Horror Den") ]+  , rosterAlly = [] } -playerHero = Player-  { playerName = "Spacefarer Crew"-  , playerFaction = "hero"-  , playerIsSpawn = False-  , playerIsHero = True-  , playerEntry = 1-  , playerInitial = 3-  , playerLeader = True-  , playerAI = False-  , playerUI = True-  }+rosterSkirmish = rosterDuel+  { rosterList = [ playerHero { fname = "Spacefarer Crew"+                              , fentryLevel = 3 }+                 , playerAntiHero { fname = "Red Collars"+                                  , fentryLevel = 3 }+                 , playerHorror ] } -playerAntiHero = playerHero-  { playerAI = True-  , playerUI = False-  }+rosterAmbush = rosterDuel+  { rosterList = [ playerHero { fname = "Spacefarer Crew"+                              , fentryLevel = 5 }+                 , playerAntiHero { fname = "Red Collars"+                                  , fentryLevel = 5 }+                 , playerHorror {fentryLevel = 5} ] } -playerCivilian = Player-  { playerName = "Civilian Crowd"-  , playerFaction = "civilian"-  , playerIsSpawn = False-  , playerIsHero = False-  , playerEntry = 1-  , playerInitial = 3-  , playerLeader = False  -- unorganized-  , playerAI = True-  , playerUI = False-  }+rosterBattle = Roster+  { rosterList = [ playerSoldier { finitialActors = 5+                                 , fentryLevel = 5 }+                 , playerMobileMonster { finitialActors = 30+                                       , fentryLevel = 5+                                       , fneverEmpty = True }+                 , playerMobileAnimal { finitialActors = 10+                                      , fentryLevel = 5+                                      , fneverEmpty = True }+                 , playerMobileRobot { finitialActors = 10+                                     , fentryLevel = 5+                                     , fneverEmpty = True } ]+  , rosterEnemy = [ ("Armed Spacefarer Crew", "Alien Hierarchy")+                  , ("Armed Spacefarer Crew", "Animal Kingdom")+                  , ("Armed Spacefarer Crew", "Robot Anarchy") ]+  , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")+                , ("Alien Hierarchy", "Robot Anarchy")+                , ("Robot Anarchy", "Animal Kingdom") ] } -playerAlien = Player-  { playerName = "Alien Hierarchy"-  , playerFaction = "alien"-  , playerIsSpawn = True-  , playerIsHero = False-  , playerEntry = 4-  , playerInitial = 3-  , playerLeader = True-  , playerAI = True-  , playerUI = False-  }+rosterSafari = Roster+  { rosterList = [ playerAntiMonster { fname = "Alien Tourist Office"+                                     , fcanEscape = True+                                     , fneverEmpty = True+                                     -- Follow-the-guide, as tourists do.+                                     , ftactic = TFollow+                                     , fentryLevel = 4+                                     , finitialActors = 15+                                     , fleaderMode =+                                         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 = 25 } ]+  , 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" )] } -playerAnimal = Player-  { playerName = "Animal Kingdom"-  , playerFaction = "animal"-  , playerIsSpawn = True-  , playerIsHero = False-  , playerEntry = 2-  , playerInitial = 3-  , playerLeader = False-  , playerAI = True-  , playerUI = False-  }+rosterPvP = Roster+  { rosterList = [ playerHero { fname = "Red"+                              , fentryLevel = 3 }+                 , playerHero { fname = "Blue"+                              , fentryLevel = 3 }+                 , playerHorror ]+  , rosterEnemy = [ ("Red", "Blue")+                  , ("Red", "Horror Den")+                  , ("Blue", "Horror Den") ]+  , rosterAlly = [] } -playerRobot = Player-  { playerName = "Robot Anarchy"-  , playerFaction = "robot"-  , playerIsSpawn = True-  , playerIsHero = False-  , playerEntry = 3-  , playerInitial = 3-  , playerLeader = False-  , playerAI = True-  , playerUI = False-  }+rosterCoop = Roster+  { rosterList = [ playerAntiHero { fname = "Coral" }+                 , playerAntiHero { fname = "Amber"+                                  , fleaderMode = LeaderNull }+                 , playerAntiHero { fname = "Green" }+                 , playerAnimal { fhasUI = True }+                 , playerMonster { fname = "Alien Hierarchy" }+                 , playerMonster { fname = "Leaderless Alien Hierarchy"+                                 , fleaderMode = LeaderNull }+                 , playerRobot ]+  , rosterEnemy = [ ("Coral", "Alien Hierarchy")+                  , ("Amber", "Alien Hierarchy")+                  , ("Animal Kingdom", "Leaderless Alien Hierarchy") ]+  , rosterAlly = [ ("Coral", "Amber")+                 , ("Coral", "Green")+                 , ("Amber", "Green")+                 , ("Green", "Animal Kingdom")+                 , ("Green", "Robot Anarchy")+                 , ("Green", "Alien Hierarchy")+                 , ("Green", "Leaderless Alien Hierarchy") ] } -playerHorror = Player-  { playerName = "Horror Den"-  , playerFaction = "horror"-  , playerIsSpawn = False-  , playerIsHero = False-  , playerEntry = 1-  , playerInitial = 0-  , playerLeader = False-  , playerAI = True-  , playerUI = False-  }+rosterDefense = Roster+  { rosterList = [ playerAntiMonster { finitialActors = 1 }+                 , playerAntiHero { fname = "Yellow"+                                  , finitialActors = 10 }+                 , 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") ] }   cavesCampaign, cavesSkirmish, cavesAmbush, cavesBattle, cavesSafari :: Caves -cavesCampaign = IM.fromList $ [(1, ("caveRogue", Nothing))]-                              ++ zip [2..11] (repeat ("dng", Nothing))-                              ++ [(12, ("caveNoise", Just True))]+cavesCampaign = IM.fromList+                $ [(1, ("caveRogue", Nothing))]+                  ++ zip [2..11] (repeat ("campaign random", Nothing))+                  ++ [(12, ("caveNoise", Just True))]  cavesSkirmish = IM.fromList [(3, ("caveSkirmish", Nothing))]  cavesAmbush = IM.fromList [(5, ("caveAmbush", Nothing))] -cavesBattle = IM.fromList [(3, ("caveBattle", Nothing))]+cavesBattle = IM.fromList [(5, ("caveBattle", Nothing))]  cavesSafari = IM.fromList [ (4, ("caveSafari1", Nothing))                           , (7, ("caveSafari2", Nothing))
+ GameDefinition/Content/ModeKindPlayer.hs view
@@ -0,0 +1,149 @@+-- 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.+--+-- | Basic players definitions.+module Content.ModeKindPlayer+  ( playerHero, playerSoldier, playerAntiHero, playerCivilian, playerMonster+  , playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal+  , playerRobot, playerMobileRobot, playerHorror+  ) where++import qualified Data.EnumMap.Strict as EM++import Game.LambdaHack.Common.Ability+import Game.LambdaHack.Content.ModeKind++playerHero, playerSoldier, playerAntiHero, playerCivilian, playerMonster, playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal, playerRobot, playerMobileRobot, playerHorror :: Player++playerHero = Player+  { fname = "Spacefarer Crew"+  , fgroup = "hero"+  , fskillsOther = meleeAdjacent+  , fcanEscape = True+  , fneverEmpty = True+  , fhasNumbers = True+  , fhasGender = True+  , ftactic = TExplore+  , fentryLevel = 1+  , finitialActors = 3+  , fleaderMode = LeaderUI $ AutoLeader False False+  , fhasUI = True+  }++playerSoldier = playerHero+  { fname = "Armed Spacefarer Crew"+  , fgroup = "soldier"+  }++playerAntiHero = playerHero+  { fleaderMode = LeaderAI $ AutoLeader False False+  , fhasUI = False+  }++playerCivilian = Player+  { fname = "Civilian Crowd"+  , fgroup = "civilian"+  , fskillsOther = unitSkills  -- not coordinated by any leadership+  , fcanEscape = False+  , fneverEmpty = True+  , fhasNumbers = False+  , fhasGender = True+  , ftactic = TPatrol+  , fentryLevel = 1+  , finitialActors = 3+  , fleaderMode = LeaderNull  -- unorganized+  , fhasUI = False+  }++playerMonster = Player+  { fname = "Alien Hierarchy"+  , fgroup = "alien"+  , fskillsOther = unitSkills+  , fcanEscape = False+  , fneverEmpty = False+  , fhasNumbers = False+  , fhasGender = False+  , ftactic = TExplore+  , fentryLevel = 4+  , finitialActors = 3+  , fleaderMode = LeaderAI $ AutoLeader True False+  , fhasUI = False+  }++playerMobileMonster = playerMonster++playerAntiMonster = playerMonster+  { fhasUI = True+  }++playerAnimal = Player+  { fname = "Animal Kingdom"+  , fgroup = "animal"+  , fskillsOther = animalSkills+  , fcanEscape = False+  , fneverEmpty = False+  , fhasNumbers = False+  , fhasGender = False+  , ftactic = TRoam  -- can't pick up, so no point exploring+  , fentryLevel = 2+  , finitialActors = 3+  , fleaderMode = LeaderNull+  , fhasUI = False+  }++playerMobileAnimal = playerAnimal+  { fgroup = "mobile animal" }++playerRobot = Player+  { fname = "Robot Anarchy"+  , fgroup = "robot"+  , fskillsOther = robotSkills+  , fcanEscape = False+  , fneverEmpty = False+  , fhasNumbers = False+  , fhasGender = False+  , ftactic = TFollow  -- coordinated via net, follow alien leader (TODO)+  , fentryLevel = 3+  , finitialActors = 3+  , fleaderMode = LeaderNull+  , fhasUI = False+  }++playerMobileRobot = playerRobot+  { fgroup = "mobile robot" }++-- | A special player, for summoned actors that don't belong to any+-- of the main players of a given game. E.g., animals summoned during+-- a duel game between two hero players land in the horror faction.+-- In every game, either all factions for which summoning items exist+-- should be present or a horror player should be added to host them.+-- Actors that can be summoned should have "horror" in their @ifreq@ set.+playerHorror = Player+  { fname = "Horror Den"+  , fgroup = "horror"+  , fskillsOther = unitSkills+  , fcanEscape = False+  , fneverEmpty = False+  , fhasNumbers = False+  , fhasGender = False+  , ftactic = TPatrol  -- disoriented+  , fentryLevel = 3+  , finitialActors = 0+  , fleaderMode = LeaderNull+  , fhasUI = False+  }+++meleeAdjacent, _meleeAndRanged, animalSkills, robotSkills :: Skills++meleeAdjacent = EM.fromList $ zip [AbWait, AbMelee] [1, 1..]++-- Melee and reaction fire.+_meleeAndRanged = EM.fromList $ zip [AbWait, AbMelee, AbProject] [1, 1..]++animalSkills =+  EM.fromList $ zip [AbMove, AbMelee, AbAlter, AbWait, AbTrigger] [1, 1..]++robotSkills = EM.delete AbApply unitSkills
GameDefinition/Content/PlaceKind.hs view
@@ -3,7 +3,7 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Rooms, halls and passages for Allure of the Stars.+-- | Room, hall and passage definitions. module Content.PlaceKind ( cdefs ) where  import Game.LambdaHack.Common.ContentDef@@ -14,17 +14,18 @@   { getSymbol = psymbol   , getName = pname   , getFreq = pfreq-  , validate = validatePlaceKind+  , validateSingle = validateSinglePlaceKind+  , validateAll = validateAllPlaceKind   , content =-      [rect, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillarC, pillar3, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells]+      [rect, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells]   }-rect,        ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillarC, pillar3, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind+rect,        ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind  rect = PlaceKind  -- Valid for any nonempty area, hence low frequency.   { psymbol  = 'r'   , pname    = "room"-  , pfreq    = [("rogue", 100), ("ambush", 8)]-  , prarity  = [(1, 1)]+  , pfreq    = [("rogue", 70), ("ambush", 8), ("noise", 40)]+  , prarity  = [(1, 10), (10, 8)]   , pcover   = CStretch   , pfence   = FWall   , ptopLeft = ["."]@@ -33,8 +34,8 @@ ruin = PlaceKind   { psymbol  = 'R'   , pname    = "ruin"-  , pfreq    = [("ambush", 17), ("battle", 100)]-  , prarity  = [(1, 1)]+  , pfreq    = [("ambush", 17), ("battle", 100), ("noise", 20)]+  , prarity  = [(1, 10), (10, 20)]   , pcover   = CStretch   , pfence   = FWall   , ptopLeft = ["X"]@@ -44,7 +45,7 @@   { psymbol  = 'c'   , pname    = "collapsed cavern"   , pfreq    = [("noise", 1)]-  , prarity  = [(1, 1)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FNone   , ptopLeft = ["#"]@@ -72,27 +73,38 @@ pillar = PlaceKind   { psymbol  = 'p'   , pname    = "pillar room"-  , pfreq    = [("rogue", 1000)]  -- larger rooms require support pillars-  , prarity  = [(1, 1)]+  , pfreq    = [("rogue", 1000), ("noise", 50)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FWall+  -- Larger rooms require support pillars.   , ptopLeft = [ "...."-               , ".#.."+               , ".O.."                , "...."                , "...."                ]   , poverride = []   }-pillarC = pillar-  { ptopLeft = [ ".#.."+pillar2 = pillar+  { prarity  = [(1, 5), (10, 5)]+  , ptopLeft = [ ".#.."                , "#..."                , "...."                , "...."                ]   } pillar3 = pillar-  { ptopLeft = [ "&.#."+  { prarity  = [(1, 5), (10, 5)]+  , ptopLeft = [ "#..."+               , "..#."+               , ".#.."                , "...."+               ]+  }+pillar4 = pillar+  { prarity  = [(10, 7)]+  , ptopLeft = [ "&.#."+               , "...."                , "#..."                , "...."                ]@@ -100,8 +112,8 @@ colonnade = PlaceKind   { psymbol  = 'c'   , pname    = "colonnade"-  , pfreq    = [("rogue", 60)]-  , prarity  = [(1, 1)]+  , pfreq    = [("rogue", 70), ("noise", 2000)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CAlternate   , pfence   = FFloor   , ptopLeft = [ ".#"@@ -109,8 +121,28 @@                ]   , poverride = []   }+colonnade2 = colonnade+  { prarity  = [(1, 2), (10, 4)]+  , pfence   = FGround+  , ptopLeft = [ ".."+               , ".O"+               ]+  }+colonnade3 = colonnade+  { prarity  = [(1, 4), (10, 6)]+  , ptopLeft = [ "#.."+               , "..#"+               ]+  }+colonnade4 = colonnade+  { ptopLeft = [ "#."+               , ".."+               , ".#"+               ]+  } colonnadeWide = colonnade-  { pfence   = FWall+  { prarity  = [(1, 3), (10, 3)]+  , pfence   = FWall   , ptopLeft = [ ".."                , ".#"                ]@@ -119,7 +151,7 @@   { psymbol  = 'l'   , pname    = "lamp post"   , pfreq    = [("ambush", 30), ("battle", 10)]-  , prarity  = [(1, 1)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CVerbatim   , pfence   = FNone   , ptopLeft = [ "X.X"@@ -154,7 +186,7 @@   { psymbol  = 't'   , pname    = "tree shade"   , pfreq    = [("skirmish", 100)]-  , prarity  = [(1, 1)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CVerbatim   , pfence   = FNone   , ptopLeft = [ "sss"@@ -179,21 +211,20 @@   { psymbol  = 'o'   , pname    = "oval room"   , pfreq    = [("rogue", 1000)]-  , prarity  = [(1, 1)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FWall-  , ptopLeft = [ "####.."-               , "##...."-               , "#....."-               , "#....."-               , "......"-               , "......"+  , ptopLeft = [ "####."+               , "##..."+               , "#...."+               , "#...."+               , "....."                ]   , poverride = []   } ovalFloor = oval  -- Without outer solid fence, visible from outside.   { pfreq    = [("rogue", 10000)]-  , pfence   = FFloor+  , pfence   = FGround   , ptopLeft = [ "XXXX+#"                , "XX###."                , "X##..."@@ -203,7 +234,8 @@                ]   } ovalSquare = ovalFloor-  { ptopLeft = [ "X###+"+  { pfreq    = [("rogue", 3000)]+  , ptopLeft = [ "X###+"                , "##..."                , "#...."                , "#...."@@ -214,7 +246,7 @@   { psymbol  = 'm'   , pname    = "maze"   , pfreq    = [("rogue", 20)]-  , prarity  = [(1, 1)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CStretch   , pfence   = FNone   , ptopLeft = [ "#.#.##"@@ -269,8 +301,8 @@ cells = PlaceKind   { psymbol  = '#'   , pname    = "cells"-  , pfreq    = [("rogue", 30)]-  , prarity  = [(1, 1)]+  , pfreq    = [("rogue", 100), ("noise", 100)]+  , prarity  = [(1, 10), (10, 10)]   , pcover   = CReflect   , pfence   = FWall   , ptopLeft = [ "..#"
GameDefinition/Content/RuleKind.hs view
@@ -4,7 +4,7 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Game rules and assorted game setup data for Allure of the Stars.+-- | Game rules and assorted game setup data. module Content.RuleKind ( cdefs ) where  import Language.Haskell.TH.Syntax@@ -21,7 +21,8 @@   { getSymbol = rsymbol   , getName = rname   , getFreq = rfreq-  , validate = validateRuleKind+  , validateSingle = validateSingleRuleKind+  , validateAll = validateAllRuleKind   , content =       [standard]   }@@ -33,7 +34,7 @@   , rfreq          = [("standard", 100)]   -- Check whether one position is accessible from another.   -- Precondition: the two positions are next to each other-  -- and the target tile is walkable. +  -- and the target tile is walkable.   -- TODO: in the future check flying for chasms, swimming for water, etc.   , raccessible    = Nothing   , raccessibleDoor = Nothing@@ -70,9 +71,10 @@       lift x)   , rfirstDeathEnds = False   , rfovMode = Digital-  , rsaveBkpClips = 500+  , rwriteSaveClips = 500   , rleadLevelClips = 100   , rscoresFile = "scores"   , rsavePrefix = "save"   , rsharedStash = True+  , rnearby = 10   }
GameDefinition/Content/TileKind.hs view
@@ -3,18 +3,18 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Terrain tiles for Allure of the Stars.+-- | Terrain tile definitions. module Content.TileKind ( cdefs ) where  import Control.Arrow (first) import Data.Maybe-import Data.Text (Text) import qualified Data.Text as T  import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.ContentDef import qualified Game.LambdaHack.Common.Effect as Effect import Game.LambdaHack.Common.Feature+import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.TileKind @@ -23,7 +23,8 @@   { getSymbol = tsymbol   , getName = tname   , getFreq = tfreq-  , validate = validateTileKind+  , validateSingle = validateSingleTileKind+  , validateAll = validateAllTileKind   , content =       [wall, wallCache, hardRock, doorlessWall, oriel, pillar, lampPost, burningBush, bush, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorArenaShade, floorRedLit, floorBlueLit, floorGreenLit]       ++ map makeDarkColor [floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit]@@ -255,15 +256,16 @@   makeDark :: TileKind -> TileKind-makeDark k = let darkText :: Text -> Text-                 darkText t = maybe t (<> "Dark") $ T.stripSuffix "Lit" t+makeDark k = let darkText :: GroupName -> GroupName+                 darkText t = maybe t (toGroupName . (<> "Dark"))+                              $ T.stripSuffix "Lit" $ tshow t                  darkFrequency = map (first darkText) $ tfreq k                  darkFeat (OpenTo t) = Just $ OpenTo $ darkText t                  darkFeat (CloseTo t) = Just $ CloseTo $ darkText t                  darkFeat (ChangeTo t) = Just $ ChangeTo $ darkText t                  darkFeat (HideAs t) = Just $ HideAs $ darkText t                  darkFeat (RevealAs t) = Just $ RevealAs $ darkText t-                 darkFeat OftenItem = Nothing+                 darkFeat OftenItem = Nothing  -- items not common in the dark                  darkFeat feat = Just $ feat              in k { tfreq    = darkFrequency                   , tfeature = Dark : mapMaybe darkFeat (tfeature k)
GameDefinition/PLAYING.md view
@@ -1,7 +1,7 @@ Playing Allure of the Stars =========================== -Your party of trusted crew-members is set to test their fortune+Your party of trusted crew-members is about to test their fortune by exploring an abandoned Solar System passenger cruiser. You are going to set up ambushes for it's feral denizens, hide in shadows, cover tracks, bump into unspeakable horrors, hidden mechanisms@@ -173,6 +173,7 @@                 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)  Assorted remaining keys and commands follow.
GameDefinition/TieKnot.hs view
@@ -9,7 +9,6 @@  import qualified Client.UI.Content.KeyKind as Content.KeyKind import qualified Content.CaveKind-import qualified Content.FactionKind import qualified Content.ItemKind import qualified Content.ModeKind import qualified Content.PlaceKind@@ -28,7 +27,6 @@   let -- Common content operations, created from content definitions.       copsServer = Kind.COps         { cocave    = Kind.createOps Content.CaveKind.cdefs-        , cofaction = Kind.createOps Content.FactionKind.cdefs         , coitem    = Kind.createOps Content.ItemKind.cdefs         , comode    = Kind.createOps Content.ModeKind.cdefs         , coplace   = Kind.createOps Content.PlaceKind.cdefs
GameDefinition/scores view

binary file changed (578 → 335 bytes)

− GameDefinition/screenshot.png

binary file changed (16303 → absent bytes)

Makefile view
@@ -256,6 +256,14 @@ 	dist/build/Allure/Allure --dbgMsgSer --noMore --savePrefix defense --dumpInitRngs --automateAll --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log  +build-binary:+	cabal configure --prefix=/usr/local+	cabal build Allure+	rm -rf /tmp/Allure+	cabal copy --destdir=/tmp/Allure+	tar -czf /tmp/Allure.tar.gz -C /tmp --exclude=Allure/usr/local/lib --exclude=Allure/usr/local/share/doc Allure++ # The rest of the makefile is unmaintained at the moment.  default : dist/setup-config
README.md view
@@ -1,17 +1,16 @@-Allure of the Stars [![Build Status](https://secure.travis-ci.org/AllureOfTheStars/Allure.png)](http://travis-ci.org/AllureOfTheStars/Allure)[![Build Status](https://drone.io/github.com/AllureOfTheStars/Allure/status.png)](https://drone.io/github.com/AllureOfTheStars/Allure/latest)+Allure of the Stars [![Build Status](https://travis-ci.org/AllureOfTheStars/Allure.svg?branch=master)](https://travis-ci.org/AllureOfTheStars/Allure)[![Build Status](https://drone.io/github.com/AllureOfTheStars/Allure/status.png)](https://drone.io/github.com/AllureOfTheStars/Allure/latest) =================== -This is an alpha release of [Allure of the Stars] [8],-a near-future Sci-Fi [roguelike] [2] and tactical squad game.-Have a look at [PLAYING.md](GameDefinition/PLAYING.md) or jump straight-into the fray.+[Allure of the Stars] [8] is a near-future Sci-Fi [roguelike] [2]+and tactical squad game. Have a look at [PLAYING.md](GameDefinition/PLAYING.md)+or jump straight into the fray.  ![gameplay screenshot](GameDefinition/screenshot.png?raw=true) -Long-term goals of the project are high replayability and auto-balancing-through procedural content generation and persistent content-modification based on player behaviour. The game is written in [Haskell] [1]-using the [LambdaHack] [5] roguelike game engine.+The game is written in [Haskell] [1] using the [LambdaHack] [5]+roguelike game engine. Long-term goals of the project are high+replayability and auto-balancing through procedural content generation+and persistent content modification based on player behaviour.   Compilation and installation@@ -20,15 +19,17 @@ 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. The latest official-version of the game can be downloaded automatically by Cabal-from [Hackage] [4] as follows+version of the game can be downloaded, compiled and installed+automatically by Cabal from [Hackage] [4] as follows +    cabal install gtk2hs-buildtools     cabal install Allure  For a newer version, install a matching LambdaHack library snapshot from a development branch, download the game source from [github] [3] and run `cabal install` from the main directory. +Some pre-compiled game binaries may be available from the [releases] [9] page.  Compatibility notes -------------------@@ -102,3 +103,4 @@ [6]: https://github.com/AllureOfTheStars/Allure/wiki [7]: http://www.haskell.org/platform [8]: http://allureofthestars.com+[9]: https://github.com/AllureOfTheStars/Allure/releases