Allure 0.7.1.0 → 0.8.0.0
raw patch · 23 files changed
+3280/−2474 lines, 23 filesdep +enummapsetdep −enummapset-thdep ~LambdaHackdep ~asyncdep ~random
Dependencies added: enummapset
Dependencies removed: enummapset-th
Dependency ranges changed: LambdaHack, async, random
Files
- Allure.cabal +26/−25
- CHANGELOG.md +41/−0
- GameDefinition/Client/UI/Content/KeyKind.hs +114/−100
- GameDefinition/Content/CaveKind.hs +74/−65
- GameDefinition/Content/ItemKind.hs +1528/−1304
- GameDefinition/Content/ItemKindActor.hs +114/−102
- GameDefinition/Content/ItemKindBlast.hs +353/−205
- GameDefinition/Content/ItemKindEmbed.hs +269/−146
- GameDefinition/Content/ItemKindOrgan.hs +108/−69
- GameDefinition/Content/ItemKindTemporary.hs +45/−55
- GameDefinition/Content/ModeKind.hs +44/−18
- GameDefinition/Content/ModeKindPlayer.hs +6/−7
- GameDefinition/Content/PlaceKind.hs +51/−62
- GameDefinition/Content/RuleKind.hs +33/−20
- GameDefinition/Content/TileKind.hs +171/−92
- GameDefinition/InGameHelp.txt +48/−44
- GameDefinition/Main.hs +18/−6
- GameDefinition/MainMenu.ascii +60/−24
- GameDefinition/PLAYING.md +62/−49
- GameDefinition/TieKnot.hs +24/−15
- GameDefinition/config.ui.default +7/−4
- Makefile +58/−22
- README.md +26/−40
Allure.cabal view
@@ -5,31 +5,34 @@ -- PVP summary:+-+------- breaking API changes -- | | +----- minor or non-breaking API additions -- | | | +--- code changes with no API change-version: 0.7.1.0+version: 0.8.0.0 synopsis: Near-future Sci-Fi roguelike and tactical squad game-description: Allure of the Stars- is a near-future Sci-Fi roguelike and tactical squad game.- Try out the browser version of Allure of the Stars at+description: Allure of the Stars is a near-future Sci-Fi roguelike+ and tactical squad game. Binaries and the game manual+ are available at the homepage, where you can also+ try the game out in the browser: <http://allureofthestars.com/play> (It runs fastest on Chrome. Keyboard commands and savefiles are supported only on recent enough versions of browsers. Mouse should work everywhere.) .- <<https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/crawl-0.6.0.0-8x8xb.png>>+ Not a single picture in this game. You have to imagine everything+ yourself, like with a book (a grown-up book, without pictures).+ Once you learn to imagine things, though, you can keep exploring+ and mastering the world and making up stories for a long time. .+ The game is written in Haskell using the LambdaHack roguelike+ game engine <http://hackage.haskell.org/package/LambdaHack>. Please see the changelog file for recent improvements and the issue tracker for short-term plans. Long term goals are high replayability and auto-balancing through procedural content generation and persistent content modification based on player behaviour. Contributions are welcome.- .- The game is written using the LambdaHack roguelike game engine- available at <http://hackage.haskell.org/package/LambdaHack>. homepage: http://allureofthestars.com bug-reports: http://github.com/AllureOfTheStars/Allure/issues license: AGPL-3 license-file: LICENSE-tested-with: GHC==8.0.2, GHC==8.2.1, GHC==8.2.2+tested-with: GHC==8.0.2, GHC==8.2.2, GHC==8.4.2 data-files: GameDefinition/config.ui.default, GameDefinition/fonts/16x16x.fon, GameDefinition/fonts/8x8xb.fon,@@ -37,13 +40,14 @@ GameDefinition/fonts/LICENSE.16x16x, GameDefinition/fonts/Fix15Mono-Bold.woff, GameDefinition/fonts/LICENSE.Fix15Mono-Bold,- GameDefinition/PLAYING.md, GameDefinition/InGameHelp.txt, README.md, CHANGELOG.md, LICENSE, CREDITS-extra-source-files: GameDefinition/MainMenu.ascii, Makefile+extra-source-files: GameDefinition/MainMenu.ascii,+ GameDefinition/PLAYING.md,+ Makefile author: Andres Loeh, Mikolaj Konarski and others maintainer: Mikolaj Konarski <mikolaj.konarski@funktory.com> category: Game@@ -72,13 +76,13 @@ Content.TileKind, TieKnot, Paths_Allure- build-depends: LambdaHack >= 0.7.1.0 && < 0.7.2.0,+ build-depends: LambdaHack >= 0.8.0.0 && < 0.8.1.0, template-haskell >= 2.6, async >= 2, base >= 4.9 && < 99, containers >= 0.5.3.0,- enummapset-th >= 0.6.0.0,+ enummapset >= 0.5.2.2, filepath >= 1.2.0.1, optparse-applicative >= 0.13, random >= 1.1,@@ -87,26 +91,23 @@ default-language: Haskell2010 default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings BangPatterns, RecordWildCards, NamedFieldPuns, MultiWayIf,- LambdaCase, StrictData+ LambdaCase, StrictData, CPP other-extensions: TemplateHaskell ghc-options: -Wall -Wcompat -Worphans -Wincomplete-uni-patterns -Wincomplete-record-updates -Wimplicit-prelude -Wmissing-home-modules -Widentities -Wredundant-constraints ghc-options: -Wall-missed-specialisations ghc-options: -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively ghc-options: -threaded -rtsopts+-- Minimize median lag at the cost of occasional bigger GC lag,+-- which fortunately sometimes fits into idle time between turns):+ ghc-options: -with-rtsopts=-A99m if impl(ghcjs) { -- This is the largest GHCJS_BUSY_YIELD value that does not cause dropped frames -- on my machine with default --maxFps. cpp-options: -DGHCJS_BUSY_YIELD=50--- Minimize median lag at the cost of occasional huge lag when GC kicks in--- (and some of the GCs fit into idle time, while the player ponders--- or game is being saved):- ghc-options: "-with-rtsopts=-A99m"+ cpp-options: -DUSE_JSFILE } else { build-depends: zlib >= 0.5.3.1--- The -A options makes it slightly faster, especially with short sessions:- ghc-options: "-with-rtsopts=-A99m -K1000K"--- TODO: get back to -K1K when I can use pretty-1.1.3.4 (TH depends on an old one), that is, when I can drop GHC 8.0.2 and older } test-suite test@@ -133,7 +134,7 @@ base >= 4.9 && < 99, containers >= 0.5.3.0,- enummapset-th >= 0.6.0.0,+ enummapset >= 0.5.2.2, filepath >= 1.2.0.1, optparse-applicative >= 0.13, random >= 1.1,@@ -147,14 +148,14 @@ ghc-options: -Wall -Wcompat -Worphans -Wincomplete-uni-patterns -Wincomplete-record-updates -Wimplicit-prelude -Wmissing-home-modules -Widentities -Wredundant-constraints ghc-options: -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively ghc-options: -threaded -rtsopts+-- Minimize median lag at the cost of occasional bigger GC lag,+-- which fortunately sometimes fits into idle time between turns):+ ghc-options: -with-rtsopts=-A99m if impl(ghcjs) { -- This is the largest GHCJS_BUSY_YIELD value that does not cause dropped frames -- on my machine with default --maxFps. cpp-options: -DGHCJS_BUSY_YIELD=50- ghc-options: "-with-rtsopts=-A99m" } else { build-depends: zlib >= 0.5.3.1- ghc-options: "-with-rtsopts=-A99m -K1000K"--- TODO: get back to -K1K when I can use pretty-1.1.3.4 (TH depends on an old one), that is, when I can drop GHC 8.0.2 and older }
CHANGELOG.md view
@@ -1,3 +1,44 @@+## [v0.8.0.0, aka 'Explosive dashboard'](https://github.com/AllureOfTheStars/Allure/compare/v0.7.1.0...v0.8.0.0)++- display initial bits of backstory as a help screen and in-game+- rework greying out menu items and permitting item application and projection+- rework history collection; merge message repetitions more aggressively+- display HP in red when below (configurable) warning threshold+- tweak AI: actors remember they are fleeing; better leader choice, etc.+- add to content specialized explosive projectiles; tune the effects+- calculate loot score component based on fraction of dungeon loot collected+- don't hardwire item price, but let it be specified in content+- let all valuables glitter in the dark to avoid complete level exploration+- teach AI to cure ailments and shake off impressions+- rework detection effects; add detection of items embedded in tiles+- automatically identify stolen items that only have minor effects+- let projectiles hit each other if fragile and substantial enough+- rework item kind identification code; change the way it's defined in content+- make more item kinds (including some traps) secret+- protect paralyzed actors with a stasis condition to avoid infinite paralysis+- implement dumping screenshots in SDL2 and create animated GIFs in Makefile+- generate most common consumables less often, but in depth-scaled bunches+- make pushed actors alter tiles and trigger effects of embedded items+- validate and cross-validate more content; reduce content creation boilerplate+- make summoning more varied and prevent chain-summoning+- add many ways to conditionally sequence effects+- create large, merged rooms more often+- generalize the terrain altering player command (C-c, mouse)+- let RET, SPACE and ESC clear pending messages, if any+- add dashboard with links to all menus and info screens+- scale some organ and trap power with level depth+- simplify level-scaled dice roll semantics+- change scaled dice notation 'dl' to 'dL' for readability in-game+- rebalance items and decrease dice variety to unclutter backpack+- colour-code beneficial and harmful conditions in menu and in HUD+- display item lore (also for organs, embedded items, explosions, etc.)+- display embedded item descriptions as if they were tile descriptions+- tweak blast visuals, lower particle counts, beautify their spread+- tweak projectile visuals, e.g., display an extra frame when projectile dies+- add intro screen and work on other ways to convey story+- simplify a lot of code, including a bit of game rules+- fix some bugs, tweak content, speed up some AI bottlenecks+ ## [v0.7.1.0, aka 'Ancient troubles'](https://github.com/AllureOfTheStars/Allure/compare/v0.7.0.0...v0.7.1.0) - add amazing cave and item (actor, blast, organ) descriptions
GameDefinition/Client/UI/Content/KeyKind.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,6 +15,7 @@ import Game.LambdaHack.Common.Prelude import Game.LambdaHack.Client.UI.Content.KeyKind+import Game.LambdaHack.Client.UI.HandleHelperM (ppSLore) import Game.LambdaHack.Client.UI.HumanCmd import Game.LambdaHack.Common.Misc import qualified Game.LambdaHack.Content.TileKind as TK@@ -32,34 +33,71 @@ -- Remember to put commands that show information (e.g., enter aiming -- mode) first. - -- Main Menu+ -- Main menu [ ("e", ([CmdMainMenu], "enter challenges menu>", ChallengesMenu)) , ("s", ([CmdMainMenu], "start new game", GameRestart)) , ("x", ([CmdMainMenu], "exit to desktop", GameExit)) , ("v", ([CmdMainMenu], "visit settings menu>", SettingsMenu)) , ("a", ([CmdMainMenu], "automate faction", Automate))- , ("?", ([CmdMainMenu], "see command Help", Help))+ , ("?", ([CmdMainMenu], "see command help", Help))+ , ("F12", ([CmdMainMenu], "go to dashboard", Dashboard)) , ("Escape", ([CmdMainMenu], "back to playing", Cancel)) - -- Item use, 1st part+ -- Minimal command set, in the desired presentation order , ("g", addCmdCategory CmdMinimal $ grabItems "grab item(s)")+ -- actually it's not necessary, ground items menu suffices+ , ("Escape", ( [CmdMinimal, CmdAim]+ , "cancel aiming/open main menu"+ , ByAimMode { exploration = ExecuteIfClear MainMenu+ , aiming = Cancel } ))+ , ("Return", ( [CmdMinimal, CmdAim]+ , "accept target/open dashboard"+ , ByAimMode { exploration = ExecuteIfClear Dashboard+ , aiming = Accept } ))+ , ("space", ( [CmdMinimal, CmdMeta]+ , "clear messages/display history"+ , ExecuteIfClear History ))+ -- not necessary, because messages available from dashboard+ , ("BackTab", ( [CmdMinimal, CmdMove]+ , "cycle among all party members"+ , MemberBack ))+ , ("KP_Multiply", ( [CmdMinimal, CmdAim]+ , "cycle x-hair among enemies"+ , AimEnemy ))+ -- not necessary, because flinging from item menu enters aiming mode+ , ("C-c", ([CmdMinimal, CmdMove], "open or close or alter", AlterDir []))+ , ("+", ([CmdMinimal, CmdAim], "swerve the aiming line", EpsIncr True))++ -- Item menu, first part of item use commands , ("comma", grabItems "") , ("d", dropItems "drop item(s)") , ("period", dropItems "") , ("f", addCmdCategory CmdItemMenu $ projectA flingTs) , ("C-f", addCmdCategory CmdItemMenu $ replaceDesc "fling without aiming" $ projectI flingTs)- , ("a", addCmdCategory CmdItemMenu $ applyI [ApplyItem- { verb = "apply"- , object = "consumable"- , symbol = ' ' }])+ , ("a", addCmdCategory CmdItemMenu $ applyI [TriggerItem+ { tiverb = "apply"+ , tiobject = "consumable"+ , tisymbols = "!?-" }]) , ("C-a", addCmdCategory CmdItemMenu- $ replaceDesc "apply and keep choice" $ applyIK [ApplyItem- { verb = "apply"- , object = "consumable"- , symbol = ' ' }])+ $ replaceDesc "apply and keep choice" $ applyIK [TriggerItem+ { tiverb = "apply"+ , tiobject = "consumable"+ , tisymbols = "!?-" }])+ , ("p", moveItemTriple [CGround, CEqp, CSha] CInv+ "item" False)+ , ("e", moveItemTriple [CGround, CInv, CSha] CEqp+ "item" False)+ , ("s", moveItemTriple [CGround, CInv, CEqp] CSha+ "and share item" False) -- Terrain exploration and alteration+ , ("Tab", ( [CmdMove]+ , "cycle among party members on the level"+ , MemberCycle ))+ , ("c", ([CmdMove], descTs closeDoorTriggers, AlterDir closeDoorTriggers))+ , ("=", ( [CmdMove], "select (or deselect) party member", SelectActor) )+ , ("_", ([CmdMove], "deselect (or select) all on the level", SelectNone)) , ("semicolon", ( [CmdMove] , "go to x-hair for 25 steps" , Macro ["C-semicolon", "C-/", "C-V"] ))@@ -75,73 +113,71 @@ , ("R", ([CmdMove], "rest (wait 25 times)", Macro ["KP_5", "C-V"])) , ("C-R", ( [CmdMove], "lurk (wait 0.1 turns 100 times)" , Macro ["C-KP_5", "V"] ))- , ("c", ( [CmdMove, CmdMinimal]- , descTs closeDoorTriggers- , AlterDir closeDoorTriggers )) -- Item use, continued- , ("^", ( [CmdItem], "sort items by kind and stats", SortSlots))- , ("p", moveItemTriple [CGround, CEqp, CSha] CInv- "item" False)- , ("e", moveItemTriple [CGround, CInv, CSha] CEqp- "item" False)- , ("s", moveItemTriple [CGround, CInv, CEqp] CSha- "and share item" False)- , ("P", ( [CmdMinimal, CmdItem]+ , ("^", ( [CmdItem], "sort items by ownership, kind and stats", SortSlots))+ , ("P", ( [CmdItem, CmdDashboard] , "manage item pack of the leader" , ChooseItemMenu (MStore CInv) ))- , ("G", ( [CmdItem]+ , ("G", ( [CmdItem, CmdDashboard] , "manage items on the ground" , ChooseItemMenu (MStore CGround) ))- , ("E", ( [CmdItem]+ , ("E", ( [CmdItem, CmdDashboard] , "manage equipment of the leader" , ChooseItemMenu (MStore CEqp) ))- , ("S", ( [CmdItem]+ , ("S", ( [CmdItem, CmdDashboard] , "manage the shared party stash" , ChooseItemMenu (MStore CSha) ))- , ("A", ( [CmdItem]+ , ("A", ( [CmdItem, CmdDashboard] , "manage all owned items" , ChooseItemMenu MOwned ))- , ("@", ( [CmdItem]+ , ("@", ( [CmdItem, CmdDashboard] , "describe organs of the leader"- , ChooseItemMenu (MStore COrgan) ))- , ("#", ( [CmdItem]+ , ChooseItemMenu MOrgans ))+ , ("#", ( [CmdItem, CmdDashboard] , "show stat summary of the leader" , ChooseItemMenu MStats )) , ("~", ( [CmdItem] , "display known lore"- , ChooseItemMenu MLoreItem ))- , ("q", addCmdCategory CmdItem $ applyI [ApplyItem- { verb = "quaff"- , object = "drink"- , symbol = '!' }])- , ("r", addCmdCategory CmdItem $ applyI [ApplyItem- { verb = "read"- , object = "chip"- , symbol = '?' }])+ , ChooseItemMenu (MLore SItem) ))+ , ("q", addCmdCategory CmdItem $ applyI [TriggerItem+ { tiverb = "quaff"+ , tiobject = "liquid"+ , tisymbols = "!" }])+ , ("r", addCmdCategory CmdItem $ applyI [TriggerItem+ { tiverb = "read"+ , tiobject = "chip"+ , tisymbols = "?" }]) , ("t", addCmdCategory CmdItem $ projectA- [ ApplyItem { verb = "throw"- , object = "missile"- , symbol = '{' }- , ApplyItem { verb = "throw"- , object = "missile"- , symbol = '}' } ])--- , ("z", projectA [ApplyItem { verb = "zap"--- , object = "wand"--- , symbol = '-' }])+ [ TriggerItem { tiverb = "throw"+ , tiobject = "missile"+ , tisymbols = "{" }+ , TriggerItem { tiverb = "throw"+ , tiobject = "missile"+ , tisymbols = "}" } ])+-- , ("z", projectA [TriggerItem { tiverb = "zap"+-- , tiobject = "wand"+-- , tisymbols = "-" }]) + -- Dashboard, in addition to commands marked above+ , ("safeD0", ([CmdInternal, CmdDashboard], "", Cancel)) -- blank line+ ]+ +++ map (\(k, slore) -> ("safeD" ++ show (k :: Int)+ , ( [CmdInternal, CmdDashboard]+ , "display" <+> ppSLore slore <+> "lore"+ , ChooseItemMenu (MLore slore) )))+ (zip [1..] [minBound..maxBound])+ +++ [ ("safeD99", ([CmdInternal, CmdDashboard], "", Cancel)) -- blank line+ -- Aiming- , ("KP_Multiply", ( [CmdAim, CmdMinimal]- , "cycle x-hair among enemies", AimEnemy ))- -- not really minimal, because flinging from Item Menu enters aiming- -- mode, first screen mentions aiming mode not in fling context , ("!", ([CmdAim], "", AimEnemy)) , ("KP_Divide", ([CmdAim], "cycle x-hair among items", AimItem)) , ("/", ([CmdAim], "", AimItem))- , ("\\", ([CmdAim], "cycle aiming modes", AimFloor))- , ("+", ([CmdAim, CmdMinimal], "swerve the aiming line", EpsIncr True)) , ("-", ([CmdAim], "unswerve the aiming line", EpsIncr False))+ , ("\\", ([CmdAim], "cycle aiming modes", AimFloor)) , ("C-?", ( [CmdAim] , "set x-hair to nearest unknown spot" , XhairUnknown ))@@ -152,52 +188,40 @@ , "set x-hair to nearest upstairs" , XhairStair True )) , ("C-}", ( [CmdAim]- , "set x-hair to nearest downstairs"+ , "set x-hair to nearest dnstairs" , XhairStair False ))- , ("<", ([CmdAim], "move aiming one level higher" , AimAscend 1))- , ("C-<", ( [CmdNoHelp], "move aiming 10 levels higher"+ , ("<", ([CmdAim], "move aiming one level up" , AimAscend 1))+ , ("C-<", ( [CmdNoHelp], "move aiming 10 levels up" , AimAscend 10) )- , (">", ([CmdAim], "move aiming one level lower", AimAscend (-1)))- , ("C->", ( [CmdNoHelp], "move aiming 10 levels lower"+ , (">", ([CmdAim], "move aiming one level down", AimAscend (-1)))+ -- 'lower' would be misleading in some games, just as 'deeper'+ , ("C->", ( [CmdNoHelp], "move aiming 10 levels down" , AimAscend (-10)) ) , ("BackSpace" , ( [CmdAim] , "clear chosen item and target" , ComposeUnlessError ItemClear TgtClear ))- , ("Escape", ( [CmdAim, CmdMinimal]- , "cancel aiming/open Main Menu"- , ByAimMode {exploration = MainMenu, aiming = Cancel} ))- , ("Return", ( [CmdAim, CmdMinimal]- , "accept target/open Help"- , ByAimMode {exploration = Help, aiming = Accept} )) -- Assorted- , ("space", ( [CmdMinimal, CmdMeta]- , "clear messages/display history", Clear ))- , ("?", ([CmdMeta], "display Help", Help))- , ("F1", ([CmdMeta], "", Help))- , ("Tab", ( [CmdMeta]- , "cycle among party members on the level"- , MemberCycle ))- , ("BackTab", ( [CmdMeta, CmdMinimal]- , "cycle among all party members"- , MemberBack ))- , ("=", ( [CmdMinimal, CmdMeta]- , "select (or deselect) party member", SelectActor) )- , ("_", ([CmdMeta], "deselect (or select) all on the level", SelectNone))+ , ("F12", ([CmdMeta], "open dashboard", Dashboard))+ , ("?", ([CmdMeta], "display help", Hint))+ , ("F1", ([CmdMeta], "", Hint)) , ("v", ([CmdMeta], "voice again the recorded commands", Repeat 1)) , ("V", repeatTriple 100) , ("C-v", repeatTriple 1000) , ("C-V", repeatTriple 25) , ("'", ([CmdMeta], "start recording commands", Record))+ , ("C-P", ([CmdMeta], "print screen", PrintScreen)) + -- Dashboard, in addition to commands marked above+ , ("safeD100", ([CmdInternal, CmdDashboard], "display help", Help))+ , ("safeD101", ([CmdInternal, CmdDashboard], "display history", History))+ -- Mouse , ("LeftButtonRelease", mouseLMB) , ("RightButtonRelease", mouseRMB) , ("C-LeftButtonRelease", replaceDesc "" mouseRMB) -- Mac convention , ( "C-RightButtonRelease"- , ( [CmdMouse]- , "open or close door"- , AlterWithPointer $ closeDoorTriggers ++ openDoorTriggers ) )+ , ([CmdMouse], "open or close or alter at pointer", AlterWithPointer []) ) , ("MiddleButtonRelease", mouseMMB) , ("WheelNorth", ([CmdMouse], "swerve the aiming line", Macro ["+"])) , ("WheelSouth", ([CmdMouse], "unswerve the aiming line", Macro ["-"]))@@ -232,8 +256,8 @@ , ("safe6", ( [CmdInternal] , "fling at enemy under pointer" , aimFlingCmd ))- , ("safe7", ( [CmdInternal]- , "open Main Menu"+ , ("safe7", ( [CmdInternal, CmdDashboard]+ , "open main menu" , MainMenu )) , ("safe8", ( [CmdInternal] , "cancel aiming"@@ -250,22 +274,12 @@ ] ++ map defaultHeroSelect [0..6] -closeDoorTriggers :: [Trigger]+closeDoorTriggers :: [TriggerTile] closeDoorTriggers =- [ AlterFeature { verb = "close"- , object = "door"- , feature = TK.CloseTo "closed door" }- , AlterFeature { verb = "close"- , object = "door"- , feature = TK.CloseTo "closed door" }- ]--openDoorTriggers :: [Trigger]-openDoorTriggers =- [ AlterFeature { verb = "open"- , object = "door"- , feature = TK.OpenTo "open door" }- , AlterFeature { verb = "open"- , object = "door"- , feature = TK.OpenTo "open door" }+ [ TriggerTile { ttverb = "close"+ , ttobject = "door"+ , ttfeature = TK.CloseTo "closed door" }+ , TriggerTile { ttverb = "close"+ , ttobject = "door"+ , ttfeature = TK.CloseTo "closed door" } ]
GameDefinition/Content/CaveKind.hs view
@@ -1,12 +1,12 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Cave properties. module Content.CaveKind- ( cdefs+ ( content ) where import Prelude ()@@ -15,34 +15,27 @@ import Data.Ratio -import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.CaveKind -cdefs :: ContentDef CaveKind-cdefs = ContentDef- { getSymbol = csymbol- , getName = cname- , getFreq = cfreq- , validateSingle = validateSingleCaveKind- , validateAll = validateAllCaveKind- , content = contentFromList- [rogue, rogue2, arena, arena2, laboratory, empty, noise, noise2, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1empty, emptyExit, raid, brawl, shootout, escape, zoo, ambush, battle, safari1, safari2, safari3]- }+content :: [CaveKind]+content =+ [rogue, rogue2, arena, arena2, laboratory, empty, noise, noise2, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1empty, emptyExit, raid, brawl, shootout, escape, zoo, ambush, battle, safari1, safari2, safari3]+ rogue, rogue2, arena, arena2, laboratory, empty, noise, noise2, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1empty, emptyExit, raid, brawl, shootout, escape, zoo, ambush, battle, safari1, safari2, safari3 :: CaveKind rogue = CaveKind { csymbol = 'R' , cname = "Insulated storage area"- , cfreq = [ ("default random", 100), ("deep random", 80)+ , cfreq = [ ("default random", 100), ("deep random", 70) , ("caveRogue", 1) ] , cxsize = fst normalLevelBound + 1 , cysize = snd normalLevelBound + 1 , cgrid = DiceXY (3 `d` 2) 4 , cminPlaceSize = DiceXY (2 `d` 2 + 4) 5- , cmaxPlaceSize = DiceXY 15 10- , cdarkChance = 1 `d` 54 + 1 `dl` 20+ , cmaxPlaceSize = DiceXY 16 20+ , cdarkChance = 1 `d` 54 + 1 `dL` 20 , cnightChance = 51 -- always night , cauxConnects = 1%2 , cmaxVoid = 1%6@@ -51,10 +44,11 @@ , cdoorChance = 3%4 , copenChance = 1%5 , chidden = 7- , cactorCoeff = 130 -- the maze requires time to explore+ , cactorCoeff = 65 -- the maze requires time to explore , cactorFreq = [("monster", 50), ("animal", 25), ("robot", 25)]- , citemNum = 6 `d` 5- , citemFreq = [("useful", 40), ("treasure", 60)]+ , citemNum = 6 `d` 5 - 4 `dL` 1 -- deeper down quality over quantity+ , citemFreq = [ ("common item", 40), ("treasure", 60)+ , ("curious item", 10) ] , cplaceFreq = [("rogue", 100)] , cpassable = False , cdefTile = "fillerWall"@@ -69,7 +63,7 @@ , cdesc = "Winding tunnels stretch into the dark." } rogue2 = rogue- { cfreq = [("deep random", 20)]+ { cfreq = [("deep random", 30)] , cname = "Dark storage area" , cdarkChance = 51 -- all rooms dark , cnightChance = 0 -- always day@@ -79,7 +73,7 @@ { csymbol = 'A' , cname = "Recreational deck" , cfreq = [("default random", 40), ("caveArena", 1)]- , cgrid = DiceXY (2 + 1 `d` 2) (1 `d` 3)+ , cgrid = DiceXY (2 + 1 `d` 2) (1 + 1 `d` 2) , cminPlaceSize = DiceXY (2 `d` 2 + 4) 6 , cmaxPlaceSize = DiceXY 16 12 , cdarkChance = 49 + 1 `d` 10 -- almost all rooms dark (1 in 10 lit)@@ -89,12 +83,13 @@ , cnightChance = 0 -- always day , cauxConnects = 1 , cmaxVoid = 1%8- , cextraStairs = 1 `d` 3+ , cextraStairs = 1 , chidden = 0- , cactorCoeff = 100+ , cactorCoeff = 50 , cactorFreq = [("monster", 25), ("animal", 70), ("robot", 5)]- , citemNum = 5 `d` 5 -- few rooms- , citemFreq = [("useful", 20), ("treasure", 40), ("any scroll", 40)]+ , citemNum = 4 `d` 5 -- few rooms+ , citemFreq = [ ("common item", 20), ("treasure", 40), ("any scroll", 40)+ , ("curious item", 10) ] , cplaceFreq = [("arena", 100)] , cpassable = True , cdefTile = "arenaSetLit"@@ -108,8 +103,10 @@ , cdarkChance = 41 + 1 `d` 10 -- almost all rooms lit (1 in 10 dark) -- Trails provide enough light for fun stealth. , cnightChance = 51 -- always night- , citemNum = 7 `d` 5 -- rare, so make it exciting- , citemFreq = [("useful", 20), ("treasure", 80)] -- lives up to the name+ , citemNum = 6 `d` 5 -- rare, so make it exciting+ , citemFreq = [ ("common item", 20)+ , ("treasure", 80) -- lives up to the name+ , ("curious item", 20) ] , cdefTile = "arenaSetDark" , cdesc = "" }@@ -119,16 +116,18 @@ , cfreq = [("deep random", 20), ("caveLaboratory", 1)] , cgrid = DiceXY (2 `d` 2 + 7) 3 , cminPlaceSize = DiceXY (3 `d` 2 + 4) 5- , cdarkChance = 1 `d` 54 + 1 `dl` 20 -- most rooms lit, to compensate for corridors+ , cdarkChance = 1 `d` 54 + 1 `dL` 20+ -- most rooms lit, to compensate for corridors , cnightChance = 0 -- always day , cauxConnects = 1%10 , cmaxVoid = 1%10- , cextraStairs = 1 `d` 2+ , cextraStairs = 1 , cdoorChance = 1 , copenChance = 1%2 , chidden = 7- , citemNum = 7 `d` 5 -- reward difficulty- , citemFreq = [("useful", 20), ("treasure", 40), ("any vial", 40)]+ , citemNum = 6 `d` 5 -- reward difficulty+ , citemFreq = [ ("common item", 20), ("treasure", 40), ("explosive", 40)+ , ("curious item", 20) ] , cplaceFreq = [("laboratory", 100)] , cpassable = False , cdefTile = "fillerWall"@@ -144,16 +143,16 @@ , cgrid = DiceXY 1 1 , cminPlaceSize = DiceXY 12 12 , cmaxPlaceSize = DiceXY 48 32 -- favour large rooms- , cdarkChance = 1 `d` 100 + 1 `dl` 100+ , cdarkChance = 1 `d` 100 + 1 `dL` 100 , cnightChance = 0 -- always day , cauxConnects = 3%2 , cminStairDist = 30 , cmaxVoid = 0 -- too few rooms to have void and fog common anyway- , cextraStairs = 1 `d` 2+ , cextraStairs = 1 , cdoorChance = 0 , copenChance = 0 , chidden = 0- , cactorCoeff = 80+ , cactorCoeff = 40 , cactorFreq = [("monster", 25), ("animal", 5), ("robot", 70)] , citemNum = 5 `d` 5 -- few rooms , cplaceFreq = [("empty", 100)]@@ -169,7 +168,7 @@ , cname = "Flight hardware hub" , cfreq = [("caveNoise", 1)] , cgrid = DiceXY (2 + 1 `d` 3) 3- , cminPlaceSize = DiceXY 8 5+ , cminPlaceSize = DiceXY 8 6 , cmaxPlaceSize = DiceXY 20 10 , cdarkChance = 51 -- Light is deadly, because nowhere to hide and pillars enable spawning@@ -177,12 +176,14 @@ , cnightChance = 0 -- harder variant, but looks cheerful , cauxConnects = 1%10 , cmaxVoid = 1%100- , cextraStairs = 1 `d` 4+ , cextraStairs = 1 + 1 `d` 2 , cdoorChance = 1 -- to enable the doorlessWall hack and have no lit tiles , chidden = 0- , cactorCoeff = 160 -- the maze requires time to explore+ , cactorCoeff = 80 -- the maze requires time to explore , cactorFreq = [("monster", 70), ("animal", 15), ("robot", 15)]- , citemNum = 7 `d` 5 -- an incentive to explore the labyrinth+ , citemNum = 6 `d` 5 -- an incentive to explore the labyrinth+ , citemFreq = [ ("common item", 20), ("treasure", 60), ("explosive", 20)+ , ("curious item", 20) ] , cpassable = True , cplaceFreq = [("noise", 100)] , cdefTile = "noiseSet"@@ -195,7 +196,9 @@ { cname = "Power distribution hub" , cfreq = [("caveNoise2", 1)] , cnightChance = 51 -- easier variant, but looks sinister- , citemNum = 13 `d` 5 -- an incentive to explore the final labyrinth+ , citemNum = 11 `d` 5 -- an incentive to explore the final labyrinth+ , citemFreq = [ ("common item", 40), ("treasure", 60)+ , ("curious item", 20) ] , cplaceFreq = [("noise", 1), ("mine", 99)] , cstairFreq = [("gated staircase", 100)] , cdesc = ""@@ -208,8 +211,9 @@ , cextraStairs = 1 , cactorCoeff = 200 -- it's quite deep already, so spawn slowly , cactorFreq = [("animal", 100)]- , citemNum = 9 `d` 5 -- lure them in with loot- , citemFreq = filter ((/= "treasure") . fst) $ citemFreq rogue+ , citemNum = 8 `d` 5 -- lure them in with loot+ , citemFreq = filter ((`notElem` ["treasure", "curious item"]) . fst)+ $ citemFreq rogue , cdesc = "The bridge is gutted out and deserted. There are animal cries down below and ominous silence up above." } shallow2rogue = rogue@@ -222,8 +226,8 @@ shallow2arena = arena { cfreq = [("shallow random 2", 100)] , cactorCoeff = cactorCoeff arena `div` 2- , cactorFreq = filter ((/= "monster") . fst) $ cactorFreq empty- , citemFreq = filter ((/= "treasure") . fst) $ citemFreq empty+ , cactorFreq = filter ((/= "monster") . fst) $ cactorFreq arena+ , citemFreq = filter ((/= "treasure") . fst) $ citemFreq arena , cdesc = "" } shallow2empty = empty@@ -231,9 +235,10 @@ , cactorCoeff = cactorCoeff empty `div` 2 , cactorFreq = filter ((/= "monster") . fst) $ cactorFreq empty , citemFreq = filter ((/= "treasure") . fst) $ citemFreq empty+ , cdefTile = "emptyExitSet" -- avoid floor windows , cdesc = "" }-shallow1empty = shallow2empty -- TODO: replace some rooms with oriels?+shallow1empty = empty { cname = "Outermost deck" , cfreq = [("outermost", 100)] , cactorCoeff = 4 -- shallower than LH, so fewer immediate actors, so boost@@ -244,16 +249,20 @@ -- enough of a continuity. The faucets on lvl 1 are not OP and can't be -- abused, because they spawn less and less often and also HP doesn't -- effectively accumulate over max.+ , citemFreq = filter ((/= "treasure") . fst) $ citemFreq empty , couterFenceTile = "oriels fence"- , cdesc = "The black sky outside can be seen through the oriels."+ , cdesc = "The black sky outside sucks light through the oriels." } emptyExit = empty { cname = "Shuttle servicing area" , cfreq = [("caveEmptyExit", 1)]- , cdarkCorTile = "trailLit" -- flavour+ , cdefTile = "emptyExitSet"+ , cdarkCorTile = "transport route"+ , clitCorTile = "transport route" , couterFenceTile = "noise fence" -- for flavour , cescapeGroup = Just "escape spaceship down"- , cdesc = "Empty husks and strewn entrails of small craft litter the hangar among neglected cranes and airlocks."+ , cstairFreq = [("gated staircase", 100)]+ , cdesc = "Empty husks and strewn entrails of small craft litter the hangar among neglected cranes and airlocks welded shut." } raid = rogue { csymbol = 'S'@@ -261,10 +270,10 @@ , cfreq = [("caveRaid", 1)] , cdarkChance = 0 -- all rooms lit, for a gentle start , cmaxVoid = 1%10- , cactorCoeff = 500 -- deep level with no kit, so slow spawning+ , cactorCoeff = 250 -- deep level with no kit, so slow spawning , cactorFreq = [("animal", 50), ("robot", 50)] , citemNum = 6 `d` 8 -- just one level, hard enemies, treasure- , citemFreq = [("useful", 33), ("gem", 33), ("currency", 33)]+ , citemFreq = [("common item", 100), ("currency", 500)] , cescapeGroup = Just "escape up" , cdesc = "" }@@ -285,7 +294,7 @@ , chidden = 0 , cactorFreq = [] , citemNum = 5 `d` 8- , citemFreq = [("useful", 100)]+ , citemFreq = [("common item", 100)] , cplaceFreq = [("brawl", 60), ("rogue", 40)] , cpassable = True , cdefTile = "brawlSetLit"@@ -314,9 +323,8 @@ , citemNum = 5 `d` 16 -- less items in inventory, more to be picked up, -- to reward explorer and aggressor and punish camper- , citemFreq = [ ("useful", 30)- , ("any arrow", 400), ("harpoon", 300)- , ("any vial", 60) ]+ , citemFreq = [ ("common item", 30)+ , ("any arrow", 400), ("harpoon", 300), ("explosive", 50) ] -- Many consumable buffs are needed in symmetric maps -- so that aggressor prepares them in advance and camper -- needs to waste initial turns to buff for the defence.@@ -340,18 +348,19 @@ , cdarkChance = 51 -- colonnade rooms should always be dark , cnightChance = 51 -- always night , cauxConnects = 3%2- , cmaxVoid = 1%20+ , cmaxVoid = 1%10 , cextraStairs = 1 , chidden = 0 , cactorFreq = []- , citemNum = 5 `d` 8- , citemFreq = [ ("useful", 30), ("treasure", 30), ("gem", 100)- , ("weak arrow", 500), ("harpoon", 400) ]+ , citemNum = 6 `d` 8+ , citemFreq = [ ("common item", 30), ("gem", 150)+ , ("weak arrow", 500), ("harpoon", 400)+ , ("explosive", 100) ] , cplaceFreq = [("park", 100)] , cpassable = True , cdefTile = "escapeSetDark" -- different tiles, not burning yet- , cdarkCorTile = "trailLit" -- let trails give off light- , clitCorTile = "trailLit"+ , cdarkCorTile = "alarmingTrailLit" -- let trails give off light+ , clitCorTile = "alarmingTrailLit" , cescapeGroup = Just "escape outdoor down" , cdesc = "" }@@ -366,13 +375,13 @@ , cnightChance = 51 -- always night , cauxConnects = 1%4 , cmaxVoid = 1%20- , cdoorChance = 2%10+ , cdoorChance = 7%10 , copenChance = 9%10 , cextraStairs = 1 , chidden = 0 , cactorFreq = [] , citemNum = 7 `d` 8- , citemFreq = [("useful", 100), ("light source", 1000)]+ , citemFreq = [("common item", 100), ("light source", 1000)] , cplaceFreq = [("zoo", 50)] , cpassable = True , cdefTile = "zooSet"@@ -396,7 +405,7 @@ (2 `d` 2 + 5) 3 -- for now, to fit larger places , cminPlaceSize = DiceXY 3 3 , cmaxPlaceSize = DiceXY 15 15 -- allow hangars- , cdarkChance = 51+ , cdarkChance = 51 -- colonnade rooms should always be dark , cnightChance = 51 -- always night , cauxConnects = 3%2 , cmaxVoid = 1%20@@ -404,7 +413,8 @@ , chidden = 0 , cactorFreq = [] , citemNum = 5 `d` 8- , citemFreq = [("useful", 30), ("any arrow", 400), ("harpoon", 300)]+ , citemFreq = [ ("common item", 30)+ , ("any arrow", 400), ("harpoon", 300), ("explosive", 50) ] , cplaceFreq = [("ambush", 100)] , cpassable = True , cdefTile = "ambushSet"@@ -429,7 +439,7 @@ , chidden = 0 , cactorFreq = [] , citemNum = 5 `d` 8- , citemFreq = [("useful", 100), ("light source", 200)]+ , citemFreq = [("common item", 100), ("light source", 200)] , cplaceFreq = [("battle", 50), ("rogue", 50)] , cpassable = True , cdefTile = "battleSet"@@ -441,7 +451,6 @@ safari1 = brawl { cname = "Hunam habitat" , cfreq = [("caveSafari1", 1)]- , cescapeGroup = Nothing , cstairFreq = [("staircase outdoor", 1)] , cdesc = "\"DLC 1. Hunams scavenge in a forest in their usual disgusting way.\"" }
GameDefinition/Content/ItemKind.hs view
@@ -1,1306 +1,1530 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)--- This file is a part of the computer game Allure of the Stars--- and is released under the terms of the GNU Affero General Public License.--- For license and copyright information, see the file LICENSE.------ | Item definitions.-module Content.ItemKind- ( cdefs, items, otherItemContent- ) where--import Prelude ()--import Game.LambdaHack.Common.Prelude--import Content.ItemKindActor-import Content.ItemKindBlast-import Content.ItemKindEmbed-import Content.ItemKindOrgan-import Content.ItemKindTemporary-import Game.LambdaHack.Common.Ability-import Game.LambdaHack.Common.Color-import Game.LambdaHack.Common.ContentDef-import Game.LambdaHack.Common.Dice-import Game.LambdaHack.Common.Flavour-import Game.LambdaHack.Common.Misc-import Game.LambdaHack.Content.ItemKind--cdefs :: ContentDef ItemKind-cdefs = ContentDef- { getSymbol = isymbol- , getName = iname- , getFreq = ifreq- , validateSingle = validateSingleItemKind- , validateAll = validateAllItemKind- , content = contentFromList $ items ++ otherItemContent- }--otherItemContent :: [ItemKind]-otherItemContent = embeds ++ actors ++ organs ++ blasts ++ temporaries--items :: [ItemKind]-items =- [sandstoneRock, dart, spike, slingStone, slingBullet, paralizingProj, harpoon, net, light1, light2, light3, blanket, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, gem5, currency]- -- Allure-specific- ++ [needle, constructionHooter]--sandstoneRock, dart, spike, slingStone, slingBullet, paralizingProj, harpoon, net, light1, light2, light3, blanket, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, gem5, currency :: ItemKind--- Allure-specific-needle, constructionHooter :: ItemKind--necklace, ring, potion, flask, scroll, wand, gem :: ItemKind -- generic templates---- * Item group symbols, from Angband and variants--symbolProjectile, _symbolLauncher, symbolLight, symbolTool, symbolSpecial, symbolGold, symbolNecklace, symbolRing, symbolPotion, symbolFlask, symbolScroll, symbolTorsoArmor, symbolMiscArmor, _symbolClothes, symbolShield, symbolPolearm, symbolEdged, symbolHafted, symbolWand, _symbolStaff, symbolFood :: Char--symbolProjectile = '{'-_symbolLauncher = '}'-symbolLight = '('-symbolTool = ')'-symbolSpecial = '*' -- don't overuse, because it clashes with projectiles-symbolGold = '$' -- also gems-symbolNecklace = '"'-symbolRing = '='-symbolPotion = '!' -- concoction, bottle, jar, vial, canister-symbolFlask = '!'-symbolScroll = '?' -- book, note, tablet, remote, chip, card-symbolTorsoArmor = '['-symbolMiscArmor = '['-_symbolClothes = '['-symbolShield = ']'-symbolPolearm = '/'-symbolEdged = '|'-symbolHafted = '\\'-symbolWand = '-' -- magical rod, transmitter, pistol, rifle-_symbolStaff = '_' -- scanner-symbolFood = ',' -- also body part; distinct from floor: not middle dot---- * Thrown weapons--sandstoneRock = ItemKind- { isymbol = symbolProjectile- , iname = "ceramic foam splinter"- , ifreq = [("sandstone rock", 1), ("weak arrow", 10)]- , iflavour = zipPlain [Green]- , icount = 1 `d` 2- , irarity = [(1, 50), (10, 1)]- , iverbHit = "hit"- , iweight = 300- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddHurtMelee $ -16 * 5]- , ieffects = []- , ifeature = [toVelocity 70, Fragile, Identified] -- not dense, irregular- , idesc = "A light, irregular lump of ceramic foam used in construction."- , ikit = []- }-dart = ItemKind- { isymbol = symbolProjectile- , iname = "billiard ball"- , ifreq = [("useful", 100), ("any arrow", 50), ("weak arrow", 50)]- , iflavour = zipPlain [BrWhite]- , icount = 4 `d` 3- , irarity = [(1, 20), (10, 10)]- , iverbHit = "strike"- , iweight = 170- , idamage = [(98, 1 `d` 1), (2, 2 `d` 1)]- , iaspects = [AddHurtMelee $ (-14 + 1 `d` 2 + 1 `dl` 4) * 5]- -- only leather-piercing- , ieffects = []- , ifeature = [Identified]- , idesc = "Ideal shape, size and weight for throwing."- , ikit = []- }-spike = ItemKind- { isymbol = symbolProjectile- , iname = "steak knife"- , ifreq = [("useful", 100), ("any arrow", 50), ("weak arrow", 50)]- , iflavour = zipPlain [Cyan]- , icount = 4 `d` 3- , irarity = [(1, 10), (10, 20)]- , iverbHit = "nick"- , iweight = 100- , idamage = [(98, 2 `d` 1), (2, 4 `d` 1)]- , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dl` 4) * 5]- -- heavy vs armor- , ieffects = [ Explode "single spark" -- when hitting enemy- , OnSmash (Explode "single spark") ] -- at wall hit- , ifeature = [toVelocity 70, Identified] -- hitting with tip costs speed- , idesc = "Not particularly well balanced, but with a laser-sharpened titanium tip and blade."- , ikit = []- }-slingStone = ItemKind- { isymbol = symbolProjectile- , iname = "steel hex nut"- , ifreq = [("useful", 5), ("any arrow", 100)]- , iflavour = zipPlain [Blue]- , icount = 3 `d` 3- , irarity = [(1, 1), (10, 20)]- , iverbHit = "hit"- , iweight = 200- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dl` 4) * 5]- -- heavy vs armor- , ieffects = [ Explode "single spark" -- when hitting enemy- , OnSmash (Explode "single spark") ] -- at wall hit- , ifeature = [toVelocity 150, Identified]- , idesc = "A large hexagonal fastening nut, securely lodging in the pouch of a makeshift string and cloth sling due to its angular shape."- , ikit = []- }-slingBullet = ItemKind- { isymbol = symbolProjectile- , iname = "bearing ball"- , ifreq = [("useful", 5), ("any arrow", 100)]- , iflavour = zipPlain [White]- , icount = 6 `d` 3- , irarity = [(1, 1), (10, 15)]- , iverbHit = "hit"- , iweight = 28- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddHurtMelee $ (-17 + 1 `d` 2 + 1 `dl` 4) * 5]- -- not armor-piercing- , ieffects = []- , ifeature = [toVelocity 200, Identified]- , idesc = "Small but heavy bearing ball. Due to its size and shape, it securely fits in the makeshift sling's pouch and doesn't snag when released."- , ikit = []- }---- * Exotic thrown weapons---- Identified, because shape (and name) says it all. Detailed stats id by use.-paralizingProj = ItemKind- { isymbol = symbolProjectile- , iname = "can"- , ifreq = [("useful", 100), ("can of sticky foam", 1)]- , iflavour = zipPlain [Magenta]- , icount = 1 `dl` 3- , irarity = [(5, 5), (10, 20)]- , iverbHit = "glue"- , iweight = 1000- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddHurtMelee $ -14 * 5]- , ieffects = [ ELabel "of sticky foam", Paralyze (10 + 1 `d` 12)- , OnSmash (Explode "glue") ]- , ifeature = [toVelocity 70, Identified, Lobable, Fragile] -- unwieldy- , idesc = "A can of liquid, fast-setting construction foam."- , ikit = []- }-harpoon = ItemKind- { isymbol = symbolProjectile- , iname = "harpoon"- , ifreq = [("useful", 100), ("harpoon", 100)]- , iflavour = zipPlain [Brown]- , icount = 1 `dl` 5- , irarity = [(5, 5), (10, 5)]- , iverbHit = "hook"- , iweight = 750- , idamage = [(99, 5 `d` 1), (1, 10 `d` 1)]- , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dl` 4) * 5]- , ieffects = [PullActor (ThrowMod 200 50)]- , ifeature = [Identified]- , idesc = "A display piece harking back to the Earth's oceanic tourism hayday. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying."- , ikit = []- }-net = ItemKind- { isymbol = symbolProjectile- , iname = "net"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [White]- , icount = 1 `dl` 3- , irarity = [(3, 5), (10, 4)]- , iverbHit = "entangle"- , iweight = 1000- , idamage = toDmg $ 2 `d` 1- , iaspects = [AddHurtMelee $ -14 * 5]- , ieffects = [ toOrganGameTurn "slowed" (3 + 1 `d` 3)- , DropItem maxBound 1 CEqp "torso armor" ]- , ifeature = [Identified]- , idesc = "A large synthetic fibre net with weights affixed along the edges. Entangles armor and restricts movement."- , ikit = []- }---- * Lights--light1 = ItemKind- { isymbol = symbolLight- , iname = "torch"- , ifreq = [("useful", 100), ("light source", 100), ("wooden torch", 1)]- , iflavour = zipPlain [Brown]- , icount = 1 `d` 2- , irarity = [(1, 15)]- , iverbHit = "scorch"- , iweight = 1000- , idamage = toDmg 0- , iaspects = [ AddShine 3 -- not only flashes, but also sparks,- , AddSight (-2) ] -- so unused by AI due to the mixed blessing- , ieffects = [Burn 1, EqpSlot EqpSlotLightSource]- , ifeature = [Lobable, Identified, Equipable] -- not Fragile; reusable flare- , idesc = "A torch improvised with cloth soaked in tar on a stick."- , ikit = []- }-light2 = ItemKind- { isymbol = symbolLight- , iname = "oil lamp"- , ifreq = [("useful", 100), ("light source", 100)]- , iflavour = zipPlain [BrYellow]- , icount = 1- , irarity = [(6, 7)]- , iverbHit = "burn"- , iweight = 1500- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddShine 3, AddSight (-1)]- , ieffects = [ Burn 1, Paralyze 6, OnSmash (Explode "burning oil 3")- , EqpSlot EqpSlotLightSource ]- , ifeature = [Lobable, Fragile, Identified, Equipable]- , idesc = "A sizable restaurant glass lamp filled with plant oil feeding a wick."- , ikit = []- }-light3 = ItemKind- { isymbol = symbolLight- , iname = "crank spotlight"- , ifreq = [("useful", 100), ("light source", 100)]- , iflavour = zipPlain [BrWhite]- , icount = 1- , irarity = [(10, 5)]- , iverbHit = "snag"- , iweight = 3000- , idamage = toDmg 0- , iaspects = [AddShine 4, AddArmorRanged $ - 1 `d` 3] -- noise and distraction- , ieffects = [EqpSlot EqpSlotLightSource]- , ifeature = [Identified, Equipable]- , idesc = "Powerful, wide-beam spotlight, powered by a hand-crank. Requires noisy two-handed recharging every few minutes."- , ikit = []- }-blanket = ItemKind- { isymbol = symbolLight- , iname = "mineral fibre blanket"- , ifreq = [("useful", 100), ("light source", 100), ("blanket", 1)]- , iflavour = zipPlain [BrBlack]- , icount = 1- , irarity = [(1, 5)]- , iverbHit = "swoosh"- , iweight = 1000- , idamage = toDmg 0- , iaspects = [ AddShine (-10) -- douses torch, lamp and lantern in one action- , AddArmorMelee 1, AddMaxCalm 2 ]- , ieffects = []- , ifeature = [Lobable, Identified, Equipable] -- not Fragile; reusable douse- , idesc = ""- , ikit = []- }---- * Exploding consumables, often intended to be thrown.---- Not identified, because they are perfect for the id-by-use fun,--- due to effects. They are fragile and upon hitting the ground explode--- for effects roughly corresponding to their normal effects.--- Whether to hit with them or explode them close to the tartget--- is intended to be an interesting tactical decision.------ Flasks are often not natural; maths, magic, distillery.--- In reality, they just cover all temporary effects, which in turn matches--- all aspects.------ No flask nor temporary organ of Calm depletion, since Calm reduced often.-flask = ItemKind- { isymbol = symbolFlask- , iname = "flask"- , ifreq = [("useful", 100), ("flask", 100), ("any vial", 100)]- , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol- ++ zipLiquid brightCol- , icount = 1- , irarity = [(1, 7), (10, 4)]- , iverbHit = "splash"- , iweight = 500- , idamage = toDmg 0- , iaspects = []- , ieffects = []- , ifeature = [Applicable, Lobable, Fragile, toVelocity 50] -- oily, bad grip- , idesc = "A flask of oily liquid of a suspect color. Something seems to be moving inside."- , ikit = []- }-flask1 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of strength renewal brew"- , toOrganActorTurn "strengthened" (20 + 1 `d` 5)- , toOrganNone "regenerating"- , OnSmash (Explode "dense shower") ]- }-flask2 = flask- { ieffects = [ ELabel "of weakness brew"- , toOrganGameTurn "weakened" (20 + 1 `d` 5)- , OnSmash (Explode "sparse shower") ]- }-flask3 = flask- { ieffects = [ ELabel "of melee protective balm"- , toOrganActorTurn "protected from melee" (20 + 1 `d` 5)- , OnSmash (Explode "melee protective balm") ]- }-flask4 = flask- { ieffects = [ ELabel "of ranged protective balm"- , toOrganActorTurn "protected from ranged" (20 + 1 `d` 5)- , OnSmash (Explode "ranged protective balm") ]- }-flask5 = flask- { ieffects = [ ELabel "of red paint"- , toOrganGameTurn "painted red" (20 + 1 `d` 5)- , OnSmash (Explode "red paint") ]- }-flask6 = flask- { irarity = [(10, 9)]- , ieffects = [ ELabel "of resolution"- , toOrganActorTurn "resolute" (200 + 1 `d` 50)- -- long, for scouting and has to recharge- , RefillCalm 60 -- not to make it a drawback, via @calmEnough@- , OnSmash (Explode "resolution dust") ]- }-flask7 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of haste brew"- , toOrganActorTurn "hasted" (20 + 1 `d` 5)- , OnSmash (Explode "blast 20")- , OnSmash (Explode "haste spray") ]- }-flask8 = flask- { irarity = [(1, 14), (10, 4)]- , ieffects = [ ELabel "of lethargy brew"- , toOrganGameTurn "slowed" (20 + 1 `d` 5)- , toOrganNone "regenerating", toOrganNone "regenerating" -- x2- , RefillCalm 5- , OnSmash (Explode "slowness mist") ]- }-flask9 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of eye drops"- , toOrganActorTurn "far-sighted" (40 + 1 `d` 10)- , OnSmash (Explode "eye drop") ]- }-flask10 = flask- { irarity = [(10, 2)]- , ieffects = [ ELabel "of smelly concoction"- , toOrganActorTurn "keen-smelling" (40 + 1 `d` 10)- , DetectActor 10- , OnSmash (Explode "smelly droplet") ]- }-flask11 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of cat tears"- , toOrganActorTurn "shiny-eyed" (40 + 1 `d` 10)- , OnSmash (Explode "eye shine") ]- }-flask12 = flask- { irarity = [(1, 14), (10, 10)]- , ieffects = [ ELabel "of whiskey"- , toOrganActorTurn "drunk" (20 + 1 `d` 5)- , Burn 1, RefillHP 3- , OnSmash (Explode "whiskey spray") ]- }-flask13 = flask- { ieffects = [ ELabel "of bait cocktail"- , toOrganActorTurn "drunk" (20 + 1 `d` 5)- , Burn 1, RefillHP 3- , Summon "mobile animal" 1- , OnSmash (Summon "mobile animal" 1)- , OnSmash Impress- , OnSmash (Explode "waste") ]- }--- The player has full control over throwing the flask at his party,--- so he can milk the explosion, so it has to be much weaker, so a weak--- healing effect is enough. OTOH, throwing a harmful flask at many enemies--- at once is not easy to arrange, so these explostions can stay powerful.-flask14 = flask- { irarity = [(1, 4), (10, 14)]- , ieffects = [ ELabel "of regeneration brew"- , toOrganNone "regenerating", toOrganNone "regenerating" -- x2- , OnSmash (Explode "healing mist") ]- }-flask15 = flask- { ieffects = [ ELabel "of poison"- , toOrganNone "poisoned", toOrganNone "poisoned" -- x2- , OnSmash (Explode "poison cloud") ]- }-flask16 = flask- { irarity = [(1, 14), (10, 4)]- , ieffects = [ ELabel "of weak poison"- , toOrganNone "poisoned"- , OnSmash (Explode "poison cloud") ]- }-flask17 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of slow resistance"- , toOrganNone "slow resistant"- , OnSmash (Explode "blast 10")- , OnSmash (Explode "anti-slow mist") ]- }-flask18 = flask- { irarity = [(10, 4)]- , ieffects = [ ELabel "of poison resistance"- , toOrganNone "poison resistant"- , OnSmash (Explode "antidote mist") ]- }-flask19 = flask- { ieffects = [ ELabel "of blindness"- , toOrganGameTurn "blind" (40 + 1 `d` 10)- , OnSmash (Explode "iron filing") ]- }-flask20 = flask- { ieffects = [ ELabel "of calamity"- , toOrganNone "poisoned"- , toOrganGameTurn "weakened" (20 + 1 `d` 5)- , toOrganGameTurn "painted red" (20 + 1 `d` 5)- , OnSmash (Explode "poison cloud") ]- }---- Potions are often natura. Various configurations of effects.--- A different class of effects is on scrolls and/or mechanical items.--- Some are shared.--potion = ItemKind- { isymbol = symbolPotion- , iname = "vial"- , ifreq = [("useful", 100), ("potion", 100), ("any vial", 100)]- , iflavour = zipLiquid brightCol ++ zipPlain brightCol ++ zipFancy brightCol- , icount = 1- , irarity = [(1, 10), (10, 7)]- , iverbHit = "splash"- , iweight = 200- , idamage = toDmg 0- , iaspects = []- , ieffects = []- , ifeature = [Applicable, Lobable, Fragile, toVelocity 50] -- oily, bad grip- , idesc = "A vial of bright, frothing concoction. The best that nature has to offer."- , ikit = []- }-potion1 = potion- { ieffects = [ ELabel "of rose water", Impress, RefillCalm (-5)- , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ]- }-potion2 = potion- { ifreq = [("treasure", 100)]- , irarity = [(6, 9), (10, 9)]- , ieffects = [ Unique, ELabel "of Attraction", Impress, RefillCalm (-20)- , OnSmash (Explode "pheromone") ]- -- , idesc = ""- }-potion3 = potion- { ieffects = [ RefillHP 5, DropItem 1 maxBound COrgan "poisoned"- , OnSmash (Explode "healing mist") ]- }-potion4 = potion- { irarity = [(1, 7), (10, 10)]- , ieffects = [ RefillHP 10, DropItem 1 maxBound COrgan "poisoned"- , OnSmash (Explode "healing mist 2") ]- }-potion5 = potion -- needs to be common to show at least a portion of effects- { irarity = [(1, 30), (10, 15)]- , ieffects = [ OneOf [ RefillHP 10, RefillHP 5, Burn 5- , DropItem 1 maxBound COrgan "poisoned"- , toOrganActorTurn "strengthened" (20 + 1 `d` 5) ]- , OnSmash (OneOf [ Explode "dense shower"- , Explode "sparse shower"- , Explode "melee protective balm"- , Explode "ranged protective balm"- , Explode "red paint"- , Explode "blast 10" ]) ]- }-potion6 = potion -- needs to be common to show at least a portion of effects- { irarity = [(1, 5), (10, 20)]- , ieffects = [ Impress- , OneOf [ RefillCalm (-60)- , RefillHP 20, RefillHP 10, Burn 10- , DropItem 1 maxBound COrgan "poisoned"- , toOrganActorTurn "hasted" (20 + 1 `d` 5) ]- , OnSmash (OneOf [ Explode "healing mist 2"- , Explode "wounding mist"- , Explode "distressing odor"- , Explode "haste spray"- , Explode "slowness mist"- , Explode "fragrance"- , Explode "blast 20" ]) ]- }-potion7 = potion- { irarity = [(1, 11), (10, 4)]- , ieffects = [ DropItem 1 maxBound COrgan "poisoned"- , OnSmash (Explode "antidote mist") ]- }-potion8 = potion- { irarity = [(1, 9)]- , ieffects = [ DropItem 1 maxBound COrgan "temporary condition"- , OnSmash (Explode "blast 10") ]- }-potion9 = potion- { irarity = [(10, 9)]- , ieffects = [ DropItem maxBound maxBound COrgan "temporary condition"- , OnSmash (Explode "blast 20") ]- }-potion10 = potion- { ifreq = [("treasure", 100)]- , irarity = [(10, 4)]- , ieffects = [ Unique, ELabel "of Love", RefillHP 60- , Impress, RefillCalm (-60)- , OnSmash (Explode "healing mist 2")- , OnSmash (Explode "pheromone") ]- -- , idesc = ""- }---- * Non-exploding consumables, not specifically designed for throwing--scroll = ItemKind- { isymbol = symbolScroll- , iname = "chip"- , ifreq = [("useful", 100), ("any scroll", 100)]- , iflavour = zipFancy stdCol ++ zipPlain darkCol -- arcane and old- , icount = 1- , irarity = [(1, 14), (10, 11)]- , iverbHit = "thump"- , iweight = 20- , idamage = toDmg 0- , iaspects = []- , ieffects = []- , ifeature = [ toVelocity 30 -- too small- , Applicable ]- , idesc = "A generic, diposable chip, capable of a one-time holo-display. Some of these also contain a one-time password authorizing a particular spaceship's infrastructure transition. It is unknown how the infrastructure might respond after so many years."- , ikit = []- }-scroll1 = scroll- { ifreq = [("treasure", 100)]- , irarity = [(5, 9), (10, 9)] -- mixed blessing, so available early- , ieffects = [ Unique, ELabel "of Reckless Beacon"- , Summon "hero" 1, Summon "mobile animal" (2 + 1 `d` 2) ]- , idesc = "This ihdustrial wide-spectrum alarm broadcaster, if over-amped for a single powerful blast, should be able to cut through the interference and reach any lost crew members, giving them enough positional information to locate us."- }-scroll2 = scroll- { irarity = [(1, 2)]- , ieffects = [ ELabel "of greed", DetectItem 20, Teleport 20- , RefillCalm (-100) ]- }-scroll3 = scroll- { irarity = [(1, 4), (10, 2)]- , ieffects = [Ascend True]- }-scroll4 = scroll -- needs to be common to show at least a portion of effects- { irarity = [(1, 40), (10, 20)]- , ieffects = [OneOf [ Teleport 5, RefillCalm 5, InsertMove 5- , DetectActor 20, DetectItem 20 ]]- }-scroll5 = scroll -- needs to be common to show at least a portion of effects- { irarity = [(10, 30)]- , ieffects = [ Impress- , OneOf [ Teleport 20, Ascend False, Ascend True- , Summon "hero" 1, Summon "mobile animal" 2- , Detect 40, RefillCalm (-100)- , CreateItem CGround "useful" TimerNone ] ]- }-scroll6 = scroll- { ieffects = [Teleport 5]- }-scroll7 = scroll- { ieffects = [Teleport 20]- }-scroll8 = scroll- { irarity = [(10, 2)]- , ieffects = [InsertMove $ 1 + 1 `d` 2 + 1 `dl` 2]- }-scroll9 = scroll- { irarity = [(1, 30)]- , ieffects = [ ELabel "of scientific explanation"- , Composite [Identify, RefillCalm 10] ]- -- your most pressing existential concerns are answered scientifitically,- -- hence the calming effect- }-scroll10 = scroll- { irarity = [(10, 20)]- , ieffects = [ ELabel "molecular reconfiguration"- , Composite [PolyItem, Explode "firecracker 7"] ]- }-scroll11 = scroll- { ifreq = [("treasure", 100)]- , irarity = [(6, 9), (10, 9)]- , ieffects = [Unique, ELabel "of Prisoner Release", Summon "hero" 1]- , idesc = "This lock chip opens a nearby closet containing one of our lost crew members."- }-scroll12 = scroll- { irarity = [(1, 9), (10, 4)]- , ieffects = [DetectHidden 20]- }-scroll13 = scroll- { ieffects = [ELabel "of acute hearing", DetectActor 20]- }---- * Assorted tools--jumpingPole = ItemKind- { isymbol = symbolTool- , iname = "jumping pole"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [White]- , icount = 1- , irarity = [(1, 2)]- , iverbHit = "prod"- , iweight = 10000- , idamage = toDmg 0- , iaspects = [Timeout $ (1 `d` 2 + 2 - 1 `dl` 2) * 10]- , ieffects = [Recharging (toOrganActorTurn "hasted" 1)]- , ifeature = [Durable, Applicable, Identified]- , idesc = "Makes you vulnerable at take-off, but then you are free like a bird."- , ikit = []- }-sharpeningTool = ItemKind- { isymbol = symbolTool- , iname = "honing steel"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [Blue]- , icount = 1- , irarity = [(10, 10)]- , iverbHit = "smack"- , iweight = 400- , idamage = toDmg 0- , iaspects = [AddHurtMelee $ (1 `d` 10) * 3]- , ieffects = [EqpSlot EqpSlotAddHurtMelee]- , ifeature = [Identified, Equipable]- , idesc = "Originally used for realigning the bent or buckled edges of kitchen knives in the local bars. Now it saves lives by letting you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop."- , ikit = []- }-seeingItem = ItemKind- { isymbol = symbolFood- , iname = "visual sensor"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [Red]- , icount = 1- , irarity = [(1, 1)]- , iverbHit = "gaze at"- , iweight = 500- , idamage = toDmg 0- , iaspects = [ AddSight 10, AddMaxCalm 30, AddShine 2- , Timeout $ 1 + 1 `d` 2 ]- , ieffects = [ Periodic- , Recharging (toOrganNone "poisoned")- , Recharging (Summon "mobile robot" 1) ]- , ifeature = [Identified]- , idesc = "A functioning visual sensor torn out from some sizable robot. The circuitry seem too large for basic signal processing alone. Watch out for the sharp edges and the seeping coolant liquid."- , ikit = []- }-motionScanner = ItemKind- { isymbol = symbolTool- , iname = "handhelp sonar"- , ifreq = [("useful", 100), ("add nocto 1", 20)]- , iflavour = zipPlain [Green]- , icount = 1- , irarity = [(6, 2), (10, 2)]- , iverbHit = "ping"- , iweight = 1000- , idamage = toDmg 0- , iaspects = [ AddNocto 1- , AddArmorMelee (1 `dl` 5 - 10), AddArmorRanged (1 `dl` 5 - 10) ]- , ieffects = [EqpSlot EqpSlotMiscBonus]- , ifeature = [Identified, Equipable]- , idesc = "Handheld underwater echolocator overdriven to scan dark corridors at the cost of emitting loud pings."- , ikit = []- }---- * Periodic jewelry--gorget = ItemKind- { isymbol = symbolNecklace- , iname = "Old Gorget"- , ifreq = [("useful", 25), ("treasure", 25)]- , iflavour = zipFancy [BrCyan]- , icount = 1- , irarity = [(4, 3), (10, 3)] -- weak, shallow- , iverbHit = "whip"- , iweight = 30- , idamage = toDmg 0- , iaspects = [ Timeout $ 1 + 1 `d` 2- , AddArmorMelee $ 2 + 1 `d` 3- , AddArmorRanged $ 1 `d` 3 ]- , ieffects = [ Unique, Periodic- , Recharging (RefillCalm 1), EqpSlot EqpSlotMiscBonus ]- , ifeature = [Durable, Precious, Identified, Equipable]- , idesc = "Highly ornamental, cold, large, steel medallion on a chain. Unlikely to offer much protection as an armor piece, but the old, worn engraving reassures you."- , ikit = []- }--- Not idenfified, because the id by use, e.g., via periodic activations. Fun.-necklace = ItemKind- { isymbol = symbolNecklace- , iname = "necklace"- , ifreq = [("useful", 100)]- , iflavour = zipFancy stdCol ++ zipPlain brightCol- , icount = 1- , irarity = [(10, 2)]- , iverbHit = "whip"- , iweight = 30- , idamage = toDmg 0- , iaspects = []- , ieffects = [Periodic]- , ifeature = [Precious, toVelocity 50, Equipable] -- not dense enough- , idesc = "Tingling, rattling chain of flat encrusted links. Eccentric millionaires are known to hide their highly personalized body augmentation packs in such large jewelry pieces."- , ikit = []- }-necklace1 = necklace- { ifreq = [("treasure", 100)]- , irarity = [(3, 0), (4, 1), (10, 2)] -- prevents camping on lvl 3- , iaspects = [Timeout $ (1 `d` 3 + 4 - 1 `dl` 3) * 10]- , ieffects = [ Unique, ELabel "of Trickle Life", EqpSlot EqpSlotMiscBonus- , Recharging (RefillHP 1) ]- ++ ieffects necklace- , ifeature = Durable : ifeature necklace- -- , idesc = ""- }-necklace2 = necklace- { ifreq = [("treasure", 100)] -- just too nasty to call it useful- , irarity = [(1, 1)]- , iaspects = [Timeout $ (1 `d` 3 + 3 - 1 `dl` 3) * 10]- , ieffects = [ Recharging (Summon "mobile animal" $ 1 + 1 `dl` 2)- , Recharging (Explode "waste")- , Recharging Impress- , Recharging (DropItem 1 maxBound COrgan "temporary condition") ]- ++ ieffects necklace- }-necklace3 = necklace- { iaspects = [Timeout $ (1 `d` 3 + 4 - 1 `dl` 3) * 5]- , ieffects = [ ELabel "of fearful listening"- , Recharging (DetectActor 20)- , Recharging (RefillCalm (-20)) ]- ++ ieffects necklace- }-necklace4 = necklace- { iaspects = [Timeout $ (1 `d` 4 + 4 - 1 `dl` 4) * 2]- , ieffects = [Recharging (Teleport $ 3 `d` 2)]- ++ ieffects necklace- }-necklace5 = necklace- { iaspects = [Timeout $ (1 `d` 3 + 4 - 1 `dl` 3) * 10]- , ieffects = [ ELabel "of escape"- , Recharging (Teleport $ 14 + 3 `d` 3)- , Recharging (DetectExit 20)- , Recharging (RefillHP (-2)) ] -- prevent micromanagement- ++ ieffects necklace- }-necklace6 = necklace- { iaspects = [Timeout $ (1 `d` 3 + 1) * 2]- , ieffects = [Recharging (PushActor (ThrowMod 100 50))]- ++ ieffects necklace- }-necklace7 = necklace- { ifreq = [("treasure", 100)]- , iaspects = [ AddMaxHP $ 10 + 1 `d` 10- , AddArmorMelee 20, AddArmorRanged 10- , Timeout $ 1 `d` 2 + 5 - 1 `dl` 3 ]- , ieffects = [ Unique, ELabel "of Overdrive", EqpSlot EqpSlotAddSpeed- , Recharging (InsertMove $ 1 + 1 `d` 2)- , Recharging (RefillHP (-1))- , Recharging (RefillCalm (-1)) ] -- fake "hears something" :)- ++ ieffects necklace- , ifeature = Durable : ifeature necklace- -- , idesc = ""- }-necklace8 = necklace- { iaspects = [Timeout $ (1 `d` 3 + 3 - 1 `dl` 3) * 5]- , ieffects = [Recharging $ Explode "spark"]- ++ ieffects necklace- }-necklace9 = necklace- { iaspects = [Timeout $ (1 `d` 3 + 3 - 1 `dl` 3) * 5]- , ieffects = [Recharging $ Explode "fragrance"]- ++ ieffects necklace- }---- * Non-periodic jewelry--imageItensifier = ItemKind- { isymbol = symbolRing- , iname = "noctovisor"- , ifreq = [("treasure", 100), ("add nocto 1", 80)]- , iflavour = zipFancy [BrGreen]- , icount = 1- , irarity = [(7, 2), (10, 2)]- , iverbHit = "rattle"- , iweight = 700- , idamage = toDmg 0- , iaspects = [AddNocto 1, AddSight (-1), AddArmorMelee $ (1 + 1 `dl` 3) * 3]- , ieffects = [EqpSlot EqpSlotMiscBonus]- , ifeature = [Precious, Identified, Durable, Equipable]- , idesc = "Sturdy antique night vision goggles of unknown origin. Wired to run on modern micro-cells."- , ikit = []- }-sightSharpening = ItemKind- { isymbol = symbolRing- , iname = "Autozoom Contact Lens"- , ifreq = [("treasure", 10), ("add sight", 1)] -- not unique, so very rare- , iflavour = zipPlain [White]- , icount = 1- , irarity = [(7, 1), (10, 5)]- , iverbHit = "rap"- , iweight = 50- , idamage = toDmg 0- , iaspects = [AddSight $ 1 + 1 `d` 2, AddHurtMelee $ (1 `d` 2) * 3]- , ieffects = [EqpSlot EqpSlotAddSight]- , ifeature = [Precious, Identified, Durable, Equipable]- , idesc = "Zooms on any movement, distant or close. Requires some getting used to. Never needs to be taken off."- , ikit = []- }--- Don't add standard effects to rings, because they go in and out--- of eqp and so activating them would require UI tedium: looking for--- them in eqp and inv or even activating a wrong item by mistake.------ However, rings have the explosion effect.--- They explode on use (and throw), for the fun of hitting everything--- around without the risk of being hit. In case of teleportation explosion--- this can also be used to immediately teleport close friends, as opposed--- to throwing the ring, which takes time.------ Rings should have @Identified@, so that they fully identify upon picking up.--- Effects of many of them are seen in character sheet, so it would be silly--- not to identify them. Necklaces provide the fun of id-by-use, because they--- have effects and when they are triggered, they id.-ring = ItemKind- { isymbol = symbolRing- , iname = "ring"- , ifreq = [("useful", 100)]- , iflavour = zipPlain stdCol ++ zipFancy darkCol- , icount = 1- , irarity = [(10, 3)]- , iverbHit = "knock"- , iweight = 15- , idamage = toDmg 0- , iaspects = []- , ieffects = []- , ifeature = [Precious, Identified, Equipable]- , idesc = "A sturdy ring with a softly shining eye. If it contains a body booster unit, beware of the side-effects."- , ikit = []- }-ring1 = ring- { irarity = [(10, 2)]- , iaspects = [AddSpeed $ 1 + 1 `d` 2, AddMaxHP $ 1 `dl` 7 - 7 - 1 `d` 7]- , ieffects = [ Explode "distortion" -- high power- , EqpSlot EqpSlotAddSpeed ]- }-ring2 = ring- { irarity = [(10, 8)]- , iaspects = [AddMaxHP $ 10 + 1 `dl` 10, AddMaxCalm $ 1 `dl` 5 - 20 - 1 `d` 5]- , ieffects = [Explode "blast 20", EqpSlot EqpSlotAddMaxHP]- }-ring3 = ring- { irarity = [(10, 3)]- , iaspects = [AddMaxCalm $ 29 + 1 `dl` 10]- , ieffects = [Explode "blast 20", EqpSlot EqpSlotMiscBonus]- , idesc = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."- }-ring4 = ring- { irarity = [(3, 3), (10, 5)]- , iaspects = [ AddHurtMelee $ (1 `d` 5 + 1 `dl` 5) * 3- , AddMaxHP $ 1 `dl` 3 - 5 - 1 `d` 3 ]- , ieffects = [Explode "blast 20", EqpSlot EqpSlotAddHurtMelee]- }-ring5 = ring -- by the time it's found, probably no space in eqp- { irarity = [(5, 0), (10, 2)]- , iaspects = [AddShine $ 1 `d` 2]- , ieffects = [ Explode "distortion" -- high power- , EqpSlot EqpSlotLightSource ]- , idesc = "A sturdy ring with a large, shining stone."- }-ring6 = ring- { ifreq = [("treasure", 100)]- , irarity = [(10, 2)]- , iaspects = [ AddSpeed $ 3 + 1 `d` 4- , AddMaxCalm $ - 20 - 1 `d` 20, AddMaxHP $ - 20 - 1 `d` 20 ]- , ieffects = [ Unique, ELabel "of Rush" -- no explosion, because Durable- , EqpSlot EqpSlotAddSpeed ]- , ifeature = Durable : ifeature ring- -- , idesc = ""- }-ring7 = ring- { ifreq = [("useful", 10), ("ring of opportunity sniper", 1) ]- , irarity = [(10, 5)]- , iaspects = [AddAbility AbProject 8]- , ieffects = [ ELabel "of opportunity sniper"- , Explode "distortion" -- high power- , EqpSlot EqpSlotAbProject ]- }-ring8 = ring- { ifreq = [("useful", 1), ("ring of opportunity grenadier", 1) ]- , irarity = [(1, 1)]- , iaspects = [AddAbility AbProject 11]- , ieffects = [ ELabel "of opportunity grenadier"- , Explode "distortion" -- high power- , EqpSlot EqpSlotAbProject ]- }---- * Armor--armorLeather = ItemKind- { isymbol = symbolTorsoArmor- , iname = "spacesuit breastplate"- , ifreq = [("useful", 100), ("torso armor", 1)]- , iflavour = zipPlain [Brown]- , icount = 1- , irarity = [(1, 9), (10, 3)]- , iverbHit = "thud"- , iweight = 7000- , idamage = toDmg 0- , iaspects = [ AddHurtMelee (-2)- , AddArmorMelee $ (1 + 1 `d` 2 + 1 `dl` 2) * 5- , AddArmorRanged $ (1 `dl` 3) * 3 ]- , ieffects = [EqpSlot EqpSlotAddArmorMelee]- , ifeature = [Durable, Identified, Equipable]- , idesc = "A hard-shell torso segment cut from a disposed off spacesuit."- , ikit = []- }-armorMail = armorLeather- { iname = "bulletproof vest"- , ifreq = [("useful", 100), ("torso armor", 1), ("armor ranged", 50) ]- , iflavour = zipPlain [Cyan]- , irarity = [(6, 9), (10, 3)]- , iweight = 12000- , idamage = toDmg 0- , iaspects = [ AddHurtMelee (-3)- , AddArmorMelee $ (1 + 1 `d` 2 + 1 `dl` 2) * 5- , AddArmorRanged $ (2 + 1 `d` 2 + 1 `dl` 3) * 3 ]- , ieffects = [EqpSlot EqpSlotAddArmorRanged]- , ifeature = [Durable, Identified, Equipable]- , idesc = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow."- }-gloveFencing = ItemKind- { isymbol = symbolMiscArmor- , iname = "construction glove"- , ifreq = [("useful", 100), ("armor ranged", 50)]- , iflavour = zipPlain [BrYellow]- , icount = 1- , irarity = [(5, 9), (10, 9)]- , iverbHit = "flap"- , iweight = 100- , idamage = toDmg $ 1 `d` 1- , iaspects = [ AddHurtMelee $ (1 `d` 2 + 1 `dl` 7) * 3- , AddArmorRanged $ (1 `dl` 2) * 3 ]- , ieffects = [EqpSlot EqpSlotAddHurtMelee]- , ifeature = [ toVelocity 50 -- flaps and flutters- , Durable, Identified, Equipable ]- , idesc = "A flexible construction glove from rough leather ensuring a good grip. Also, quite effective in deflecting or even catching slow projectiles."- , ikit = []- }-gloveGauntlet = gloveFencing- { iname = "spacesuit glove"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [BrCyan]- , irarity = [(1, 9), (10, 3)]- , iweight = 300- , idamage = toDmg $ 2 `d` 1- , iaspects = [ AddArmorMelee $ (2 + 1 `dl` 2) * 5- , AddArmorRanged $ (1 `dl` 1) * 3 ]- , ieffects = [EqpSlot EqpSlotAddArmorMelee]- , idesc = "A piece of a hull maintenance spacesuit, padded and reinforced with carbon fibre."- }-gloveJousting = gloveFencing- { iname = "Welding Handgear"- , ifreq = [("useful", 100)]- , iflavour = zipFancy [BrRed]- , irarity = [(1, 3), (10, 3)]- , iweight = 1000- , idamage = toDmg $ 3 `d` 1- , iaspects = [ AddHurtMelee $ (1 `dl` 4 - 6) * 3- , AddArmorMelee $ (2 + 1 `d` 2 + 1 `dl` 2) * 5- , AddArmorRanged $ (1 `dl` 2) * 3 ]- , ieffects = [Unique, EqpSlot EqpSlotAddArmorMelee]- , idesc = "Rigid, bulky handgear embedding a welding equipment, complete with an affixed small shield and a darkened visor. Awe-inspiring."- }---- * Shields---- Shield doesn't protect against ranged attacks to prevent--- micromanagement: walking with shield, melee without.--- Note that AI will pick them up but never wear and will use them at most--- as a way to push itself (but they won't recharge, not being in eqp).--- Being @Meleeable@ they will not be use as weapons either.--- This is OK, using shields smartly is totally beyond AI.-buckler = ItemKind- { isymbol = symbolShield- , iname = "buckler"- , ifreq = [("useful", 100)]- , iflavour = zipPlain [Blue]- , icount = 1- , irarity = [(4, 6)]- , iverbHit = "bash"- , iweight = 2000- , idamage = [(96, 2 `d` 1), (3, 4 `d` 1), (1, 8 `d` 1)]- , iaspects = [ AddArmorMelee 40 -- not enough to compensate; won't be in eqp- , AddHurtMelee (-30) -- too harmful; won't be wielded as weapon- , Timeout $ (1 `d` 3 + 3 - 1 `dl` 3) * 2 ]- , ieffects = [ Recharging (PushActor (ThrowMod 200 50))- , EqpSlot EqpSlotAddArmorMelee ]- , ifeature = [ toVelocity 50 -- unwieldy to throw- , Durable, Identified, Meleeable ]- , idesc = "Heavy and unwieldy arm protection made from an outer airlock panel. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with."- , ikit = []- }-shield = buckler- { iname = "shield"- , irarity = [(8, 3)]- , iflavour = zipPlain [Green]- , iweight = 3000- , idamage = [(96, 4 `d` 1), (3, 8 `d` 1), (1, 16 `d` 1)]- , iaspects = [ AddArmorMelee 80 -- not enough to compensate; won't be in eqp- , AddHurtMelee (-70) -- too harmful; won't be wielded as weapon- , Timeout $ (1 `d` 6 + 6 - 1 `dl` 6) * 2 ]- , ieffects = [ Recharging (PushActor (ThrowMod 400 50))- , EqpSlot EqpSlotAddArmorMelee ]- , ifeature = [ toVelocity 50 -- unwieldy to throw- , Durable, Identified, Meleeable ]- , idesc = "Large and unwieldy rectangle made of anti-meteorite ceramic sheet. Absorbs a percentage of melee damage, both dealt and sustained. Too heavy to intercept projectiles with."- }---- * Weapons--dagger = ItemKind- { isymbol = symbolEdged- , iname = "cleaver"- , ifreq = [("useful", 100), ("starting weapon", 100)]- , iflavour = zipPlain [BrCyan]- , icount = 1- , irarity = [(3 * 10/12, 50), (4 * 10/12, 1)]- , iverbHit = "stab"- , iweight = 1000- , idamage = toDmg $ 6 `d` 1- , iaspects = [ AddHurtMelee $ (1 `d` 3 + 1 `dl` 3) * 3- , AddArmorMelee $ (1 `d` 2) * 5 ]- , ieffects = [EqpSlot EqpSlotWeapon]- , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed- , Durable, Identified, Meleeable ]- , idesc = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."- , ikit = []- }-daggerDropBestWeapon = dagger- { iname = "Double Dagger"- , ifreq = [("treasure", 20)]- , irarity = [(1, 1), (10, 4)]- -- The timeout has to be small, so that the player can count on the effect- -- occuring consistently in any longer fight. Otherwise, the effect will be- -- absent in some important fights, leading to the feeling of bad luck,- -- but will manifest sometimes in fights where it doesn't matter,- -- leading to the feeling of wasted power.- -- If the effect is very powerful and so the timeout has to be significant,- -- let's make it really large, for the effect to occur only once in a fight:- -- as soon as the item is equipped, or just on the first strike.- , iaspects = iaspects dagger ++ [Timeout $ (1 `d` 3 + 4 - 1 `dl` 3) * 2]- , ieffects = ieffects dagger- ++ [ Unique- , Recharging DropBestWeapon, Recharging $ RefillCalm (-3) ]- , idesc = "A knife with a forked blade that a focused fencer can use to catch and twist an opponent's weapon occasionally."- }-hammer = ItemKind- { isymbol = symbolHafted- , iname = "demolition hammer"- , ifreq = [("useful", 100), ("starting weapon", 100)]- , iflavour = zipFancy [BrMagenta] -- avoid "pink"- , icount = 1- , irarity = [(3 * 10/12, 3), (5, 20), (8, 1)]- -- don't make it too common on lvl 3- , iverbHit = "club"- , iweight = 1600- , idamage = [(96, 8 `d` 1), (3, 12 `d` 1), (1, 16 `d` 1)]- , iaspects = [AddHurtMelee $ (1 `d` 2 + 1 `dl` 2) * 3]- , ieffects = [EqpSlot EqpSlotWeapon]- , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed- , Durable, Identified, Meleeable ]- , idesc = "A hammer on a long handle used for construction work. It may not cause grave wounds, but neither does it ricochet or glance off armor. Great sidearm for opportunistic blows against armored foes."- , ikit = []- }-hammerParalyze = hammer- { iname = "Concussion Hammer"- , ifreq = [("treasure", 20)]- , irarity = [(5, 1), (10, 6)]- , idamage = toDmg $ 8 `d` 1- , iaspects = iaspects hammer ++ [Timeout $ (1 `d` 2 + 3 - 1 `dl` 2) * 2]- , ieffects = ieffects hammer ++ [Unique, Recharging $ Paralyze 10]- -- , idesc = ""- }-hammerSpark = hammer- { iname = "Grand Smithhammer"- , ifreq = [("treasure", 20)]- , irarity = [(5, 1), (10, 6)]- , idamage = toDmg $ 12 `d` 1- , iaspects = iaspects hammer- ++ [AddShine 3, Timeout $ (1 `d` 4 + 4 - 1 `dl` 4) * 2]- , ieffects = ieffects hammer ++ [Unique, Recharging $ Explode "spark"]- -- , idesc = ""- }-sword = ItemKind- { isymbol = symbolPolearm- , iname = "sharpened pipe"- , ifreq = [("useful", 100), ("starting weapon", 10)]- , iflavour = zipPlain [BrBlue]- , icount = 1- , irarity = [(4, 1), (5, 15)]- , iverbHit = "slash"- , iweight = 2000- , idamage = toDmg $ 10 `d` 1- , iaspects = []- , ieffects = [EqpSlot EqpSlotWeapon]- , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed- , Durable, Identified, Meleeable ]- , idesc = "A makeshift weapon of simple design, but great potential. Hard to master, though."- , ikit = []- }-swordImpress = sword- { isymbol = symbolEdged- , iname = "Master's Sword"- , ifreq = [("treasure", 20)]- , irarity = [(5, 1), (10, 6)]- , iaspects = [Timeout $ (1 `d` 4 + 5 - 1 `dl` 4) * 2]- , ieffects = ieffects sword ++ [Unique, Recharging Impress]- }-swordNullify = sword- { isymbol = symbolEdged- , iname = "Gutting Sword"- , ifreq = [("treasure", 20)]- , irarity = [(5, 1), (10, 6)]- , iaspects = [Timeout $ (1 `d` 4 + 5 - 1 `dl` 4) * 2]- , ieffects = ieffects sword- ++ [ Unique- , Recharging $ DropItem 1 maxBound COrgan- "temporary condition"- , Recharging $ RefillCalm (-10) ]- }-halberd = ItemKind- { isymbol = symbolPolearm- , iname = "pole cleaver"- , ifreq = [("useful", 100), ("starting weapon", 20)]- , iflavour = zipPlain [BrYellow]- , icount = 1- , irarity = [(8, 1), (9, 40)]- , iverbHit = "impale"- , iweight = 3000- , idamage = [(96, 12 `d` 1), (3, 18 `d` 1), (1, 24 `d` 1)]- , iaspects = [ AddHurtMelee (-20) -- just benign enough to be used- , AddArmorMelee $ (1 + 1 `dl` 3) * 5 ]- , ieffects = [EqpSlot EqpSlotWeapon]- , ifeature = [ toVelocity 20 -- not balanced- , Durable, Identified, Meleeable ]- , idesc = "An improvised but deadly weapon made of a long, sharp kitchen knife glued and bound to a long pole."- , ikit = []- }-halberdPushActor = halberd- { iname = "Swiss Halberd"- , ifreq = [("treasure", 20)]- , irarity = [(8, 1), (9, 20)]- , idamage = toDmg $ 12 `d` 1- , iaspects = iaspects halberd ++ [Timeout $ (1 `d` 5 + 5 - 1 `dl` 5) * 2]- , ieffects = ieffects halberd- ++ [Unique, Recharging (PushActor (ThrowMod 400 25))]- , idesc = "A perfect replica made for a reenactor troupe, missing only some sharpening. Versatile, with great reach and leverage. Foes are held at a distance."- }---- * Wands--wand = ItemKind- { isymbol = symbolWand- , iname = "injector"- , ifreq = [("useful", 100)]- , iflavour = zipFancy brightCol- , icount = 1- , irarity = []- , iverbHit = "club"- , iweight = 300- , idamage = toDmg 0- , iaspects = [AddShine 1, AddSpeed (-1)] -- pulsing with power, distracts- , ieffects = []- , ifeature = [ toVelocity 125 -- sufficiently advanced tech- , Applicable, Durable ]- , idesc = "Buzzing with dazzling light that shines even through appendages that handle it."- , ikit = []- }-wand1 = wand- { ieffects = [] -- will be: emit a cone of sound shrapnel that makes enemy cover his ears and so drop '|' and '{'- }-wand2 = wand- { ieffects = []- }---- * Treasure--gem = ItemKind- { isymbol = symbolGold- , iname = "gem"- , ifreq = [("treasure", 100), ("gem", 100)]- , iflavour = zipPlain $ delete BrYellow brightCol -- natural, so not fancy- , icount = 1- , irarity = []- , iverbHit = "tap"- , iweight = 50- , idamage = toDmg 0- , iaspects = [AddShine 1, AddSpeed (-1)]- -- reflects strongly, distracts; so it glows in the dark,- -- is visible on dark floor, but not too tempting to wear- , ieffects = [RefillCalm (-1)] -- minor effect to ensure no id-on-pickup- , ifeature = [Precious] -- no @Identified@, so kind not known- , idesc = "Precious, though useless. Worth around 100 gold grains."- , ikit = []- }-gem1 = gem- { irarity = [(3, 0), (10, 24)]- }-gem2 = gem- { irarity = [(5, 0), (10, 28)]- }-gem3 = gem- { irarity = [(7, 0), (10, 32)]- }-gem4 = gem- { irarity = [(9, 0), (10, 100)]- }-gem5 = gem- { isymbol = symbolSpecial- , iname = "stimpack"- , iflavour = zipPlain [BrYellow]- , irarity = [(1, 40), (10, 40)]- , iaspects = []- , ieffects = [ELabel "of youth", RefillCalm 5, RefillHP 15]- , ifeature = [Identified, Applicable, Precious]- , idesc = "Calms, heals, invigorates and rejuvenates at the same time. No side-effects. As valuable as precious gems, at 100 gold grains each."- }-currency = ItemKind- { isymbol = symbolGold- , iname = "gold grain"- , ifreq = [("treasure", 100), ("currency", 100)]- , iflavour = zipPlain [BrYellow]- , icount = 10 + 1 `d` 20 + 1 `dl` 20- , irarity = [(1, 25), (10, 10)]- , iverbHit = "tap"- , iweight = 1- , idamage = toDmg 0- , iaspects = []- , ieffects = []- , ifeature = [Identified, Precious]- , idesc = "Reliably valuable in every civilized place."- , ikit = []- }---- * Allure-specific--needle = ItemKind- { isymbol = symbolProjectile- , iname = "needle"- , ifreq = [("needle", 1)] -- special; TODO: fast when fired, not thrown- , iflavour = zipPlain [BrBlue]- , icount = 9 `d` 3- , irarity = [(1, 1)]- , iverbHit = "prick"- , iweight = 3- , idamage = toDmg $ 1 `d` 1- , iaspects = [AddHurtMelee $ -10 * 5]- , ieffects = []- , ifeature = [toVelocity 70, Fragile]- , idesc = "A long hypodermic needle ending in a dried out micro-syringe. It's too light to throw hard, but it penetrates deeply, causing intense pain on movement."- , ikit = []- }-constructionHooter = scroll- { iname = "construction hooter"- , ifreq = [("useful", 1), ("construction hooter", 1)] -- extremely rare- , iflavour = zipPlain [BrRed]- , irarity = [(1, 1)]- , iaspects = []- , ieffects = [Summon "construction robot" $ 1 + 1 `dl` 2]- , ifeature = Identified : ifeature scroll- , idesc = "The single-use electronic overdrive hooter that construction robots use to warn about danger and call help in extreme emergency."- , ikit = []+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history)+-- This file is a part of the computer game Allure of the Stars+-- and is released under the terms of the GNU Affero General Public License.+-- For license and copyright information, see the file LICENSE.+--+-- | Item definitions.+module Content.ItemKind+ ( content, items, otherItemContent+ ) where++import Prelude ()++import Game.LambdaHack.Common.Prelude++import Content.ItemKindActor+import Content.ItemKindBlast+import Content.ItemKindEmbed+import Content.ItemKindOrgan+import Content.ItemKindTemporary+import Game.LambdaHack.Common.Ability+import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..), EqpSlot (..))+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.ItemKind++content :: [ItemKind]+content = items ++ otherItemContent++otherItemContent :: [ItemKind]+otherItemContent = embeds ++ actors ++ organs ++ blasts ++ temporaries++items :: [ItemKind]+items =+ [sandstoneRock, dart, spike, spike2, slingStone, slingBullet, paralizingProj, harpoon, harpoon2, net, light1, light2, light3, blanket, flaskTemplate, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potionTemplate, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, fragmentationBomb, concussionBomb, flashBomb, firecrackerBomb, scrollTemplate, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklaceTemplate, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ringTemplate, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, shield2, shield3, dagger, daggerDropBestWeapon, hammer, hammer2, hammer3, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberd2, halberd3, halberdPushActor, wandTemplate, wand1, gemTemplate, gem1, gem2, gem3, gem4, gem5, currencyTemplate, currency]+ -- Allure-specific+ ++ [needle, constructionHooter, scroll14]++sandstoneRock, dart, spike, spike2, slingStone, slingBullet, paralizingProj, harpoon, harpoon2, net, light1, light2, light3, blanket, flaskTemplate, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, flask15, flask16, flask17, flask18, flask19, flask20, potionTemplate, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, fragmentationBomb, concussionBomb, flashBomb, firecrackerBomb, scrollTemplate, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, scroll12, scroll13, jumpingPole, sharpeningTool, seeingItem, motionScanner, gorget, necklaceTemplate, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, imageItensifier, sightSharpening, ringTemplate, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, shield2, shield3, dagger, daggerDropBestWeapon, hammer, hammer2, hammer3, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberd2, halberd3, halberdPushActor, wandTemplate, wand1, gemTemplate, gem1, gem2, gem3, gem4, gem5, currencyTemplate, currency :: ItemKind+-- Allure-specific+needle, constructionHooter, scroll14 :: ItemKind++-- Keep the dice rolls and sides in aspects small so that not too many+-- distinct items are generated (for display in item lore and for narrative+-- impact ("oh, I found the more powerful of the two variants of the item!",+-- instead of "hmm, I found one of the countless variants, a decent one").+-- In particular, for unique items, unless they inherit aspects from+-- a standard item, permit only a couple possible variants.+-- This is especially important if an item kind has mulitple random aspects.+-- Instead multiply dice results, e.g., (1 `d` 3) * 5 instead of 1 `d` 15.+--+-- Beware of non-periodic non-weapon durable items with beneficial effects+-- and low timeout -- AI will starve applying such an item incessantly.++-- * Item group symbols, from Angband and variants++symbolProjectile, _symbolLauncher, symbolLight, symbolTool, symbolSpecial, symbolGold, symbolNecklace, symbolRing, symbolPotion, symbolFlask, symbolScroll, symbolTorsoArmor, symbolMiscArmor, _symbolClothes, symbolShield, symbolPolearm, symbolEdged, symbolHafted, symbolWand, _symbolStaff, symbolFood :: Char++symbolProjectile = '{'+_symbolLauncher = '}'+symbolLight = '('+symbolTool = ')'+symbolSpecial = '*' -- don't overuse, because it clashes with projectiles+symbolGold = '$' -- also gems+symbolNecklace = '"'+symbolRing = '='+symbolPotion = '!' -- concoction, bottle, jar, vial, canister+symbolFlask = '!'+symbolScroll = '?' -- book, note, tablet, remote, chip, card+symbolTorsoArmor = '['+symbolMiscArmor = '['+_symbolClothes = '['+symbolShield = ']'+symbolPolearm = '/'+symbolEdged = '|'+symbolHafted = '\\'+symbolWand = '-' -- magical rod, transmitter, pistol, rifle, instrument+_symbolStaff = '_' -- scanner+symbolFood = ',' -- also body part; distinct from floor: not middle dot++-- * Thrown weapons++sandstoneRock = ItemKind+ { isymbol = symbolProjectile+ , iname = "ceramic foam splinter"+ , ifreq = [("sandstone rock", 1), ("weak arrow", 10)]+ , iflavour = zipPlain [Green]+ , icount = 1 `d` 2+ , irarity = [(1, 50), (10, 1)]+ , iverbHit = "hit"+ , iweight = 300+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ -16 * 5]+ , ieffects = []+ , ifeature = [toVelocity 70, Fragile] -- not dense, irregular+ , idesc = "A light, irregular lump of ceramic foam used in construction."+ , ikit = []+ }+dart = ItemKind+ { isymbol = symbolProjectile+ , iname = "billiard ball"+ , ifreq = [("common item", 100), ("any arrow", 50), ("weak arrow", 50)]+ , iflavour = zipPlain [BrWhite]+ , icount = 4 `dL` 5+ , irarity = [(1, 20), (10, 10)]+ , iverbHit = "strike"+ , iweight = 170+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ (-15 + 1 `d` 2 + 1 `dL` 3) * 5]+ -- only leather-piercing+ , ieffects = []+ , ifeature = []+ , idesc = "Ideal shape, size and weight for throwing."+ , ikit = []+ }+spike = ItemKind+ { isymbol = symbolProjectile+ , iname = "steak knife"+ , ifreq = [("common item", 100), ("any arrow", 50), ("weak arrow", 50)]+ , iflavour = zipPlain [Cyan]+ , icount = 4 `dL` 5+ , irarity = [(1, 10), (10, 15)]+ , iverbHit = "nick"+ , iweight = 100+ , idamage = 2 `d` 1+ , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dL` 3) * 5]+ -- heavy vs armor+ , ieffects = [ Explode "single spark" -- when hitting enemy+ , OnSmash (Explode "single spark") ] -- at wall hit+ -- this results in a wordy item synopsis, but it's OK, the spark really+ -- is useful in some situations, not just a flavour+ , ifeature = [MinorEffects, toVelocity 70] -- hitting with tip costs speed+ , idesc = "Not particularly well balanced, but with a laser-sharpened titanium tip and blade."+ , ikit = []+ }+spike2 = spike+ { ifreq = [("common item", 2), ("any arrow", 1), ("weak arrow", 1)]+ , iweight = 150+ , idamage = 4 `d` 1+ -- , idesc = ""+ }+slingStone = ItemKind+ { isymbol = symbolProjectile+ , iname = "steel hex nut"+ , ifreq = [("common item", 5), ("any arrow", 100)]+ , iflavour = zipPlain [Blue]+ , icount = 3 `dL` 4+ , irarity = [(1, 1), (10, 20)]+ , iverbHit = "hit"+ , iweight = 200+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dL` 3) * 5]+ -- heavy vs armor+ , ieffects = [ Explode "single spark" -- when hitting enemy+ , OnSmash (Explode "single spark") ] -- at wall hit+ , ifeature = [MinorEffects, toVelocity 150]+ , idesc = "A large hexagonal fastening nut; due to its angular shape, securely lodging in the pouch of a makeshift string and cloth sling."+ , ikit = []+ }+slingBullet = ItemKind+ { isymbol = symbolProjectile+ , iname = "bearing ball"+ , ifreq = [("common item", 5), ("any arrow", 100)]+ , iflavour = zipPlain [White]+ , icount = 6 `dL` 4+ , irarity = [(1, 1), (10, 15)]+ , iverbHit = "hit"+ , iweight = 28+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ (-17 + 1 `d` 2 + 1 `dL` 3) * 5]+ -- not armor-piercing+ , ieffects = []+ , ifeature = [toVelocity 200]+ , idesc = "Small but heavy bearing ball. Thanks to its size and shape, it doesn't snag when released from the makeshift sling's pouch."+ , ikit = []+ }++-- * Exotic thrown weapons++-- Identified, because shape (and name) says it all. Detailed stats id by use.+paralizingProj = ItemKind+ { isymbol = symbolProjectile+ , iname = "can"+ , ifreq = [("common item", 100), ("can of sticky foam", 1)]+ , iflavour = zipPlain [Magenta]+ , icount = 1 `dL` 4+ , irarity = [(5, 5), (10, 20)]+ , iverbHit = "glue"+ , iweight = 1000+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ -14 * 5]+ , ieffects = [Paralyze 15, OnSmash (Explode "glue") ]+ , ifeature = [ ELabel "of sticky foam"+ , toVelocity 70, Lobable, Fragile ] -- unwieldy+ , idesc = "A can of liquid, fast-setting construction foam."+ , ikit = []+ }+harpoon = ItemKind+ { isymbol = symbolProjectile+ , iname = "harpoon"+ , ifreq = [("curious item", 100), ("harpoon", 100)]+ , iflavour = zipPlain [Brown]+ , icount = 1 `dL` 5+ , irarity = [(5, 5), (10, 5)]+ , iverbHit = "hook"+ , iweight = 750+ , idamage = 5 `d` 1+ , iaspects = [AddHurtMelee $ (-10 + 1 `d` 2 + 1 `dL` 3) * 5]+ , ieffects = [PullActor (ThrowMod 200 50)]+ , ifeature = []+ , idesc = "A display piece harking back to the Earth's oceanic tourism heyday. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying."+ , ikit = []+ }+harpoon2 = harpoon+ { ifreq = [("curious item", 2), ("harpoon", 2)]+ , iweight = 1000+ , idamage = 10 `d` 1+ -- , idesc = "" -- perhaps something modern for a change? some sharpened cargo hook?+ }+net = ItemKind+ { isymbol = symbolProjectile+ , iname = "net"+ , ifreq = [("common item", 100)]+ , iflavour = zipPlain [White]+ , icount = 1 `dL` 3+ , irarity = [(3, 5), (10, 4)]+ , iverbHit = "entangle"+ , iweight = 1000+ , idamage = 2 `d` 1+ , iaspects = [AddHurtMelee $ -14 * 5]+ , ieffects = [ toOrganBad "slowed" (3 + 1 `d` 3)+ , DropItem maxBound 1 CEqp "torso armor"+ , SendFlying (ThrowMod 100 50) ] -- make the drop painful+ -- only one of each kind is dropped, because no rubbish in this group+ , ifeature = []+ , idesc = "A large synthetic fibre net with weights affixed along the edges. Entangles armor and restricts movement."+ , ikit = []+ }++-- * Lights++light1 = ItemKind+ { isymbol = symbolLight+ , iname = "torch"+ , ifreq = [("common item", 100), ("light source", 100), ("wooden torch", 1)]+ , iflavour = zipPlain [Brown]+ , icount = 1 `dL` 4+ , irarity = [(1, 15)]+ , iverbHit = "scorch"+ , iweight = 1000+ , idamage = 0+ , iaspects = [ AddShine 3 -- not only flashes, but also sparks,+ , AddSight (-2) ] -- so unused by AI due to the mixed blessing+ , ieffects = [Burn 1]+ , ifeature = [Lobable, Equipable, EqpSlot EqpSlotLightSource]+ -- not Fragile; reusable flare+ , idesc = "A torch improvised with cloth soaked in tar on a stick."+ , ikit = []+ }+light2 = ItemKind+ { isymbol = symbolLight+ , iname = "oil lamp"+ , ifreq = [("common item", 100), ("light source", 100)]+ , iflavour = zipPlain [BrYellow]+ , icount = 1 `dL` 2+ , irarity = [(6, 8)]+ , iverbHit = "burn"+ , iweight = 1500+ , idamage = 1 `d` 1+ , iaspects = [AddShine 3, AddSight (-1)]+ , ieffects = [Burn 1, Paralyze 6, OnSmash (Explode "burning oil 3")]+ , ifeature = [Lobable, Fragile, Equipable, EqpSlot EqpSlotLightSource ]+ , idesc = "A sizable restaurant glass lamp filled with plant oil feeding a wick."+ , ikit = []+ }+light3 = ItemKind+ { isymbol = symbolLight+ , iname = "crank spotlight"+ , ifreq = [("common item", 100), ("light source", 100)]+ , iflavour = zipPlain [BrWhite]+ , icount = 1+ , irarity = [(10, 4)]+ , iverbHit = "snag"+ , iweight = 3000+ , idamage = 0+ , iaspects = [ AddShine 4+ , AddArmorRanged $ - 1 `d` 3 ] -- noise and distraction+ , ieffects = []+ , ifeature = [Equipable, EqpSlot EqpSlotLightSource]+ , idesc = "Powerful, wide-beam spotlight, powered by a hand-crank. Requires noisy two-handed recharging every few minutes."+ , ikit = []+ }+blanket = ItemKind+ { isymbol = symbolLight+ , iname = "mineral fibre blanket"+ , ifreq = [("common item", 100), ("light source", 100), ("blanket", 1)]+ , iflavour = zipPlain [BrBlack]+ , icount = 1+ , irarity = [(1, 3)]+ , iverbHit = "swoosh"+ , iweight = 1000+ , idamage = 0+ , iaspects = [ AddShine (-10) -- douses torch, lamp and lantern in one action+ , AddArmorMelee 1, AddMaxCalm 2 ]+ , ieffects = []+ , ifeature = [Lobable, Equipable] -- not Fragile; reusable douse+ , idesc = ""+ , ikit = []+ }++-- * Exploding consumables, often intended to be thrown.++-- Not identified, because they are perfect for the id-by-use fun,+-- due to effects. They are fragile and upon hitting the ground explode+-- for effects roughly corresponding to their normal effects.+-- Whether to hit with them or explode them close to the tartget+-- is intended to be an interesting tactical decision.+--+-- Flasks are often not natural; maths, magic, distillery.+-- In reality, they just cover all conditions, which in turn matches+-- all aspects.+--+-- There is no flask nor temporary organ of Calm depletion,+-- because Calm reduced often via combat, etc..++flaskTemplate = ItemKind+ { isymbol = symbolFlask+ , iname = "flask"+ , ifreq = [("flask unknown", 1)]+ , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol+ ++ zipLiquid brightCol+ , icount = 1 `dL` 3+ , irarity = [(1, 7), (10, 3)]+ , iverbHit = "splash"+ , iweight = 500+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [ HideAs "flask unknown", Lobable, Fragile+ , toVelocity 50 ] -- oily, bad grip+ , idesc = "A flask of oily liquid of a suspect color. Something seems to be moving inside."+ , ikit = []+ }+flask1 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(10, 5)]+ , ieffects = [ toOrganGood "strengthened" (20 + 1 `d` 5)+ , toOrganNoTimer "regenerating"+ , OnSmash (Explode "dense shower") ]+ , ifeature = [ELabel "of strength renewal brew"] ++ ifeature flaskTemplate+ }+flask2 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganBad "weakened" (20 + 1 `d` 5)+ , OnSmash (Explode "sparse shower") ]+ , ifeature = [ELabel "of weakness brew"] ++ ifeature flaskTemplate+ }+flask3 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganGood "protected from melee" (20 + 1 `d` 5)+ , OnSmash (Explode "melee protective balm") ]+ , ifeature = [ELabel "of melee protective balm"] ++ ifeature flaskTemplate+ }+flask4 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganGood "protected from ranged" (20 + 1 `d` 5)+ , OnSmash (Explode "ranged protective balm") ]+ , ifeature = [ELabel "of ranged protective balm"] ++ ifeature flaskTemplate+ }+flask5 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganBad "painted red" (20 + 1 `d` 5)+ , OnSmash (Explode "red paint") ]+ , ifeature = [ELabel "of red paint"] ++ ifeature flaskTemplate+ }+flask6 = flaskTemplate+ { ifreq = []+ }+flask7 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , icount = 1 -- too poweful en masse+ , ieffects = [ toOrganGood "hasted" (20 + 1 `d` 5)+ , OnSmash (Explode "haste spray") ]+ , ifeature = [ELabel "of haste brew"] ++ ifeature flaskTemplate+ }+flask8 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(1, 12), (10, 2)]+ , ieffects = [ toOrganBad "slowed" (20 + 1 `d` 5)+ , toOrganNoTimer "regenerating", toOrganNoTimer "regenerating" -- x2+ , RefillCalm 5+ , OnSmash (Explode "slowness mist")+ , OnSmash (Explode "youth sprinkle") ]+ , ifeature = [ELabel "of lethargy brew"] ++ ifeature flaskTemplate+ }+flask9 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganGood "far-sighted" (40 + 1 `d` 10)+ , OnSmash (Explode "eye drop") ]+ , ifeature = [ELabel "of eye drops"] ++ ifeature flaskTemplate+ }+flask10 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(10, 2)] -- not very useful right now+ , ieffects = [ toOrganGood "keen-smelling" (40 + 1 `d` 10)+ , Detect DetectActor 10+ , OnSmash (Explode "smelly droplet") ]+ , ifeature = [ELabel "of smelly concoction"] ++ ifeature flaskTemplate+ }+flask11 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(10, 2)] -- not very useful right now+ , ieffects = [ toOrganGood "shiny-eyed" (40 + 1 `d` 10)+ , OnSmash (Explode "eye shine") ]+ , ifeature = [ELabel "of cat tears"] ++ ifeature flaskTemplate+ }+flask12 = flaskTemplate+ { iname = "bottle"+ , ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , icount = 1 `d` 3 -- the only one sometimes giving away its identity+ , ieffects = [ toOrganGood "drunk" (20 + 1 `d` 5)+ , Burn 1, RefillHP 3+ , OnSmash (Explode "whiskey spray") ]+ , ifeature = [ELabel "of whiskey"] ++ ifeature flaskTemplate+ }+flask13 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , icount = 1+ , ieffects = [ toOrganGood "drunk" (20 + 1 `d` 5)+ , Burn 1, RefillHP 3+ , Summon "mobile animal" 1+ , OnSmash (Summon "mobile animal" 1)+ , OnSmash Impress+ , OnSmash (Explode "waste") ]+ , ifeature = [ELabel "of bait cocktail"] ++ ifeature flaskTemplate+ }+-- The player has full control over throwing the flask at his party,+-- so he can milk the explosion, so it has to be much weaker, so a weak+-- healing effect is enough. OTOH, throwing a harmful flask at many enemies+-- at once is not easy to arrange, so these explostions can stay powerful.+flask14 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(1, 2), (10, 10)]+ , ieffects = [ toOrganNoTimer "regenerating", toOrganNoTimer "regenerating" -- x2+ , OnSmash (Explode "youth sprinkle") ]+ , ifeature = [ELabel "of regeneration brew"] ++ ifeature flaskTemplate+ }+flask15 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganNoTimer "poisoned", toOrganNoTimer "poisoned" -- x2+ , OnSmash (Explode "poison cloud") ]+ , ifeature = [ELabel "of poison"] ++ ifeature flaskTemplate+ }+flask16 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganNoTimer "poisoned"+ , OnSmash (Explode "poison cloud") ]+ , ifeature = [ELabel "of weak poison"] ++ ifeature flaskTemplate+ }+flask17 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(10, 3)]+ , ieffects = [ toOrganNoTimer "slow resistant"+ , OnSmash (Explode "anti-slow mist") ]+ , ifeature = [ELabel "of slow resistance"] ++ ifeature flaskTemplate+ }+flask18 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , irarity = [(10, 3)]+ , ieffects = [ toOrganNoTimer "poison resistant"+ , OnSmash (Explode "antidote mist") ]+ , ifeature = [ELabel "of poison resistance"] ++ ifeature flaskTemplate+ }+flask19 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganBad "blind" (40 + 1 `d` 10)+ , OnSmash (Explode "iron filing") ]+ , ifeature = [ELabel "of blindness"] ++ ifeature flaskTemplate+ }+flask20 = flaskTemplate+ { ifreq = [("common item", 100), ("explosive", 100), ("any vial", 100)]+ , ieffects = [ toOrganNoTimer "poisoned"+ , toOrganBad "weakened" (20 + 1 `d` 5)+ , toOrganBad "painted red" (20 + 1 `d` 5)+ , OnSmash (Explode "glass hail") ] -- enough glass to cause that+ , ifeature = [ELabel "of calamity"] ++ ifeature flaskTemplate+ }++-- Potions are often natural. Appear deeper than most flasks. Various+-- configurations of effects. A different class of effects is on scrolls+-- and mechanical items. Some are shared.++potionTemplate = ItemKind+ { isymbol = symbolPotion+ , iname = "vial"+ , ifreq = [("potion unknown", 1)]+ , iflavour = zipLiquid brightCol ++ zipPlain brightCol ++ zipFancy brightCol+ , icount = 1 `dL` 3+ , irarity = [(1, 10), (10, 6)]+ , iverbHit = "splash"+ , iweight = 200+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [ HideAs "potion unknown", Lobable, Fragile+ , toVelocity 50 ] -- oily, bad grip+ , idesc = "A vial of bright, frothing concoction. The best that nature has to offer."+ , ikit = []+ }+potion1 = potionTemplate+ { iname = "vial"+ , ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , icount = 3 `dL` 1 -- very useful, despite appearances+ , ieffects = [ Impress, RefillCalm (-5)+ , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ]+ , ifeature = [ELabel "of rose water"] ++ ifeature potionTemplate+ }+potion2 = potionTemplate+ { ifreq = [("curious item", 100)]+ , icount = 1+ , irarity = [(5, 8), (10, 8)]+ , ieffects = [ Impress, RefillCalm (-20)+ , OnSmash (Explode "pheromone") ]+ , ifeature = [Unique, ELabel "of Attraction"]+ ++ [ Lobable, Fragile -- identified+ , toVelocity 50 ]+ -- , idesc = ""+ }+potion3 = potionTemplate+ { ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , ieffects = [ RefillHP 5, DropItem 1 maxBound COrgan "poisoned"+ , OnSmash (Explode "healing mist") ]+ }+potion4 = potionTemplate+ { ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , irarity = [(1, 6), (10, 9)]+ , ieffects = [ RefillHP 10, DropItem 1 maxBound COrgan "poisoned"+ , OnSmash (Explode "healing mist 2") ]+ }+potion5 = potionTemplate+ -- needs to be common to show at least a portion of effects+ { ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , icount = 3 `dL` 1 -- always as many as possible on this level+ -- without giving away potion identity+ , irarity = [(1, 10)]+ , ieffects = [ OneOf [ RefillHP 10, RefillHP 5, Burn 5+ , DropItem 1 maxBound COrgan "poisoned"+ , toOrganGood "strengthened" (20 + 1 `d` 5) ]+ , OnSmash (OneOf [ Explode "dense shower"+ , Explode "sparse shower"+ , Explode "melee protective balm"+ , Explode "ranged protective balm"+ , Explode "red paint" ]) ]+ }+potion6 = potionTemplate+ -- needs to be common to show at least a portion of effects+ { ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , icount = 3 `dL` 1+ , irarity = [(10, 8)]+ , ieffects = [ Impress+ , OneOf [ RefillCalm (-60)+ , RefillHP 20, RefillHP 10, Burn 10+ , DropItem 1 maxBound COrgan "poisoned"+ , toOrganGood "hasted" (20 + 1 `d` 5) ]+ , OnSmash (OneOf [ Explode "healing mist 2"+ , Explode "wounding mist"+ , Explode "distressing odor"+ , Explode "haste spray"+ , Explode "slowness mist"+ , Explode "fragrance"+ , Explode "violent flash" ]) ]+ }+potion7 = potionTemplate+ { ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , ieffects = [ DropItem 1 maxBound COrgan "poisoned"+ , OnSmash (Explode "antidote mist") ]+ }+potion8 = potionTemplate+ { iname = "ampoule" -- filled with semi-stabilized high explosive liquid+ , ifreq = [("common item", 100), ("potion", 100), ("any vial", 100)]+ , icount = 3 `dL` 1+ , ieffects = [ DropItem 1 maxBound COrgan "condition"+ , OnSmash (Explode "violent concussion") ]+ -- not fragmentation nor glass hail, because not enough glass+ }+potion9 = potionTemplate+ { ifreq = [("curious item", 100)]+ , icount = 1+ , irarity = [(10, 5)]+ , ieffects = [ RefillHP 60, Impress, RefillCalm (-60)+ , OnSmash (Explode "healing mist 2")+ , OnSmash (Explode "pheromone") ]+ , ifeature = [Unique, ELabel "of Love"]+ ++ [ Lobable, Fragile -- identified+ , toVelocity 50 ]+ -- , idesc = ""+ }++-- * Explosives, with the only effect being @Explode@++fragmentationBomb = ItemKind+ { isymbol = symbolProjectile+ , iname = "hand bomb"+ -- improvised bomb filled with iron pellets, nuts, cut nails;+ -- deflagration, not detonation, so large mass and hard container+ -- required not to burn harmlessly; improvised short fuze;+ -- can't be more powerful or would fracture the spaceship's hull+ , ifreq = [("common item", 100), ("explosive", 200)]+ , iflavour = zipPlain [Red]+ , icount = 1 `dL` 4 -- many, because not very intricate+ , irarity = [(5, 5), (10, 5)]+ , iverbHit = "thud"+ , iweight = 3000 -- low velocity due to weight+ , idamage = 1 `d` 1 -- heavy and hard+ , iaspects = []+ , ieffects = [ Explode "focused fragmentation"+ , OnSmash (Explode "violent fragmentation") ]+ , ifeature = [Lobable, Fragile]+ , idesc = ""+ -- given that we now have several kinds of explosives, tell something+ -- related to 'fragmentation', e.g., mention flying metal bits+ , ikit = []+ }+concussionBomb = fragmentationBomb+ { iname = "canister"+ -- slightly stabilized liquid explosive in a soft container, hence+ -- no fragmentation, but huge shock wave despite small size and lack+ -- of strong container to build up pressure; indoors help the shock wave;+ -- unstable enough that no fuze required (or simple electric fuse?);+ -- that's the most potent explosive (a detonating one) to be found+ -- and only in small quantities, due to depressurization hazard+ , iflavour = zipPlain [Magenta]+ , iverbHit = "flap"+ , iweight = 400+ , idamage = 0+ , ieffects = [ Explode "focused concussion"+ , OnSmash (Explode "violent concussion") ]+ , ifeature = [ Lobable, Fragile+ , toVelocity 70 ] -- flappy and so slow+ , idesc = ""+ }+-- Not flashbang, because powerful bang without fragmentation is harder+-- to manufacture (requires an oxidizer and steel canister with holes)+-- and because we don't model hearing adequately yet. The bang would also+-- paralyze and/or lower the movement skill (out of balance due to ear trauma).+flashBomb = fragmentationBomb+ { iname = "powder tube" -- filled with magnesium flash powder+ , iflavour = zipPlain [BrWhite]+ , iverbHit = "flash"+ , iweight = 400+ , idamage = 0+ , ieffects = [Explode "focused flash", OnSmash (Explode "violent flash")]+ , ifeature = [Lobable, Fragile, toVelocity 70] -- bad shape for throwing+ , idesc = ""+ }+firecrackerBomb = fragmentationBomb+ { iname = "roll" -- not fireworks, as they require outdoors+ , iflavour = zipPlain [BrMagenta]+ , irarity = [(1, 5), (5, 5)] -- a toy, if deadly+ , iverbHit = "crack" -- a pun, matches the verb from "ItemKindBlast"+ , iweight = 1000+ , idamage = 0+ , ieffects = [Explode "firecracker", OnSmash (Explode "firecracker")]+ , ifeature = [Lobable, Fragile]+ , idesc = "String and paper, concealing a deadly surprise."+ }++-- * Non-exploding consumables, not specifically designed for throwing++scrollTemplate = ItemKind+ { isymbol = symbolScroll+ , iname = "chip"+ , ifreq = [("scroll unknown", 1)]+ , iflavour = zipFancy stdCol ++ zipPlain darkCol -- arcane and old+ , icount = 1 `dL` 3+ , irarity = [(1, 14), (10, 7)]+ , iverbHit = "thump"+ , iweight = 20+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [ HideAs "scroll unknown"+ , toVelocity 30 ] -- too small+ , idesc = "A generic, disposable chip, capable of a one-time holo-display. Some of these also contain a one-time password authorizing a particular spaceship's infrastructure transition. It is unknown how the infrastructure might respond after so many years."+ , ikit = []+ }+scroll1 = scrollTemplate+ { ifreq = [("curious item", 100), ("any scroll", 100)]+ , icount = 1+ , irarity = [(5, 9), (10, 9)] -- mixed blessing, so available early, often+ , ieffects = [Summon "hero" 1, Summon "mobile animal" (2 + 1 `d` 2)]+ , ifeature = [Unique, ELabel "of Reckless Beacon"] ++ ifeature scrollTemplate+ , idesc = "This industrial, wide-spectrum alarm broadcaster, if over-amped for a single powerful blast, should be able to cut through the interference and reach any lost crew members, giving them enough positional information to locate us."+ }+scroll2 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , irarity = [(1, 2)] -- mixed blessing+ , ieffects = [Detect DetectItem 20, Teleport 20, RefillCalm (-100)]+ , ifeature = [ELabel "of greed"] ++ ifeature scrollTemplate+ }+scroll3 = scrollTemplate+ { ifreq = [("curious item", 100), ("any scroll", 100)]+ , irarity = [(1, 4), (10, 2)]+ , ieffects = [Ascend True]+ }+scroll4 = scrollTemplate+ -- needs to be common to show at least a portion of effects+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , icount = 3 `dL` 1+ , irarity = [(1, 14)]+ , ieffects = [OneOf [ Teleport 5, Paralyze 10, InsertMove 10+ , Detect DetectEmbed 12, Detect DetectItem 20 ]]+ }+scroll5 = scrollTemplate+ -- needs to be common to show at least a portion of effects+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , icount = 3 `dL` 1+ , irarity = [(10, 11)]+ , ieffects = [ Impress+ , OneOf [ Teleport 20, Ascend False, Ascend True+ , Summon "hero" 1, Summon "mobile animal" $ 1 `d` 2+ , Detect DetectAll 40, RefillCalm (-100)+ , CreateItem CGround "common item" timerNone ] ]+ }+scroll6 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , ieffects = [Teleport 5]+ }+scroll7 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , ieffects = [Teleport 20]+ }+scroll8 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , icount = 1 -- too poweful en masse+ , irarity = [(10, 4)]+ , ieffects = [InsertMove $ 1 + 1 `d` 2 + 1 `dL` 2]+ }+scroll9 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , icount = 3 `dL` 1+ , irarity = [(1, 14)] -- uncommon deep down, where all is known+ , ieffects = [Composite [Identify, RefillCalm 10]]+ , ifeature = [ELabel "of scientific explanation"] ++ ifeature scrollTemplate+ , idesc = "The most pressing existential concerns are met with a deeply satisfying scientific answer."+ }+scroll10 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , irarity = [(10, 20)] -- at endgame a crucial item may be missing+ , ieffects = [Composite [PolyItem, Explode "firecracker"]]+ , ifeature = [ELabel "of molecular reconfiguration"]+ ++ ifeature scrollTemplate+ }+scroll11 = scrollTemplate+ { ifreq = [("curious item", 100), ("any scroll", 100)]+ , icount = 1+ , irarity = [(5, 8), (10, 8)]+ , ieffects = [Summon "hero" 1]+ , ifeature = [Unique, ELabel "of Rescue Proclamation"]+ ++ ifeature scrollTemplate+ , idesc = "This lock chip opens a nearby closet containing one of our lost crew members."+ }+scroll12 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , irarity = [(1, 9), (10, 4)]+ , ieffects = [Detect DetectHidden 20]+ }+scroll13 = scrollTemplate+ { ifreq = [("common item", 100), ("any scroll", 100)]+ , ieffects = [Detect DetectActor 20]+ , ifeature = [ELabel "of acute hearing"] ++ ifeature scrollTemplate+ }++-- * Assorted tools++jumpingPole = ItemKind+ { isymbol = symbolWand+ , iname = "jumping pole"+ , ifreq = [("common item", 100)]+ , iflavour = zipPlain [White]+ , icount = 1+ , irarity = [(1, 3)]+ , iverbHit = "prod"+ , iweight = 10000+ , idamage = 0+ , iaspects = [Timeout $ (2 + 1 `d` 2 - 1 `dL` 2) * 5]+ , ieffects = [Recharging (toOrganGood "hasted" 1)]+ -- safe for AI, because it speeds up, so when AI applies it+ -- again and again, it gets its time back and is not stuck;+ -- in total, the explorations speed is unchanged,+ -- but it's useful when fleeing in the dark to make distance+ -- and when initiating combat, so it's OK that AI uses it+ , ifeature = [Durable]+ , idesc = "Makes you vulnerable at take-off, but then you are free like a bird."+ , ikit = []+ }+sharpeningTool = ItemKind+ { isymbol = symbolTool+ , iname = "honing steel"+ , ifreq = [("common item", 100)]+ , iflavour = zipPlain [Blue]+ , icount = 1+ , irarity = [(10, 10)]+ , iverbHit = "smack"+ , iweight = 400+ , idamage = 0+ , iaspects = [AddHurtMelee $ (1 `dL` 5) * 5]+ , ieffects = []+ , ifeature = [Equipable, EqpSlot EqpSlotAddHurtMelee]+ , idesc = "Originally used for realigning the chipped 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 = symbolFood+ , iname = "visual sensor"+ , ifreq = [("common item", 100)]+ , iflavour = zipPlain [Red]+ , icount = 1+ , irarity = [(1, 1)]+ , iverbHit = "gaze at"+ , iweight = 500+ , idamage = 0+ , iaspects = [ AddSight 10, AddMaxCalm 30, AddShine 2+ , Timeout $ 1 + 1 `d` 2 ]+ , ieffects = [ Recharging (toOrganNoTimer "poisoned")+ , Recharging (Summon "mobile robot" 1) ]+ , ifeature = [Periodic]+ , idesc = "A functioning visual sensor torn out from some sizable robot. The circuitry seem too large for basic signal processing alone. Watch out for the sharp edges and the seeping coolant liquid."+ , ikit = []+ }+motionScanner = ItemKind+ { isymbol = symbolTool+ , iname = "handhelp sonar"+ , ifreq = [("common item", 100), ("add nocto 1", 20)]+ , iflavour = zipPlain [Green]+ , icount = 1+ , irarity = [(5, 2)]+ , iverbHit = "ping"+ , iweight = 1000+ , idamage = 0+ , iaspects = [ AddNocto 1+ , AddArmorMelee (-10 + 1 `dL` 5)+ , AddArmorRanged (-10 + 1 `dL` 5) ]+ , ieffects = []+ , ifeature = [Equipable, EqpSlot EqpSlotMiscBonus]+ , idesc = "Handheld underwater echolocator overdriven to scan dark corridors at the cost of emitting loud pings."+ , ikit = []+ }++-- * Periodic jewelry++gorget = necklaceTemplate+ { iname = "Old Gorget"+ , ifreq = [("common item", 25), ("treasure", 25)]+ , iflavour = zipFancy [BrCyan] -- looks exactly the same as on of necklaces,+ -- but it's OK, it's an artifact+ , irarity = [(4, 3), (10, 3)] -- weak, shallow+ , iaspects = [ Timeout $ (1 `d` 2) * 2+ , AddArmorMelee 3+ , AddArmorRanged 2 ]+ , ieffects = [Recharging (RefillCalm 1)]+ , ifeature = [Unique, Durable, EqpSlot EqpSlotMiscBonus]+ ++ ifeature necklaceTemplate+ , 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."+ }+-- Not idenfified, because id by use, e.g., via periodic activations. Fun.+necklaceTemplate = ItemKind+ { isymbol = symbolNecklace+ , iname = "necklace"+ , ifreq = [("necklace unknown", 1)]+ , iflavour = zipFancy stdCol ++ zipPlain brightCol+ , icount = 1+ , irarity = [(10, 2)]+ , iverbHit = "whip"+ , iweight = 30+ , idamage = 0+ , iaspects = [Timeout 1] -- fake, but won't be displayed+ , ieffects = []+ , ifeature = [ Periodic, HideAs "necklace unknown", Precious, Equipable+ , toVelocity 50 ] -- not dense enough+ , idesc = "Tingling, rattling chain of flat encrusted links. Eccentric millionaires are known to hide their highly personalized body augmentation packs in such large jewelry pieces."+ , ikit = []+ }+necklace1 = necklaceTemplate+ { ifreq = [("curious item", 100), ("any jewelry", 100)]+ , irarity = [(3, 0), (4, 1), (10, 2)] -- prevents camping on lvl 3+ , iaspects = [Timeout $ (1 `d` 2) * 20]+ , ieffects = [Recharging (RefillHP 1)] ++ ieffects necklaceTemplate+ , ifeature = [ Unique, ELabel "of Trickle Life", Durable+ , EqpSlot EqpSlotMiscBonus ]+ ++ ifeature necklaceTemplate+ -- , idesc = ""+ }+necklace2 = necklaceTemplate+ { ifreq = [("treasure", 100), ("any jewelry", 100)]+ -- too nasty to call it just a "common item"+ , iaspects = [Timeout 30]+ , ieffects = [ Recharging (Summon "mobile animal" $ 1 `d` 2)+ , Recharging (Explode "waste")+ , Recharging Impress+ , Recharging (DropItem 1 maxBound COrgan "condition") ]+ ++ ieffects necklaceTemplate+ , ifeature = [Unique, ELabel "of Live Bait", Durable]+ ++ ifeature necklaceTemplate+ -- , idesc = ""+ }+necklace3 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ (1 `d` 2) * 20]+ , ieffects = [ Recharging (Detect DetectActor 10)+ , Recharging (RefillCalm (-20)) ]+ ++ ieffects necklaceTemplate+ , ifeature = [ELabel "of fearful listening"] ++ ifeature necklaceTemplate+ }+necklace4 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ (3 + 1 `d` 3 - 1 `dL` 3) * 2]+ , ieffects = [Recharging (Teleport $ 3 `d` 2)]+ ++ ieffects necklaceTemplate+ }+necklace5 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ (7 - 1 `dL` 5) * 10]+ , ieffects = [ Recharging (Teleport $ 14 + 3 `d` 3)+ , Recharging (Detect DetectExit 20)+ , Recharging (RefillHP (-2)) ] -- prevent micromanagement+ ++ ieffects necklaceTemplate+ , ifeature = [ELabel "of escape"] ++ ifeature necklaceTemplate+ }+necklace6 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ 1 + (1 `d` 3) * 2]+ , ieffects = [Recharging (PushActor (ThrowMod 100 50))] -- 1 step, slow+ -- the @50@ is only for the case of very light actor, etc.+ ++ ieffects necklaceTemplate+ }+necklace7 = necklaceTemplate+ { ifreq = [("curious item", 100), ("any jewelry", 100)]+ , iaspects = [AddMaxHP 15, AddArmorMelee 20, AddArmorRanged 10, Timeout 4]+ , ieffects = [ Recharging (InsertMove $ 1 `d` 3) -- unpredictable+ , Recharging (RefillCalm (-1)) -- fake "hears something" :)+ , Recharging (RefillHP (-1)) ]+ ++ ieffects necklaceTemplate+ , ifeature = [Unique, ELabel "of Overdrive", Durable, EqpSlot EqpSlotAddSpeed]+ ++ ifeature necklaceTemplate+ -- , idesc = ""+ }+necklace8 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ (1 + 1 `d` 3) * 5]+ , ieffects = [Recharging $ Explode "spark"]+ ++ ieffects necklaceTemplate+ }+necklace9 = necklaceTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , iaspects = [Timeout $ (1 + 1 `d` 3) * 5]+ , ieffects = [Recharging $ Explode "fragrance"]+ ++ ieffects necklaceTemplate+ }++-- * Non-periodic jewelry++imageItensifier = ItemKind+ { isymbol = symbolRing+ , iname = "noctovisor"+ , ifreq = [("treasure", 100), ("add nocto 1", 80)]+ , iflavour = zipFancy [BrGreen]+ , icount = 1+ , irarity = [(5, 2)]+ , iverbHit = "rattle"+ , iweight = 700+ , idamage = 0+ , iaspects = [AddNocto 1, AddSight (-1), AddArmorMelee $ (1 `dL` 3) * 3]+ , ieffects = []+ , ifeature = [Precious, Durable, Equipable, EqpSlot EqpSlotMiscBonus]+ , idesc = "Sturdy antique night vision goggles of unknown origin. Wired to run on modern micro-cells."+ , ikit = []+ }+sightSharpening = ringTemplate -- small and round, so mistaken for a ring+ { iname = "Autozoom Contact Lens"+ , ifreq = [("treasure", 10), ("add sight", 1)]+ -- it's has to be very rare, because it's powerful and not unique,+ -- and also because it looks exactly as one of necklaces, so it would+ -- be misleading when seen on the map+ , irarity = [(7, 1), (10, 5)] -- low @ifreq@+ , iweight = 50 -- heavier that it looks, due to glass+ , iaspects = [AddSight $ 1 + 1 `d` 2, AddHurtMelee $ (1 `d` 2) * 3]+ , ifeature = [EqpSlot EqpSlotAddSight] ++ ifeature ringTemplate+ , idesc = "Zooms on any movement, distant or close. Requires some getting used to. Never needs to be taken off."+ }+-- Don't add standard effects to rings, because they go in and out+-- of eqp and so activating them would require UI tedium: looking for+-- them in eqp and inv or even activating a wrong item by mistake.+--+-- By general mechanisms, due to not having effects that could identify+-- them by observing the effect, rings are identified on pickup.+-- That's unlike necklaces, which provide the fun of id-by-use, because they+-- have effects and when the effects are triggered, they get identified.+ringTemplate = ItemKind+ { isymbol = symbolRing+ , iname = "ring"+ , ifreq = [("ring unknown", 1)]+ , iflavour = zipPlain stdCol ++ zipFancy darkCol+ , icount = 1+ , irarity = [(10, 1)] -- the default very low+ , iverbHit = "knock"+ , iweight = 15+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [HideAs "ring unknown", Precious, Equipable]+ , idesc = "A sturdy ring with a softly shining eye. If it contains a body booster unit, beware of the side-effects."+ , ikit = []+ }+ring1 = ringTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , irarity = [(10, 4)]+ , iaspects = [AddSpeed $ 1 `d` 3, AddMaxHP (-15)]+ , ieffects = [OnSmash (Explode "distortion")] -- high power+ , ifeature = [EqpSlot EqpSlotAddSpeed] ++ ifeature ringTemplate+ }+ring2 = ringTemplate+ { ifreq = [("curious item", 100), ("any jewelry", 100)]+ , irarity = [(10, 2)]+ , iaspects = [AddSpeed $ (1 `d` 2) * 3, AddMaxCalm (-40), AddMaxHP (-20)]+ , ieffects = [OnSmash (Explode "distortion")] -- high power+ , ifeature = [Unique, ELabel "of Rush", Durable, EqpSlot EqpSlotAddSpeed]+ ++ ifeature ringTemplate+ -- , idesc = ""+ }+ring3 = ringTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , irarity = [(10, 11)]+ , iaspects = [ AddMaxHP $ 10 + (1 `dL` 5) * 2+ , AddMaxCalm $ -20 + (1 `dL` 5) * 2 ]+ , ifeature = [EqpSlot EqpSlotAddMaxHP] ++ ifeature ringTemplate+ }+ring4 = ringTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , irarity = [(5, 1), (10, 14)] -- needed after other rings drop Calm+ , iaspects = [AddMaxCalm $ 25 + (1 `dL` 4) * 5]+ , ifeature = [EqpSlot EqpSlotMiscBonus] ++ ifeature ringTemplate+ , idesc = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."+ }+ring5 = ringTemplate+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , irarity = [(3, 3), (10, 6)]+ , iaspects = [ AddHurtMelee $ (2 + 1 `d` 2 + (1 `dL` 2) * 2 ) * 3+ , AddMaxHP $ (-2 - (1 `d` 2) + (1 `dL` 2) * 2) * 3 ] -- !!!+ , ifeature = [EqpSlot EqpSlotAddHurtMelee] ++ ifeature ringTemplate+ }+ring6 = ringTemplate -- by the time it's found, probably no space in eqp+ { ifreq = [("common item", 100), ("any jewelry", 100)]+ , irarity = [(5, 0), (10, 4)]+ , iaspects = [AddShine $ 1 `d` 2]+ , ifeature = [EqpSlot EqpSlotLightSource] ++ ifeature ringTemplate+ , idesc = "A sturdy ring with a large, shining stone."+ }+ring7 = ringTemplate+ { ifreq = [("common item", 10), ("ring of opportunity sniper", 1) ]+ , irarity = [(10, 5)] -- low @ifreq@+ , iaspects = [AddAbility AbProject 8]+ , ieffects = [OnSmash (Explode "distortion")] -- high power+ , ifeature = [ELabel "of opportunity sniper", EqpSlot EqpSlotAbProject]+ ++ ifeature ringTemplate+ }+ring8 = ringTemplate+ { ifreq = [("common item", 1), ("ring of opportunity grenadier", 1) ]+ , irarity = [(1, 1)]+ , iaspects = [AddAbility AbProject 11]+ , ieffects = [OnSmash (Explode "distortion")] -- high power+ , ifeature = [ELabel "of opportunity grenadier", EqpSlot EqpSlotAbProject]+ ++ ifeature ringTemplate+ }++-- * Armor++armorLeather = ItemKind+ { isymbol = symbolTorsoArmor+ , iname = "spacesuit breastplate"+ , ifreq = [("common item", 100), ("torso armor", 1)]+ , iflavour = zipPlain [Brown]+ , icount = 1+ , irarity = [(1, 9), (10, 3)]+ , iverbHit = "thud"+ , iweight = 7000+ , idamage = 0+ , iaspects = [ AddHurtMelee (-2)+ , AddArmorMelee $ (2 + 1 `dL` 4) * 5+ , AddArmorRanged $ (1 + 1 `dL` 2) * 3 ]+ , ieffects = []+ , ifeature = [Durable, Equipable, EqpSlot EqpSlotAddArmorMelee]+ , idesc = "A hard-shell torso segment cut from a disposed off spacesuit."+ , ikit = []+ }+armorMail = armorLeather+ { iname = "bulletproof vest"+ , ifreq = [("common item", 100), ("torso armor", 1), ("armor ranged", 50) ]+ , iflavour = zipPlain [Cyan]+ , irarity = [(6, 9), (10, 3)]+ , iweight = 12000+ , idamage = 0+ , iaspects = [ AddHurtMelee (-3)+ , AddArmorMelee $ (2 + 1 `dL` 4) * 5+ , AddArmorRanged $ (4 + 1 `dL` 2) * 3 ]+ , ieffects = []+ , ifeature = [Durable, Equipable, EqpSlot EqpSlotAddArmorRanged]+ , idesc = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow."+ }+gloveFencing = ItemKind+ { isymbol = symbolMiscArmor+ , iname = "construction glove"+ , ifreq = [("common item", 100), ("misc armor", 1), ("armor ranged", 50)]+ , iflavour = zipPlain [BrYellow]+ , icount = 1+ , irarity = [(5, 9), (10, 9)]+ , iverbHit = "flap"+ , iweight = 100+ , idamage = 1 `d` 1+ , iaspects = [ AddHurtMelee $ (2 + 1 `d` 2 + 1 `dL` 2) * 3+ , AddArmorRanged $ (1 `dL` 2) * 3 ]+ , ieffects = []+ , ifeature = [ toVelocity 50 -- flaps and flutters+ , Durable, Equipable, EqpSlot EqpSlotAddHurtMelee ]+ , idesc = "A flexible construction glove from rough leather ensuring a good grip. Also, quite effective in deflecting or even catching slow projectiles."+ , ikit = []+ }+gloveGauntlet = gloveFencing+ { iname = "spacesuit glove"+ , ifreq = [("common item", 100), ("misc armor", 1)]+ , iflavour = zipPlain [BrCyan]+ , irarity = [(1, 9), (10, 3)]+ , iweight = 300+ , idamage = 2 `d` 1+ , iaspects = [AddArmorMelee $ (1 + 1 `dL` 4) * 5]+ , ifeature = [Durable, Equipable, EqpSlot EqpSlotAddArmorMelee]+ , idesc = "A piece of a hull maintenance spacesuit, padded and reinforced with carbon fibre."+ }+gloveJousting = gloveFencing+ { iname = "Welding Handgear"+ , ifreq = [("common item", 100), ("misc armor", 1)]+ , iflavour = zipFancy [BrRed]+ , irarity = [(1, 3), (10, 3)]+ , iweight = 3000+ , idamage = 3 `d` 1+ , iaspects = [ AddHurtMelee $ (-7 + 1 `dL` 5) * 3+ , AddArmorMelee $ (2 + 1 `d` 2 + 1 `dL` 2) * 5+ , AddArmorRanged $ (1 + 1 `dL` 2) * 3 ]+ -- very random on purpose and can even be good on occasion+ , ifeature = [ toVelocity 50 -- flaps and flutters+ , Unique, Durable, Equipable, EqpSlot EqpSlotAddArmorMelee ]+ , idesc = "Rigid, bulky handgear embedding a welding equipment, complete with an affixed small shield and a darkened visor. Awe-inspiring."+ }++-- * Shields++-- Shield doesn't protect against ranged attacks to prevent+-- micromanagement: walking with shield, melee without.+-- Note that AI will pick them up but never wear and will use them at most+-- as a way to push itself (but they won't recharge, not being in eqp).+-- Being @Meleeable@ they will not be use as weapons either.+-- This is OK, using shields smartly is totally beyond AI.+buckler = ItemKind+ { isymbol = symbolShield+ , iname = "buckler"+ , ifreq = [("common item", 100)]+ , iflavour = zipPlain [Blue]+ , icount = 1+ , irarity = [(4, 5)]+ , iverbHit = "bash"+ , iweight = 2000+ , idamage = 2 `d` 1+ , iaspects = [ AddArmorMelee 40 -- not enough to compensate; won't be in eqp+ , AddHurtMelee (-30) -- too harmful; won't be wielded as weapon+ , Timeout $ (3 + 1 `d` 3 - 1 `dL` 3) * 2 ]+ , ieffects = [Recharging (PushActor (ThrowMod 100 50))] -- 1 step, slow+ , ifeature = [ toVelocity 50 -- unwieldy to throw+ , MinorEffects, Durable, Meleeable+ , EqpSlot EqpSlotAddArmorMelee ]+ , idesc = "Heavy and unwieldy arm protection made from an outer airlock panel. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with."+ , ikit = []+ }+shield = buckler+ { iname = "shield"+ , irarity = [(8, 4)] -- the stronger variants add to total probability+ , iflavour = zipPlain [Green]+ , iweight = 4000+ , idamage = 4 `d` 1+ , iaspects = [ AddArmorMelee 80 -- not enough to compensate; won't be in eqp+ , AddHurtMelee (-70) -- too harmful; won't be wielded as weapon+ , Timeout $ (3 + 1 `d` 3 - 1 `dL` 3) * 4 ]+ , ieffects = [Recharging (PushActor (ThrowMod 400 25))] -- 1 step, fast+ , ifeature = [ toVelocity 50 -- unwieldy to throw+ , MinorEffects, Durable, Meleeable+ , EqpSlot EqpSlotAddArmorMelee ]+ , 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."+ }+shield2 = shield+ { ifreq = [("common item", 3 * 3)] -- very low base rarity+ , iweight = 5000+ , idamage = 8 `d` 1+ -- , idesc = ""+ }+shield3 = shield+ { ifreq = [("common item", 1 * 3)] -- very low base rarity+ , iweight = 6000+ , idamage = 12 `d` 1+ -- , idesc = ""+ }++-- * Weapons++dagger = ItemKind+ { isymbol = symbolEdged+ , iname = "cleaver"+ , ifreq = [("common item", 100), ("starting weapon", 100)]+ , iflavour = zipPlain [BrCyan]+ , icount = 1+ , irarity = [(3 * 10/12, 40), (4 * 10/12, 1)]+ -- no weapons brought by aliens, initially, so cleaver common+ , iverbHit = "stab"+ , iweight = 1000+ , idamage = 6 `d` 1+ , iaspects = [ AddHurtMelee $ (-1 + 1 `d` 2 + 1 `dL` 2) * 3+ , AddArmorMelee $ (1 `d` 2) * 5 ]+ -- very common, so don't make too random+ , ieffects = []+ , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed+ , Durable, Meleeable, EqpSlot EqpSlotWeapon ]+ , idesc = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."+ , ikit = []+ }+daggerDropBestWeapon = dagger+ { iname = "Double Dagger"+ , ifreq = [("treasure", 20)]+ , irarity = [(1, 3), (10, 3)]+ -- Here timeout has to be small, if the player is to count on the effect+ -- occuring consistently in any longer fight. Otherwise, the effect will be+ -- absent in some important fights, leading to the feeling of bad luck,+ -- but will manifest sometimes in fights where it doesn't matter,+ -- leading to the feeling of wasted power.+ -- If the effect is very powerful and so the timeout has to be significant,+ -- let's make it really large, for the effect to occur only once in a fight:+ -- as soon as the item is equipped, or just on the first strike.+ -- Here the timeout is either very small or very large, randomly.+ -- In the latter case the weapon is best swapped for a stronger one+ -- later on in the game, but provides some variety at the start.+ , iaspects = iaspects dagger ++ [Timeout $ (1 `d` 2) * 20 - 16]+ , ieffects = ieffects dagger+ ++ [ Recharging DropBestWeapon, Recharging $ RefillCalm (-3) ]+ , ifeature = [Unique] ++ ifeature dagger+ , idesc = "A knife with a forked blade that a focused fencer can use to catch and twist an opponent's weapon occasionally."+ }+hammer = ItemKind+ { isymbol = symbolHafted+ , iname = "demolition hammer"+ , ifreq = [ ("common item", 100), ("starting weapon", 100)+ , ("hammer unknown", 1) ]+ , iflavour = zipFancy [BrMagenta] -- avoid "pink"+ , icount = 1+ , irarity = [(3 * 10/12, 3), (5, 20), (8, 1)]+ -- don't make it too common on lvl 3+ , iverbHit = "club"+ , iweight = 1600+ , idamage = 8 `d` 1 -- we are lying about the dice here, but the dungeon+ -- is too small and the extra-dice hammers too rare+ -- to subdivide this identification class by dice+ , iaspects = [AddHurtMelee $ (-1 + 1 `d` 2 + 1 `dL` 2) * 3]+ , ieffects = []+ , ifeature = [ HideAs "hammer unknown"+ , toVelocity 40 -- ensuring it hits with the tip costs speed+ , Durable, Meleeable, EqpSlot EqpSlotWeapon ]+ , idesc = "One of many kinds of hammers employed in construction work. The ones with completely blunt heads don't cause grave wounds, but any fitted with a long enough handle can shake and bruise even most armored foes. This one looks average at a quick glance." -- if it's really the average, the weak kind, the description stays; if not, it's replaced with one of the descriptions below at identification time+ , ikit = []+ }+hammer2 = hammer+ { ifreq = [("common item", 3), ("starting weapon", 1)]+ , iweight = 2000+ , idamage = 12 `d` 1+ , idesc = "Upon closer inspection, this hammer tuns out particularly deadly, with a narrowing, sharpened head and a long handle."+ }+hammer3 = hammer+ { ifreq = [("common item", 1)]+ , iweight = 2400+ , idamage = 16 `d` 1+ , idesc = "This hammer sports a sharp point instead of a head. No armor can withstand a full strength swing."+ }+hammerParalyze = hammer+ { iname = "Concussion Hammer"+ , ifreq = [("treasure", 20)]+ , irarity = [(5, 1), (10, 6)]+ , idamage = 8 `d` 1+ , iaspects = iaspects hammer ++ [Timeout 7]+ , ieffects = ieffects hammer ++ [Recharging $ Paralyze 10]+ , ifeature = [Unique] ++ ifeature hammer+ , idesc = "This exceptionally large demolition hammer leaves no wall and no body standing."+ }+hammerSpark = hammer+ { iname = "Grand Smithhammer"+ , ifreq = [("treasure", 20)]+ , irarity = [(5, 1), (10, 6)]+ , idamage = 12 `d` 1+ , iaspects = iaspects hammer ++ [AddShine 3, Timeout 10]+ , ieffects = ieffects hammer ++ [Recharging $ Explode "spark"]+ , ifeature = [Unique] ++ ifeature hammer+ , idesc = "High carbon steel of this old hammer doesn't yield even to the newest alloys and produces fountains of sparks in defiance."+ }+sword = ItemKind+ { isymbol = symbolPolearm+ , iname = "sharpened pipe"+ , ifreq = [("common item", 100), ("starting weapon", 10)]+ , iflavour = zipPlain [BrBlue]+ , icount = 1+ , irarity = [(4, 1), (5, 15)]+ , iverbHit = "slash"+ , iweight = 2000+ , idamage = 10 `d` 1+ , iaspects = []+ , ieffects = []+ , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed+ , Durable, Meleeable, EqpSlot EqpSlotWeapon ]+ , idesc = "A makeshift weapon of simple design, but great potential. Hard to master, though."+ , ikit = []+ }+swordImpress = sword+ { isymbol = symbolEdged+ , iname = "Master's Sword"+ , ifreq = [("treasure", 20)]+ , irarity = [(5, 1), (10, 6)]+ , iaspects = [Timeout $ (1 `d` 2) * 40 - 30]+ , ieffects = ieffects sword ++ [Recharging Impress]+ , ifeature = [Unique] ++ ifeature sword+ -- , idesc = ""+ }+swordNullify = sword+ { isymbol = symbolEdged+ , iname = "Gutting Sword"+ , ifreq = [("treasure", 20)]+ , irarity = [(5, 1), (10, 6)]+ , iaspects = [Timeout 10]+ , ieffects = ieffects sword+ ++ [ Recharging+ $ DropItem 1 maxBound COrgan "condition"+ , Recharging $ RefillCalm (-10) ]+ , ifeature = [Unique] ++ ifeature sword+ -- , idesc = ""+ }+halberd = ItemKind+ { isymbol = symbolPolearm+ , iname = "pole cleaver"+ , ifreq = [("common item", 100), ("starting weapon", 20)]+ , iflavour = zipPlain [BrYellow]+ , icount = 1+ , irarity = [(7, 1), (9, 15)]+ , iverbHit = "impale"+ , iweight = 3000+ , idamage = 12 `d` 1+ , iaspects = [ AddHurtMelee (-20) -- useless against armor at game start+ , AddArmorMelee $ (1 `dL` 4) * 5 ]+ , ieffects = []+ , ifeature = [ toVelocity 20 -- not balanced+ , Durable, Meleeable, EqpSlot EqpSlotWeapon ]+ , idesc = "An improvised but deadly weapon made of a long, sharp kitchen knife glued and bound to a long pole."+ , ikit = []+ }+halberd2 = halberd+ { ifreq = [("common item", 3 * 2), ("starting weapon", 1)]+ , iweight = 4000+ , idamage = 18 `d` 1+ -- , idesc = ""+ }+halberd3 = halberd+ { ifreq = [("common item", 1 * 2)] -- compensating for low base rarity+ , iweight = 5000+ , idamage = 24 `d` 1+ -- , idesc = ""+ }+halberdPushActor = halberd+ { iname = "Swiss Halberd"+ , ifreq = [("curious item", 20)]+ , irarity = [(8, 1), (10, 15)]+ , idamage = 12 `d` 1+ , iaspects = iaspects halberd ++ [Timeout $ (1 `d` 2) * 10]+ , ieffects = ieffects halberd+ ++ [Recharging (PushActor (ThrowMod 400 25))] -- 1 step+ , ifeature = [Unique] ++ ifeature halberd+ , idesc = "A perfect replica made for a reenactor troupe, hardened, missing only some final sharpening. Versatile, with great reach and leverage. Foes are held at a distance."+ }++-- * Wands++wandTemplate = ItemKind+ { isymbol = symbolWand+ , iname = "injector"+ , ifreq = [("wand unknown", 1)]+ , iflavour = zipFancy brightCol+ , icount = 1+ , irarity = []+ , iverbHit = "club"+ , iweight = 300+ , idamage = 0+ , iaspects = [AddShine 1, AddSpeed (-1)] -- pulsing with power, distracts+ , ieffects = []+ , ifeature = [ HideAs "wand unknown", Durable+ , toVelocity 125 ] -- sufficiently advanced tech+ , idesc = "Buzzing with dazzling light that shines even through appendages that handle it."+ , ikit = []+ }+wand1 = wandTemplate+ { ifreq = []+ , ieffects = [] -- will be: emit a cone of sound shrapnel that makes enemy cover his ears and so drop '|' and '{'+ }++-- * Treasure++gemTemplate = ItemKind+ { isymbol = symbolGold+ , iname = "gem"+ , ifreq = [("gem unknown", 1), ("valuable", 100)]+ , iflavour = zipPlain $ delete BrYellow brightCol -- natural, so not fancy+ , icount = 1+ , irarity = [(3, 0), (10, 24)]+ , iverbHit = "tap"+ , iweight = 50+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [HideAs "gem unknown", Precious]+ , idesc = "Precious, though useless. Worth around 100 gold grains."+ , ikit = []+ }+gem1 = gemTemplate+ { ifreq = [ ("treasure", 100), ("gem", 100), ("any jewelry", 100)+ , ("valuable", 100) ]+ , irarity = [(3, 0), (10, 24)]+ , iaspects = [AddShine 1, AddSpeed (-1)]+ -- reflects strongly, distracts; so it glows in the dark,+ -- is visible on dark floor, but not too tempting to wear+ , ieffects = [RefillCalm (-1)] -- minor effect to ensure no id-on-pickup+ }+gem2 = gem1+ { ifreq = [ ("treasure", 100), ("gem", 100), ("any jewelry", 100)+ , ("valuable", 100) ]+ , irarity = [(5, 0), (10, 28)]+ }+gem3 = gem1+ { ifreq = [ ("treasure", 100), ("gem", 100), ("any jewelry", 100)+ , ("valuable", 100) ]+ , irarity = [(7, 0), (10, 32)]+ }+gem4 = gem1+ { ifreq = [ ("treasure", 100), ("gem", 100), ("any jewelry", 100)+ , ("valuable", 100) ]+ , irarity = [(9, 0), (10, 100)]+ }+gem5 = gem1+ { isymbol = symbolSpecial+ , iname = "stimpack"+ , ifreq = [ ("treasure", 100), ("gem", 25), ("any jewelry", 25)+ , ("valuable", 100) ]+ , iflavour = zipPlain [BrYellow]+ , irarity = [(1, 40), (10, 40)]+ , ieffects = [RefillCalm 10, RefillHP 40]+ , ifeature = [ELabel "of youth", Precious] -- not hidden+ , idesc = "Calms, heals, invigorates and rejuvenates at the same time. No side-effects. As valuable as precious gems, at 100 gold grains each."+ }+currencyTemplate = ItemKind+ { isymbol = symbolGold+ , iname = "gold grain"+ , ifreq = [("currency unknown", 1), ("valuable", 1)]+ , iflavour = zipPlain [BrYellow]+ , icount = 10 + 1 `d` 20 + 1 `dL` 20+ , irarity = [(1, 25), (10, 10)]+ , iverbHit = "tap"+ , iweight = 1+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [HideAs "currency unknown", Precious]+ , idesc = "Reliably valuable in every civilized place."+ , ikit = []+ }+currency = currencyTemplate+ { ifreq = [("treasure", 100), ("currency", 100), ("valuable", 1)]+ , iaspects = [AddShine 1, AddSpeed (-1)]+ , ieffects = [RefillCalm (-1)]+ }++-- * Allure-specific++needle = ItemKind+ { isymbol = symbolProjectile+ , iname = "needle"+ , ifreq = [("needle", 1)] -- special; TODO: fast when fired, not thrown+ , iflavour = zipPlain [BrBlue]+ , icount = 9 `d` 3+ , irarity = [(1, 1)]+ , iverbHit = "prick"+ , iweight = 3+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ -10 * 5]+ , ieffects = []+ , ifeature = [toVelocity 70, Fragile]+ , idesc = "A long hypodermic needle ending in a dried out micro-syringe. It's too light to throw hard, but it penetrates deeply, causing intense pain on movement."+ , ikit = []+ }+constructionHooter = scrollTemplate+ { iname = "construction hooter"+ , ifreq = [("common item", 1), ("construction hooter", 1)]+ -- extremely rare+ , iflavour = zipPlain [BrRed]+ , irarity = [(1, 1)]+ , iaspects = []+ , ieffects = [Summon "construction robot" $ 1 `dL` 2]+ , ifeature = [] -- not hidden+ , idesc = "The single-use electronic overdrive hooter that construction robots use to warn about danger and call help in extreme emergency."+ , ikit = []+ }+scroll14 = scrollTemplate+ { ifreq = [("treasure", 100)]+ , irarity = [(1, 2), (10, 2)] -- not every playthrough needs it+ , ieffects = [ toOrganGood "resolute" (500 + 1 `d` 200)+ -- a drawback (at least initially) due to @calmEnough@+ , Explode "cruise ad hologram" ]+ , ifeature = [Unique, ELabel "Displaying a Happy Couple"]+ ++ ifeature scrollTemplate+ , idesc = "Biodegradable self-powered mini-projector displaying a holographic ad for an interplanetary cruise." }
GameDefinition/Content/ItemKindActor.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,6 +16,7 @@ import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..)) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind @@ -40,14 +41,15 @@ , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 80 -- partially from clothes and assumed first aid , AddMaxCalm 70, AddSpeed 20, AddNocto 2 , AddAbility AbProject 2, AddAbility AbApply 1 , AddAbility AbAlter 2 ] , ieffects = []- , ifeature = [Durable, Identified]- , idesc = "A hardened veteran of combat."+ , ifeature = [Durable]+ , idesc = ""+ -- , idesc = "A hardened veteran of combat." , ikit = [ ("fist", COrgan), ("foot", COrgan), ("eye 6", COrgan) , ("sapient brain", COrgan) ] }@@ -80,7 +82,9 @@ ranger = warrior { iname = "ranger" , ifreq = [("ranger hero", 100), ("mobile", 1)]- , ikit = ikit warrior ++ [("weak arrow", CInv), ("armor ranged", CEqp)]+ , ikit = ikit warrior+ ++ [ ("armor ranged", CEqp)+ , ("weak arrow", CInv) ] -- , idesc = "" } escapist = warrior@@ -88,10 +92,10 @@ , ifreq = [("escapist hero", 100), ("mobile", 1)] , ikit = ikit warrior ++ [ ("add sight", CEqp)- , ("weak arrow", CInv) -- mostly for probing , ("armor ranged", CEqp)- , ("flask", CInv)+ , ("weak arrow", CInv) -- mostly for probing , ("light source", CInv)+ , ("wooden torch", CInv) , ("blanket", CInv) ] -- , idesc = "" }@@ -100,14 +104,19 @@ , ifreq = [("ambusher hero", 100), ("mobile", 1)] , ikit = ikit warrior -- dark and numerous, so more kit without exploring ++ [ ("ring of opportunity sniper", CEqp)- , ("light source", CEqp), ("wooden torch", CInv)- , ("weak arrow", CInv), ("any arrow", CSha), ("flask", CSha) ]+ , ("any arrow", CSha)+ , ("weak arrow", CInv)+ , ("explosive", CSha)+ , ("light source", CEqp)+ , ("wooden torch", CInv) ] -- , idesc = "" } soldier = warrior { iname = "soldier" , ifreq = [("soldier hero", 100), ("mobile", 1)]- , ikit = ikit warrior ++ [("starting weapon", CEqp)]+ , ikit = ikit warrior+ ++ [ ("starting weapon", CEqp)+ , ("explosive", CSha) ] -- , idesc = "" } @@ -148,13 +157,13 @@ , irarity = [(4, 6), (10, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 20, AddMaxCalm 70, AddSpeed 20, AddNocto 2 , AddAggression 1 , AddAbility AbProject 2, AddAbility AbApply 1 , AddAbility AbAlter 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Walks with a stately dignity. You read death in the slow beckoning gestures of its revolting upper appendages." , ikit = [ ("foot", COrgan), ("tentacle", COrgan) , ("eye 6", COrgan)@@ -162,7 +171,7 @@ } fastEye = ItemKind { isymbol = 'b'- , iname = "crawling biter"+ , iname = "rolling biter" , ifreq = [ ("monster", 100), ("mobile", 1) , ("mobile monster", 100), ("scout monster", 60) ] , iflavour = zipFancy [BrBlue]@@ -170,12 +179,12 @@ , irarity = [(4, 3), (10, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 5, AddMaxCalm 70, AddSpeed 30, AddNocto 2 , AddAggression 1 , AddAbility AbAlter 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "It bites as blindingly fast as it runs. Or rolls? Or crawls? Also, cuts and pierces." , ikit = [ ("tentacle", COrgan), ("jaw", COrgan) , ("eye 3", COrgan), ("speed gland 10", COrgan)@@ -190,12 +199,12 @@ , irarity = [(4, 5), (10, 9)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 16, AddNocto 2 , AddAggression 1 , AddAbility AbProject (-1), AddAbility AbAlter 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "A blind, slimy mass of clawing, stinging and burning. You'd think it's powerless, but as soon as it touches your trembling body, it's always one step ahead." , ikit = [ ("nostril", COrgan), ("small claw", COrgan) , ("tentacle", COrgan), ("tentacle", COrgan)@@ -212,12 +221,12 @@ , irarity = [(6, 1), (10, 9)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 12, AddMaxCalm 80, AddSpeed 21, AddNocto 2 , AddAbility AbProject 2, AddAbility AbApply 1 , AddAbility AbAlter 2, AddAbility AbMelee (-1) ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , 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 8", COrgan)@@ -234,13 +243,13 @@ , irarity = [(11 * 10/12, 0), (12 * 10/12, 1000)] -- unique , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 300, AddMaxCalm 100, AddSpeed 6, AddNocto 2 , AddAggression 3 , AddAbility AbProject 2, AddAbility AbApply 1- , AddAbility AbAlter (-1) ] -- can't switch levels, the boss- , ieffects = [Unique]- , ifeature = [Durable, Identified]+ , AddAbility AbAlter 1] -- can't exit the gated level, the boss+ , ieffects = []+ , ifeature = [Unique, Durable] , 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), ("hooked claw", COrgan) , ("large jaw", COrgan)@@ -267,10 +276,10 @@ , irarity = [(1, 3)] , iverbHit = "thud" , iweight = 13000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 12, AddMaxCalm 70, AddSpeed 24, AddNocto 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "An opportunistic predator, feeding on carrion and the weak." , ikit = [ ("small jaw", COrgan), ("eye 6", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ]@@ -285,7 +294,7 @@ , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 13000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 12, AddMaxCalm 80, AddSpeed 22, AddNocto 2 , AddAbility AbAlter (-2) ] -- can't use stairs nor doors -- Animals don't have leader, usually, so even if only one of level,@@ -293,7 +302,7 @@ -- them on par with human leaders moving solo. Random double moves, -- on either side, are just too frustrating. , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "It soars high above, searching for vulnerable prey." , ikit = [ ("screeching beak", COrgan) -- in reality it grunts and hisses , ("small claw", COrgan), ("eye 7", COrgan)@@ -308,11 +317,11 @@ , irarity = [(1, 5), (10, 3)] , iverbHit = "thud" , iweight = 4000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 22, AddNocto 2 , AddAbility AbAlter (-2) ] -- can't use stairs nor doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Its only defence is the terrible stench." , ikit = [ ("scent gland", COrgan) , ("small claw", COrgan), ("snout", COrgan)@@ -328,11 +337,11 @@ , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20, AddNocto 2 , AddAbility AbAlter (-2) ] -- can't use stairs nor doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "When threatened, it rolls into a ball." , ikit = [ ("hooked claw", COrgan), ("snout", COrgan) , ("armored skin", COrgan), ("armored skin", COrgan)@@ -348,11 +357,11 @@ , irarity = [(2, 5), (10, 3)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 12, AddMaxCalm 50, AddSpeed 18, AddNocto 2 , AddAbility AbAlter (-2) ] -- can't use stairs nor doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Numbing venom ensures that even the fastest prey has no escape." , ikit = [ ("venom tooth", COrgan), ("small claw", COrgan) , ("eye 3", COrgan), ("nostril", COrgan)@@ -367,11 +376,11 @@ , irarity = [(5, 1), (10, 12)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 25, AddMaxCalm 60, AddSpeed 16, AddNocto 2 , AddAbility AbAlter (-2) ] -- can't use stairs nor doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Beware its rattle - it serves as a warning of an agonising death." , ikit = [ ("venom fang", COrgan) , ("eye 4", COrgan), ("nostril", COrgan)@@ -386,10 +395,10 @@ , irarity = [(9, 0), (10, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 18, AddNocto 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Larger and more aggressive than any other lizard." , ikit = [ ("large tail", COrgan), ("jaw", COrgan) , ("hooked claw", COrgan), ("speed gland 4", COrgan)@@ -406,10 +415,10 @@ , irarity = [(4, 1), (10, 8)] , iverbHit = "thud" , iweight = 60000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 20, AddMaxCalm 70, AddSpeed 32, AddNocto 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Skulking in the shadows, waiting for easy prey." , ikit = [ ("jaw", COrgan), ("eye 6", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ]@@ -423,10 +432,10 @@ , irarity = [(8, 1), (10, 9)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 41, AddMaxCalm 70, AddSpeed 18, AddNocto 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "An armored predator from the dawn of time." , ikit = [ ("large jaw", COrgan), ("large tail", COrgan) , ("small claw", COrgan)@@ -442,15 +451,15 @@ , irarity = [(1 * 10/12, 1000000), (2 * 10/12, 0)] -- unique , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 90, AddMaxCalm 60, AddSpeed 27, AddNocto 2 , AddAggression 2 , AddAbility AbAlter (-1) ] -- can't switch levels, a miniboss- , ieffects = [Unique]- , ifeature = [Durable, Identified]+ , ieffects = []+ , ifeature = [Unique, Durable] , idesc = "The last of its kind. Blind with rage. Charges at deadly speed." , ikit = [ ("armored skin", COrgan), ("eye 2", COrgan)- , ("horn", COrgan), ("snout", COrgan)+ , ("rhino horn", COrgan), ("snout", COrgan) , ("animal brain", COrgan) ] } @@ -465,12 +474,12 @@ , irarity = [(1, 2), (10, 4)] , iverbHit = "thud" , iweight = 1000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 8, AddMaxCalm 60 , AddSpeed 30, AddNocto 2 -- armor in sting , AddAbility AbAlter (-2) ] -- can't use stairs nor doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Every bee would die for the queen." , ikit = [ ("bee sting", COrgan), ("vision 6", COrgan) , ("insect mortality", COrgan), ("animal brain", COrgan) ]@@ -484,12 +493,12 @@ , irarity = [(5, 1), (10, 8)] , iverbHit = "thud" , iweight = 1000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 8, AddMaxCalm 70, AddSpeed 30, AddNocto 2 , AddAbility AbAlter (-2) -- can't use stairs nor doors , AddArmorMelee 80, AddArmorRanged 40 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "A vicious cloud of stings and hate." , ikit = [ ("sting", COrgan), ("vision 8", COrgan) , ("insect mortality", COrgan), ("animal brain", COrgan) ]@@ -503,11 +512,11 @@ , irarity = [(1, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 22, AddNocto 2 , AddAbility AbWait 1, AddAbility AbMelee 1 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Each branch bears long, curved thorns." , ikit = [("thorn", COrgan), ("armored skin", COrgan)] }@@ -526,12 +535,12 @@ , irarity = [(3 * 10/12, 0), (4 * 10/12, 10)] -- quickly vanishes at depth , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddNocto 2 , AddAbility AbWait 1, AddAbility AbMelee 1- , AddArmorMelee 40, AddArmorRanged 20 ]+ , AddArmorMelee 30, AddArmorRanged 15 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Must have been bought by previous ship owners to contain the wild animal infestation." , ikit = [("razor", COrgan)] }@@ -544,12 +553,12 @@ , irarity = [(3 * 10/12, 0), (4 * 10/12, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 40, AddNocto 2 , AddAbility AbWait 1, AddAbility AbMelee 1- , AddArmorMelee 40, AddArmorRanged 20 ]+ , AddArmorMelee 30, AddArmorRanged 15 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Marginally intelligent electric shepherd. Originally used in orbital dairy farms and planetary zoos." , ikit = [("live wire", COrgan)] }@@ -562,12 +571,12 @@ , irarity = [(5 * 10/12, 0), (6 * 10/12, 3)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20, AddNocto 2 , AddAbility AbWait 1, AddAbility AbProject 3- , AddArmorMelee 40, AddArmorRanged 20 ]+ , AddArmorMelee 30, AddArmorRanged 15 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Makeshift, mostly non-lethal, autonomous perimeter defense outpost." , ikit = [ ("vision 6", COrgan) , ("needle", CInv), ("can of sticky foam", CInv) ]@@ -581,12 +590,11 @@ , irarity = [(1, 3), (5 * 10/12, 3)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0- , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 10, AddNocto 2- , AddAbility AbWait 1, AddAbility AbMelee 1- , AddArmorMelee 40, AddArmorRanged 20 ] -- hard material+ , idamage = 0+ , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 11, AddNocto 2+ , AddAbility AbWait 1, AddAbility AbMelee 1 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "A cracked valve on one of the superheated water pipes spreading radially outward from the tokamak level." , ikit = [("boiling vent", COrgan), ("boiling fissure", COrgan)] }@@ -599,12 +607,12 @@ , irarity = [(1, 10), (5 * 10/12, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0- , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 22+ , idamage = 0+ , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 22 , AddNocto 2, AddShine 3 , AddAbility AbWait 1, AddAbility AbMelee 1 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "An emergency pressure-release vent on a smelly biogas pipe." , ikit = [("biogas vent", COrgan), ("biogas fissure", COrgan)] }@@ -617,12 +625,12 @@ , irarity = [(1, 10), (5 * 10/12, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0- , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 22+ , idamage = 0+ , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 22 , AddNocto 2, AddShine 3 , AddAbility AbWait 1, AddAbility AbMelee 1 ] , ieffects = []- , ifeature = [Durable, Identified] -- TODO: only heal humans+ , ifeature = [Durable] -- 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)] }@@ -635,13 +643,13 @@ , irarity = [] -- TODO: too boring , iverbHit = "thud" , iweight = 1000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 6, AddMaxCalm 90, AddSpeed 30, AddNocto 2 , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1) , AddAbility AbProject (-1), AddAbility AbMelee (-1)- , AddArmorMelee 40, AddArmorRanged 20 ]+ , AddArmorMelee 30, AddArmorRanged 15 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , 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) ] }@@ -654,13 +662,13 @@ , irarity = [(1, 7)] , iverbHit = "thud" , iweight = 1000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 30, AddNocto 2 , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1) , AddAbility AbProject (-1) , AddArmorMelee 80, AddArmorRanged 40 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "A shabby drone for bringing cows home." , ikit = [ ("eye 4", COrgan), ("live wire", COrgan) , ("robot brain", COrgan) ]@@ -674,13 +682,13 @@ , irarity = [(3, 0), (5, 2), (10, 4)] , iverbHit = "thud" , iweight = 500- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 6, AddMaxCalm 60, AddSpeed 40, AddNocto 2 , AddAbility AbDisplace (-1), AddAbility AbMoveItem (-1) , AddAbility AbMelee (-1)- , AddArmorMelee 40, AddArmorRanged 20 ]+ , AddArmorMelee 30, AddArmorRanged 15 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Originally designed for hunting down and putting to sleep stray animals. The sleeping agent has long since dried up." , ikit = [ ("eye 5", COrgan), ("needle", CInv) , ("robot brain", COrgan) ]@@ -695,11 +703,11 @@ , irarity = [(1, 20), (10, 6)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20, AddNocto 2- , AddAbility AbProject (-1) ]+ , AddAbility AbProject (-1), AddAbility AbAlter 1 ] -- doors , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , 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) ]@@ -714,10 +722,10 @@ , irarity = [(1, 10), (10, 6)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 15, AddNocto 2 ] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "You are not in its database, hence you are waste." , ikit = [ ("jaw", COrgan), ("tentacle", COrgan) , ("waste container", COrgan), ("armored skin", COrgan)@@ -734,11 +742,11 @@ , irarity = [(3, 1), (10, 10)] , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 30, AddNocto 2- , AddAbility AbProject 2 ]+ , AddAbility AbProject 2, AddAbility AbAlter 2 ] -- uses stairs , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Interior and exterior decoration robot. Strongly fancies deep reds recently." , ikit = [ ("hooked claw", COrgan), ("tentacle", COrgan) , ("spotlight", COrgan), ("armored skin", COrgan)@@ -754,16 +762,16 @@ , irarity = [(8, 0), (10, 10)] , iverbHit = "thud" , iweight = 800000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 20, AddNocto 2- , AddAbility AbProject 2 ]+ , AddAbility AbProject 2, AddAbility AbAlter 2 ] -- uses stairs , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Heavy multi-purpose construction robot. Excels at discharging, dismantling and demolition."- , ikit = [ ("large jaw", COrgan), ("small claw", COrgan), ("spotlight", COrgan)- , ("construction hooter", CInv)- , ("armored skin", COrgan), ("eye 4", COrgan)- , ("robot brain", COrgan) ]+ , ikit = [ ("large jaw", COrgan), ("small claw", COrgan)+ , ("spotlight", COrgan), ("armored skin", COrgan)+ , ("eye 4", COrgan), ("robot brain", COrgan)+ , ("construction hooter", CInv) ] } cleanerRobot = ItemKind { isymbol = 'C'@@ -775,16 +783,20 @@ -- unique, appears at 10 of 12 , iverbHit = "thud" , iweight = 80000- , idamage = toDmg 0- , iaspects = [AddMaxHP 120, AddMaxCalm 60, AddSpeed 18, AddNocto 2]- -- can't exit the gated level, a miniboss- , ieffects = [Unique]- , ifeature = [Durable, Identified]+ , idamage = 0+ , iaspects = [ AddMaxHP 120, AddMaxCalm 60, AddSpeed 18, AddNocto 2+ , AddAggression 1+ , AddAbility AbAlter 3 ]+ -- a miniboss; can remove rubble and ice,+ -- but can't exit the gated level+ , ieffects = []+ , ifeature = [Unique, Durable] , 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), ("hooked claw", COrgan)- , ("eye 2", COrgan), ("nostril", COrgan), ("spotlight", COrgan)+ , ("jaw", COrgan), ("hooked claw", COrgan), ("nostril", COrgan)+ , ("spotlight", COrgan), ("eye 2", COrgan)+ , ("robot brain", COrgan) , ("currency", CInv), ("currency", CInv), ("currency", CInv)- , ("robot brain", COrgan) ]+ , ("construction hooter", CInv) ] }
GameDefinition/Content/ItemKindBlast.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,110 +16,258 @@ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..)) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind blasts :: [ItemKind] blasts =- [burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, glassPiece, smoke, boilingWater, glue, singleSpark, spark, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, waste, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote]+ [burningOil2, burningOil3, burningOil4, firecracker1, firecracker2, firecracker3, firecracker4, firecracker5, spreadFragmentation, spreadFragmentation8, focusedFragmentation, spreadConcussion, spreadConcussion8, focusedConcussion, spreadFlash, spreadFlash8, focusedFlash, singleSpark, glassPiece, focusedGlass,fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, smoke, boilingWater, glue, waste, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote]+ -- Allure-specific+ ++ [cruiseAdHologram, outerAdHologram, victoriaClassHologram, allureIntroHologram] -burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, glassPiece, smoke, boilingWater, glue, singleSpark, spark, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, waste, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote :: ItemKind+burningOil2, burningOil3, burningOil4, firecracker1, firecracker2, firecracker3, firecracker4, firecracker5, spreadFragmentation, spreadFragmentation8, focusedFragmentation, spreadConcussion, spreadConcussion8, focusedConcussion, spreadFlash, spreadFlash8, focusedFlash, singleSpark, glassPiece, focusedGlass,fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, smoke, boilingWater, glue, waste, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, vulnerabilityBalm, resolutionDust, hasteSpray, slownessMist, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, youthSprinkle, poisonCloud, mistAntiSlow, mistAntidote :: ItemKind+-- Allure-specific+cruiseAdHologram, outerAdHologram, victoriaClassHologram, allureIntroHologram :: ItemKind -- We take care (e.g., in burningOil below) that blasts are not faster -- than 100% fastest natural speed, or some frames would be skipped, -- which is a waste of prefectly good frames. --- * Parameterized immediate effect blasts+-- * Parameterized blasts burningOil :: Int -> ItemKind burningOil n = ItemKind { isymbol = '*' , iname = "burning oil" , ifreq = [(toGroupName $ "burning oil" <+> tshow n, 1)]- , iflavour = zipFancy [BrYellow]+ , iflavour = zipPlain [BrYellow] , icount = intToDice (n * 8) , irarity = [(1, 1)] , iverbHit = "sear" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [AddShine 2]- , ieffects = [Burn 1, Paralyze 2] -- tripping on oil+ , ieffects = [ Burn 1+ , toOrganBad "slowed" (2 + 1 `d` 2) ] -- tripping on oil , ifeature = [ toVelocity (min 100 $ n `div` 2 * 10)- , Fragile, Identified ]+ , Fragile, Blast ] , idesc = "Sticky oil, burning brightly." , ikit = [] } burningOil2 = burningOil 2 -- 2 steps, 2 turns burningOil3 = burningOil 3 -- 3 steps, 2 turns burningOil4 = burningOil 4 -- 4 steps, 2 turns-explosionBlast :: Int -> ItemKind-explosionBlast n = ItemKind- { isymbol = '*'- , iname = "blast"- , ifreq = [(toGroupName $ "blast" <+> tshow n, 1)]- , iflavour = zipPlain [BrRed]- , icount = 16 -- strong and wide, but few, so not always hits target- , irarity = [(1, 1)]- , iverbHit = "tear apart"- , iweight = 1- , idamage = toDmg 0- , iaspects = [AddShine $ intToDice $ min 10 n]- , ieffects = [RefillHP (- n `div` 2)]- ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)| n >= 10]- ++ [DropItem 1 maxBound COrgan "temporary condition" | n >= 10]- ++ [DropItem 1 maxBound COrgan "impressed" | n >= 10] -- shock- , ifeature = [toLinger 20, Fragile, Identified] -- 4 steps, 1 turn- , idesc = ""- , ikit = []- }-explosionBlast2 = explosionBlast 2-explosionBlast10 = explosionBlast 10-explosionBlast20 = explosionBlast 20 firecracker :: Int -> ItemKind firecracker n = ItemKind { isymbol = '*' , iname = "firecracker"- , ifreq = [(toGroupName $ "firecracker" <+> tshow n, 1)]- , iflavour = zipPlain [brightCol !! (n `mod` length brightCol)]- , icount = intToDice (n `div` 6) + 1 `d` (n `div` 2)+ , ifreq = [(toGroupName $ if n == 5+ then "firecracker"+ else "firecracker" <+> tshow n, 1)]+ , iflavour = zipPlain [brightCol !! ((n + 2) `mod` length brightCol)]+ , icount = if n <= 3 then 1 `d` min 2 n else 2 + 1 `d` 2 , irarity = [(1, 1)]- , iverbHit = "crack"+ , iverbHit = if n >= 4 then "singe" else "crack" , iweight = 1- , idamage = toDmg 0- , iaspects = [AddShine $ intToDice $ n `div` 2]- , ieffects = [ RefillCalm (3 - n) | n >= 5 ]- ++ [ DropBestWeapon | n >= 5]+ , idamage = 0+ , iaspects = [AddShine $ intToDice $ 1 + n `div` 2]+ , ieffects = [if n >= 4 then Burn 1 else RefillCalm (-2)]+ ++ [DropBestWeapon | n >= 4] ++ [ OnSmash $ Explode $ toGroupName $ "firecracker" <+> tshow (n - 1)- | n > 2 ]- , ifeature = [toVelocity 5, Fragile, Identified]+ | n >= 2 ]+ , ifeature = [toVelocity 5, Fragile, Blast] , idesc = "Scraps of burnt paper, covering little pockets of black powder, buffeted by colorful explosions." , ikit = [] }-firecracker7 = firecracker 7-firecracker6 = firecracker 6 firecracker5 = firecracker 5 firecracker4 = firecracker 4 firecracker3 = firecracker 3 firecracker2 = firecracker 2+firecracker1 = firecracker 1 +-- * Focused blasts++spreadFragmentation = ItemKind+ { isymbol = '*'+ , iname = "fragmentation burst"+ , ifreq = [("violent fragmentation", 1)]+ , iflavour = zipPlain [Red] -- flying shards; some fire and smoke+ , icount = 16 -- strong but few, so not always hits target+ , irarity = [(1, 1)]+ , iverbHit = "tear apart"+ , iweight = 1+ , idamage = 3 `d` 1 -- deadly and adjacent actor hit by 2 on average;+ -- however, moderate armour blocks completely+ , iaspects = [AddShine 3, AddHurtMelee $ -12 * 5]+ , ieffects = [DropItem 1 maxBound COrgan "condition"]+ , ifeature = [toLinger 20, Lobable, Fragile, Blast] -- 4 steps, 1 turn+ , idesc = ""+ , ikit = []+ }+spreadFragmentation8 = spreadFragmentation+ { iname = "fragmentation burst"+ , ifreq = [("fragmentation", 1)]+ , icount = 8+ , ifeature = [toLinger 10, Lobable, Fragile, Blast] -- 2 steps, 1 turn+ -- smaller radius, so worse for area effect, but twice the direct damage+ }+focusedFragmentation = ItemKind+ { isymbol = '`'+ , iname = "deflagration ignition" -- improvised fertilizer, etc.+ , ifreq = [("focused fragmentation", 1)]+ , iflavour = zipPlain [BrYellow]+ , icount = 4 -- 32 in total vs 16; on average 4 hits+ , irarity = [(1, 1)]+ , iverbHit = "ignite"+ , iweight = 1+ , idamage = 0+ , iaspects = []+ , ieffects = [OnSmash $ Explode "fragmentation"]+ , ifeature = [toLinger 0, Fragile, Blast] -- 0 steps, 1 turn+ -- when the target position is occupied, the explosion starts one step+ -- away, hence we set range to 0 steps, to limit dispersal+ , idesc = ""+ , ikit = []+ }+spreadConcussion = ItemKind+ { isymbol = '*'+ , iname = "concussion blast"+ , ifreq = [("violent concussion", 1)]+ , iflavour = zipPlain [Magenta] -- mosty shock wave; some fire and smoke+ , icount = 16+ , irarity = [(1, 1)]+ , iverbHit = "shock"+ , iweight = 1+ , idamage = 1 `d` 1 -- only air pressure, so not as deadly as fragmentation,+ -- but armour can't block completely that easily+ , iaspects = [AddShine 3, AddHurtMelee $ -8 * 5]+ , ieffects = [ DropItem maxBound 1 CEqp "misc armor"+ , PushActor (ThrowMod 400 25) -- 1 step, fast; after DropItem+ -- this produces spam for braced actors; too bad+ , DropItem 1 maxBound COrgan "condition" ]+ , ifeature = [toLinger 20, Lobable, Fragile, Blast] -- 4 steps, 1 turn+ -- outdoors it has short range, but we only model indoors in the game;+ -- it's much faster than black powder shock wave, but we are beyond+ -- human-noticeable speed differences on short distances anyway+ , idesc = ""+ , ikit = []+ }+spreadConcussion8 = spreadConcussion+ { iname = "concussion blast"+ , ifreq = [("concussion", 1)]+ , icount = 8+ , ifeature = [toLinger 10, Lobable, Fragile, Blast] -- 2 steps, 1 turn+ }+focusedConcussion = ItemKind+ { isymbol = '`'+ , iname = "detonation ignition" -- stabilized high explosive liquid+ , ifreq = [("focused concussion", 1)]+ , iflavour = zipPlain [BrYellow]+ , icount = 4+ , irarity = [(1, 1)]+ , iverbHit = "ignite"+ , iweight = 1+ , idamage = 0+ , iaspects = []+ , ieffects = [OnSmash $ Explode "concussion"]+ , ifeature = [toLinger 0, Fragile, Blast] -- 0 steps, 1 turn+ , idesc = ""+ , ikit = []+ }+spreadFlash = ItemKind+ { isymbol = '`'+ , iname = "magnesium flash" -- or aluminum, but let's stick to one+ , ifreq = [("violent flash", 1)]+ , iflavour = zipPlain [BrWhite] -- very brigh flash+ , icount = 16+ , irarity = [(1, 1)]+ , iverbHit = "dazzle"+ , iweight = 1+ , idamage = 0+ , iaspects = [AddShine 5]+ , ieffects = [toOrganBad "blind" 10, toOrganBad "weakened" 30]+ -- Wikipedia says: blind for five seconds and afterimage+ -- for much longer, harming aim+ , ifeature = [toLinger 20, Fragile, Blast] -- 4 steps, 1 turn+ , idesc = "A flash of fire."+ , ikit = []+ }+spreadFlash8 = spreadFlash+ { iname = "spark"+ , ifreq = [("spark", 1)]+ , icount = 8+ , iverbHit = "blind"+ , ifeature = [toLinger 10, Fragile, Blast] -- 2 steps, 1 turn+ }+focusedFlash = ItemKind+ { isymbol = '`'+ , iname = "magnesium ignition"+ , ifreq = [("focused flash", 1)]+ , iflavour = zipPlain [BrYellow]+ , icount = 4+ , irarity = [(1, 1)]+ , iverbHit = "ignite"+ , iweight = 1+ , idamage = 0+ , iaspects = []+ , ieffects = [OnSmash $ Explode "spark"]+ , ifeature = [toLinger 0, Fragile, Blast] -- 0 steps, 1 turn+ , idesc = ""+ , ikit = []+ }+singleSpark = spreadFlash+ { iname = "single spark"+ , ifreq = [("single spark", 1)]+ , icount = 1+ , iverbHit = "spark"+ , iaspects = [AddShine 3]+ , ieffects = []+ , ifeature = [toLinger 5, Fragile, Blast] -- 1 step, 1 turn+ , idesc = "A glowing ember."+ , ikit = []+ }+glassPiece = ItemKind+ { isymbol = '*'+ , iname = "glass piece"+ , ifreq = [("glass hail", 1)]+ , iflavour = zipPlain [Blue]+ , icount = 8+ , irarity = [(1, 1)]+ , iverbHit = "cut"+ , iweight = 1+ , idamage = 1 `d` 1+ , iaspects = [AddHurtMelee $ -15 * 5] -- brittle, not too dense; armor blocks+ , ieffects = [RefillHP (-1)]+ , ifeature = [toLinger 20, Fragile, Blast] -- 4 steps, 1 turn+ , idesc = "Swift, sharp edges."+ , ikit = []+ }+focusedGlass = glassPiece -- when blowing up windows+ { ifreq = [("focused glass hail", 1)]+ , icount = 4+ , ieffects = [RefillHP (-1), OnSmash $ Explode "glass hail"]+ , ifeature = [toLinger 0, Fragile, Blast] -- 0 steps, 1 turn+ }+ -- * Assorted immediate effect blasts fragrance = ItemKind { isymbol = '`' , iname = "fragrance" -- instant, fast fragrance , ifreq = [("fragrance", 1)]- , iflavour = zipFancy [Magenta]- , icount = 16+ , iflavour = zipPlain [Magenta]+ , icount = 12 , irarity = [(1, 1)] , iverbHit = "engulf" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Impress] -- Linger 10, because sometimes it takes 2 turns due to starting just -- before actor turn's end (e.g., via a necklace).- , ifeature = [toLinger 10, Fragile, Identified] -- 2 steps, 1 turn+ , ifeature = [toLinger 10, Fragile, Blast] -- 2 steps, 1 turn , idesc = "A pleasant scent." , ikit = [] }@@ -127,15 +275,15 @@ { isymbol = '`' , iname = "musky whiff" -- a kind of mist rather than fragrance , ifreq = [("pheromone", 1)]- , iflavour = zipFancy [BrMagenta]+ , iflavour = zipPlain [BrMagenta] , icount = 16 , irarity = [(1, 1)] , iverbHit = "tempt" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Impress, RefillCalm (-10)]- , ifeature = [toVelocity 10, Fragile, Identified] -- 2 steps, 2 turns+ , ifeature = [toVelocity 10, Fragile, Blast] -- 2 steps, 2 turns , idesc = "A sharp, strong scent." , ikit = [] }@@ -143,15 +291,15 @@ { isymbol = '`' , iname = "mist" , ifreq = [("calming mist", 1)]- , iflavour = zipFancy [BrGreen]+ , iflavour = zipPlain [BrGreen] , icount = 8 , irarity = [(1, 1)] , iverbHit = "sooth" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [RefillCalm 2]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "A soothing, gentle cloud." , ikit = [] }@@ -159,15 +307,15 @@ { isymbol = '`' , iname = "distressing whiff" , ifreq = [("distressing odor", 1)]- , iflavour = zipFancy [BrRed]- , icount = 16+ , iflavour = zipFancy [BrRed] -- salmon+ , icount = 8 , irarity = [(1, 1)] , iverbHit = "distress" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [RefillCalm (-20)]- , ifeature = [toLinger 10, Fragile, Identified] -- 2 steps, 1 turn+ , ifeature = [toLinger 10, Fragile, Blast] -- 2 steps, 1 turn , idesc = "It turns the stomach." , ikit = [] }@@ -180,10 +328,10 @@ , irarity = [(1, 1)] , iverbHit = "revitalize" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [AddShine 1] , ieffects = [RefillHP 2]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "It fills the air with light and life." , ikit = [] }@@ -191,15 +339,15 @@ { isymbol = '`' , iname = "mist" , ifreq = [("healing mist 2", 1)]- , iflavour = zipFancy [BrGreen]+ , iflavour = zipPlain [Green] , icount = 8 , irarity = [(1, 1)] , iverbHit = "revitalize" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [AddShine 2] , ieffects = [RefillHP 4]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "At its touch, wounds close and bruises fade." , ikit = [] }@@ -207,15 +355,15 @@ { isymbol = '`' , iname = "mist" , ifreq = [("wounding mist", 1)]- , iflavour = zipFancy [BrRed]+ , iflavour = zipPlain [BrRed] , icount = 8 , irarity = [(1, 1)] , iverbHit = "devitalize" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [RefillHP (-2)]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "The air itself stings and itches." , ikit = [] }@@ -223,34 +371,18 @@ { isymbol = 'v' , iname = "vortex" , ifreq = [("distortion", 1)]- , iflavour = zipFancy [White]- , icount = 16+ , iflavour = zipPlain [White]+ , icount = 8 -- braced are immune to Teleport; avoid failure messages , irarity = [(1, 1)] , iverbHit = "engulf" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Teleport $ 15 + 1 `d` 10]- , ifeature = [toLinger 10, Fragile, Identified] -- 2 steps, 1 turn+ , ifeature = [toLinger 10, Lobable, Fragile, Blast] -- 2 steps, 1 turn , idesc = "The air shifts oddly, as though light is being warped." , ikit = [] }-glassPiece = ItemKind -- when blowing up windows- { isymbol = '*'- , iname = "glass piece"- , ifreq = [("glass piece", 1)]- , iflavour = zipPlain [BrBlue]- , icount = 16- , irarity = [(1, 1)]- , iverbHit = "cut"- , iweight = 1- , idamage = toDmg 0- , iaspects = []- , ieffects = [RefillHP (-1)] -- high velocity, so can't do idamage- , ifeature = [toLinger 20, Fragile, Identified] -- 4 steps, 1 turn- , idesc = "Swift, sharp edges."- , ikit = []- } smoke = ItemKind -- when stuff burns out -- unused { isymbol = '`' , iname = "smoke"@@ -258,12 +390,12 @@ , iflavour = zipPlain [BrBlack] , icount = 16 , irarity = [(1, 1)]- , iverbHit = "choke" -- or obscure+ , iverbHit = "choke" -- or "obscure" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = []- , ifeature = [toVelocity 20, Fragile, Identified] -- 4 steps, 2 turns+ , ifeature = [toVelocity 20, Fragile, Blast] -- 4 steps, 2 turns , idesc = "Twirling clouds of grey smoke." , ikit = [] }@@ -271,15 +403,15 @@ { isymbol = '*' , iname = "boiling water" , ifreq = [("boiling water", 1)]- , iflavour = zipPlain [BrWhite]- , icount = 16+ , iflavour = zipPlain [White]+ , icount = 18 , irarity = [(1, 1)] , iverbHit = "boil" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Burn 1]- , ifeature = [toVelocity 30, Fragile, Identified] -- 6 steps, 2 turns+ , ifeature = [toVelocity 30, Fragile, Blast] -- 6 steps, 2 turns , idesc = "It bubbles and hisses." , ikit = [] }@@ -288,69 +420,54 @@ , iname = "hoof glue" , ifreq = [("glue", 1)] , iflavour = zipPlain [Cyan]- , icount = 16+ , icount = 8 -- Paralyze doesn't stack; avoid failure messages , irarity = [(1, 1)] , iverbHit = "glue" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Paralyze 10]- , ifeature = [toVelocity 20, Fragile, Identified] -- 4 steps, 2 turns+ , ifeature = [toVelocity 20, Fragile, Blast] -- 4 steps, 2 turns , idesc = "Thick and clinging." , ikit = [] }-singleSpark = ItemKind- { isymbol = '`'- , iname = "single spark"- , ifreq = [("single spark", 1)]- , iflavour = zipPlain [BrWhite]- , icount = 1- , irarity = [(1, 1)]- , iverbHit = "spark"- , iweight = 1- , idamage = toDmg 0- , iaspects = [AddShine 4]- , ieffects = []- , ifeature = [toLinger 5, Fragile, Identified] -- 1 step, 1 turn- , idesc = "A glowing ember."- , ikit = []- }-spark = ItemKind- { isymbol = '`'- , iname = "spark"- , ifreq = [("spark", 1)]- , iflavour = zipPlain [BrWhite]+waste = ItemKind+ { isymbol = '*'+ , iname = "waste"+ , ifreq = [("waste", 1)]+ , iflavour = zipPlain [Brown] , icount = 16 , irarity = [(1, 1)]- , iverbHit = "scorch"+ , iverbHit = "splosh" , iweight = 1- , idamage = toDmg 0- , iaspects = [AddShine 4]+ , idamage = 0+ , iaspects = [] , ieffects = [Burn 1]- , ifeature = [toLinger 10, Fragile, Identified] -- 2 steps, 1 turn- , idesc = "A flash of fire."+ , ifeature = [toLinger 10, Fragile, Blast]+ , idesc = "Sodden and foul-smelling." , ikit = [] } --- * Temporary condition blasts strictly matching the aspects+-- * Temporary condition blasts -- Almost all have @toLinger 10@, that travels 2 steps in 1 turn. -- These are very fast projectiles, not getting into the way of big -- actors and not burdening the engine for long.+-- A few are slower 'mists'. denseShower = ItemKind { isymbol = '`' , iname = "dense shower" , ifreq = [("dense shower", 1)] , iflavour = zipFancy [Green]- , icount = 16+ , icount = 12 , irarity = [(1, 1)] , iverbHit = "strengthen" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "strengthened" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "strengthened" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A thick rain of droplets." , ikit = [] }@@ -359,14 +476,14 @@ , iname = "sparse shower" , ifreq = [("sparse shower", 1)] , iflavour = zipFancy [Red]- , icount = 16+ , icount = 8 , irarity = [(1, 1)] , iverbHit = "weaken" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganGameTurn "weakened" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganBad "weakened" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "Light droplets that cling to clothing." , ikit = [] }@@ -374,15 +491,15 @@ { isymbol = '`' , iname = "balm droplet" , ifreq = [("melee protective balm", 1)]- , iflavour = zipPlain [Brown]+ , iflavour = zipFancy [Brown] , icount = 16 , irarity = [(1, 1)] , iverbHit = "balm" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "protected from melee" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "protected from melee" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A thick ointment that hardens the skin." , ikit = [] }@@ -395,10 +512,10 @@ , irarity = [(1, 1)] , iverbHit = "balm" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "protected from ranged" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "protected from ranged" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "Grease that protects from flying death." , ikit = [] }@@ -411,10 +528,10 @@ , irarity = [(1, 1)] , iverbHit = "paint" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganGameTurn "painted red" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganBad "painted red" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "" , ikit = [] }@@ -427,11 +544,11 @@ , irarity = [(1, 1)] , iverbHit = "calm" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "resolute" (3 + 1 `d` 3)]+ , ieffects = [toOrganGood "resolute" (3 + 1 `d` 3)] -- short enough duration that @calmEnough@ not a big problem- , ifeature = [toLinger 10, Fragile, Identified]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A handful of honest earth, to strengthen the soul." , ikit = [] }@@ -439,15 +556,15 @@ { isymbol = '`' , iname = "haste spray" , ifreq = [("haste spray", 1)]- , iflavour = zipPlain [BrYellow]+ , iflavour = zipFancy [BrYellow] , icount = 16 , irarity = [(1, 1)] , iverbHit = "haste" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "hasted" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "hasted" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A quick spurt." , ikit = [] }@@ -459,11 +576,12 @@ , icount = 8 , irarity = [(1, 1)] , iverbHit = "slow"- , iweight = 1- , idamage = toDmg 0+ , iweight = 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganGameTurn "slowed" (3 + 1 `d` 3)]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn, mist+ , ieffects = [toOrganBad "slowed" (3 + 1 `d` 3)]+ , ifeature = [toVelocity 5, Fragile, Blast]+ -- 1 step, 1 turn, mist, slow , idesc = "Clammy fog, making each movement an effort." , ikit = [] }@@ -471,15 +589,15 @@ { isymbol = '`' , iname = "eye drop" , ifreq = [("eye drop", 1)]- , iflavour = zipPlain [BrCyan]+ , iflavour = zipFancy [BrCyan] , icount = 16 , irarity = [(1, 1)] , iverbHit = "cleanse" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "far-sighted" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "far-sighted" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "Not to be taken orally." , ikit = [] }@@ -487,15 +605,15 @@ { isymbol = '`' , iname = "iron filing" , ifreq = [("iron filing", 1)]- , iflavour = zipPlain [Brown]+ , iflavour = zipPlain [Red] , icount = 16 , irarity = [(1, 1)] , iverbHit = "blind" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "blind" (10 + 1 `d` 10)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganBad "blind" (10 + 1 `d` 10)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A shaving of bright metal." , ikit = [] }@@ -503,15 +621,15 @@ { isymbol = '`' , iname = "smelly droplet" , ifreq = [("smelly droplet", 1)]- , iflavour = zipPlain [Blue]+ , iflavour = zipFancy [Blue] , icount = 16 , irarity = [(1, 1)] , iverbHit = "sensitize" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "keen-smelling" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "keen-smelling" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "A viscous lump that stains the skin." , ikit = [] }@@ -519,66 +637,47 @@ { isymbol = '`' , iname = "eye shine" , ifreq = [("eye shine", 1)]- , iflavour = zipPlain [Cyan]+ , iflavour = zipFancy [Cyan] , icount = 16 , irarity = [(1, 1)] , iverbHit = "smear" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "shiny-eyed" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "shiny-eyed" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "They almost glow in the dark." , ikit = [] }---- * Assorted temporary condition blasts or related (also, matching flasks)- whiskeySpray = ItemKind { isymbol = '`' , iname = "whiskey spray" , ifreq = [("whiskey spray", 1)]- , iflavour = zipPlain [Brown]+ , iflavour = zipFancy [Brown] , icount = 16 , irarity = [(1, 1)] , iverbHit = "inebriate" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganActorTurn "drunk" (3 + 1 `d` 3)]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganGood "drunk" (3 + 1 `d` 3)]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "It burns in the best way." , ikit = [] }-waste = ItemKind- { isymbol = '*'- , iname = "waste"- , ifreq = [("waste", 1)]- , iflavour = zipPlain [Brown]- , icount = 16- , irarity = [(1, 1)]- , iverbHit = "splosh"- , iweight = 1- , idamage = toDmg 0- , iaspects = []- , ieffects = [Burn 1]- , ifeature = [toLinger 10, Fragile, Identified]- , idesc = "Sodden and foul-smelling."- , ikit = []- } youthSprinkle = ItemKind { isymbol = '`' , iname = "youth sprinkle" , ifreq = [("youth sprinkle", 1)]- , iflavour = zipPlain [BrGreen]+ , iflavour = zipFancy [BrGreen] , icount = 16 , irarity = [(1, 1)] , iverbHit = "sprinkle" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganNone "regenerating"]- , ifeature = [toLinger 10, Fragile, Identified]+ , ieffects = [toOrganNoTimer "regenerating"]+ , ifeature = [toLinger 10, Fragile, Blast] , idesc = "Bright and smelling of the Spring." , ikit = [] }@@ -586,15 +685,15 @@ { isymbol = '`' , iname = "poison cloud" , ifreq = [("poison cloud", 1)]- , iflavour = zipPlain [BrMagenta]+ , iflavour = zipFancy [BrMagenta] , icount = 16 , irarity = [(1, 1)] , iverbHit = "poison"- , iweight = 1- , idamage = toDmg 0+ , iweight = 0+ , idamage = 0 , iaspects = []- , ieffects = [toOrganNone "poisoned"]- , ifeature = [toVelocity 10, Fragile, Identified] -- 2 steps, 2 turns+ , ieffects = [toOrganNoTimer "poisoned"]+ , ifeature = [toVelocity 10, Fragile, Blast] -- 2 steps, 2 turns , idesc = "Choking gas that stings the eyes." , ikit = [] }@@ -602,15 +701,15 @@ { isymbol = '`' , iname = "mist" , ifreq = [("anti-slow mist", 1)]- , iflavour = zipPlain [BrYellow]+ , iflavour = zipFancy [BrYellow] , icount = 8 , irarity = [(1, 1)] , iverbHit = "propel" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [DropItem 1 1 COrgan "slowed"]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "A cleansing rain." , ikit = [] }@@ -618,15 +717,64 @@ { isymbol = '`' , iname = "mist" , ifreq = [("antidote mist", 1)]- , iflavour = zipPlain [BrBlue]+ , iflavour = zipFancy [BrBlue] , icount = 8 , irarity = [(1, 1)] , iverbHit = "cure" , iweight = 1- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [DropItem 1 maxBound COrgan "poisoned"]- , ifeature = [toVelocity 5, Fragile, Identified] -- 1 step, 1 turn+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn , idesc = "Washes away death's dew." , ikit = []+ }++-- * Allure-specific++-- ** Lore blasts++-- They exist for a short time only, but the lore can be read+-- from the lore menu. Only optional story bits should go there,+-- becuase some players may not even notice them (at first, at least).+-- This is designed not to spam gameplay with story. Gameplay first.+-- Generally, 3 to 5 blasts of each kind should suffice for variety.+-- More would induce long repetition to see all (they are shown at random).+-- With mild exceptions, they should have no effects.++cruiseAdHologram = ItemKind+ { isymbol = '`'+ , iname = "cruise ad hologram"+ , ifreq = [("cruise ad hologram", 1), ("advertisement", 20)]+ , iflavour = zipFancy [BrMagenta]+ , icount = 8+ , irarity = [(1, 1)]+ , iverbHit = "excite"+ , iweight = 0 -- delay of 1 turn at the start, to easily read the text+ , idamage = 0+ , iaspects = []+ , ieffects = [toOrganGood "resolute" (5 + 1 `d` 2), DropBestWeapon]+ , ifeature = [toVelocity 5, Fragile, Blast] -- 1 step, 1 turn+ , idesc = "The fitful holographic clip shows a couple that laughs, watches in silence Saturn's rings through a huge window, throws treats to a little rhino frolicking in reduced gravity, runs through corridors wearing alien masks in a mock chase. An exited female voice proclaims: \"...safety and security, comfort, imagination...for each of your senses...robot servants...personalized life support zones...\""+ , ikit = []+ }+outerAdHologram = cruiseAdHologram+ { iname = "cruise ad hologram"+ , ifreq = [("advertisement", 10)]+ , icount = 4+ , ieffects = [] -- weak, 4 particles, no effect+ , idesc = "A composed young man in a hat looks straight into your eyes with unwavering stare and extols the opportunities, freedom and excitement of the outer Solar System frontier life with unshakable conviction. Names of Neptune-area realtors scroll at the bottom in small font with oversize serifs."+ }+victoriaClassHologram = outerAdHologram+ { iname = "space fleet hologram"+ , ifreq = [("story-telling", 20)]+ , iflavour = zipFancy [BrBlue]+ , icount = 1+ , iverbHit = "bore"+ , idesc = "A series of huge spaceships zoom in and out of view in a solemn procession. Male voice drones over crackling static: Victoria-class cruise liners are the largest passenger ships ever serially manufactured and the third largest in general, including transport vessel series. Bigger ships are sometimes cobbled ad-hoc, by wiring together cheap modules and primitive cargo hulls welded in space, but they are rarely certified for public commercial operation. Victoria-class passenger cruisers are produced for over three decades now, in slowly evolving configurations, one per two years on average. The design is as conservative, as possible. A disc large enough for comfortable artificial gravity through constant spinning. Fusion reactor in the middle of the axle powering engines protruding far back from the rear plane. Meteor shield at the front. Numerous redundant rechargeable power sources and autonomous life support areas, eliminating the \"all locked in a single can, breathing the same air\" space travel grievance. Actually, everything is redundant twice over, due to strict regulations. To sum it up, these are the most boring spaceships in the galaxy."+ }+allureIntroHologram = victoriaClassHologram+ { iname = "spaceship hologram"+ , ifreq = [("story-telling", 10)]+ , idesc = "A wavy 3D wireframe of a spaceship rotates ponderously. Male voice drones: Allure of the Stars belongs to a long line of luxurious orbit-to-orbit cruise liners, the Victoria-class. It was named after the largest passenger sea vessel of the early 21st century and it shares the grandeur and the extravagance. This particular Victoria-class specimen was designed for long cruises to gas giants, their moons and the moon cities (and their notorious saloons). It has a meteor shield in the form of a flat, multi-layer. unpressurized cargo bay covering the front plane. Such extra cargo capacity enables long space journeys with no limits on resource usage. On shorter legs of the journeys it also enables opportunistic mass cargo transport (in accordance to strictest regulations and completely isolated from the airflow on passenger decks), which is always in demand at the profusely productive, but scarcely populated Solar System frontier. It also makes the unit much thicker than usual: the length from the tip of the cargo bay to the end of the engines is almost two thirds of the diameter of the disk. All in all, it is a particularly sturdy and self-sufficient member of a class famed for exceptional resilience and safety." }
GameDefinition/Content/ItemKindEmbed.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,95 +16,134 @@ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..)) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind embeds :: [ItemKind] embeds =- [stairsUp, stairsDown, escape, terrainCache, terrainCacheTrap, signboardExit, signboardMap, fireSmall, fireBig, frost, rubble, staircaseTrapUp, staircaseTrapDown, doorwayTrap, obscenePictograms, subtleFresco, scratchOnWall, pulpit]--stairsUp, stairsDown, escape, terrainCache, terrainCacheTrap, signboardExit, signboardMap, fireSmall, fireBig, frost, rubble, staircaseTrapUp, staircaseTrapDown, doorwayTrap, obscenePictograms, subtleFresco, scratchOnWall, pulpit :: ItemKind+ [scratchOnWall, obscenePictogram, subtleFresco, treasureCache, treasureCacheTrap, signboardExit, signboardEmbed, fireSmall, fireBig, frost, rubble, doorwayTrapTemplate, doorwayTrap1, doorwayTrap2, doorwayTrap3, stairsUp, stairsDown, escape, staircaseTrapUp, staircaseTrapDown, pulpit]+ -- Allure-specific+ ++ [blackStarrySky, ruinedFirstAidKit, wall3dBillboard, jewelryDisplay, liftUp, liftDown, liftTrap, liftTrap2]+scratchOnWall, obscenePictogram, subtleFresco, treasureCache, treasureCacheTrap, signboardExit, signboardEmbed, fireSmall, fireBig, frost, rubble, doorwayTrapTemplate, doorwayTrap1, doorwayTrap2, doorwayTrap3, stairsUp, stairsDown, escape, staircaseTrapUp, staircaseTrapDown, pulpit :: ItemKind+-- Allure-specific+blackStarrySky, ruinedFirstAidKit, wall3dBillboard, jewelryDisplay, liftUp, liftDown, liftTrap, liftTrap2 :: ItemKind -stairsUp = ItemKind- { isymbol = '<'- , iname = "staircase up"- , ifreq = [("staircase up", 1)]- , iflavour = zipPlain [BrWhite]+-- Make sure very few walls are substantially useful, e.g., caches,+-- and none that are secret. Otherwise the player will spend a lot of time+-- bumping walls, which is boring compare to fights or dialogues+-- and ever worse, the player will bump all secret walls, wasting time+-- and foregoing the fun of guessing how to find entrance to a disjoint part+-- of the level by bumping the least number of secret walls.+scratchOnWall = ItemKind+ { isymbol = '?'+ , iname = "claw mark"+ , ifreq = [("scratch on wall", 1)]+ , iflavour = zipPlain [BrBlack] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "crash"- , iweight = 100000- , idamage = toDmg 0+ , iverbHit = "scratch"+ , iweight = 1000+ , idamage = 0 , iaspects = []- , ieffects = [Ascend True]- , ifeature = [Identified, Durable]- , idesc = "Stairs that rise towards escape."+ , ieffects = [ Temporary "start making sense of the scratches"+ , Detect DetectHidden 3 ]+ , ifeature = [Durable]+ , idesc = "A seemingly random series of scratches, carved deep into the wall." , ikit = [] }-stairsDown = stairsUp- { isymbol = '>'- , iname = "staircase down"- , ifreq = [("staircase down", 1)]- , ieffects = [Ascend False]+obscenePictogram = ItemKind+ { isymbol = '*'+ , iname = "repulsing graffiti"+ , ifreq = [("obscene pictogram", 1)]+ , iflavour = zipPlain [BrMagenta]+ , icount = 1+ , irarity = [(1, 1)]+ , iverbHit = "infuriate"+ , iweight = 1000+ , idamage = 0+ , iaspects = [Timeout 7]+ , ieffects = [ Recharging $ Temporary "enter unexplainable rage at a glimpse of the inscrutable graffiti"+ , Recharging $ RefillCalm (-20)+ , Recharging $ OneOf+ [ toOrganGood "strengthened" (3 + 1 `d` 2)+ , CreateItem CInv "sandstone rock" timerNone ] ]+ , ifeature = [Durable] , idesc = ""+ , ikit = [] }-escape = stairsUp- { iname = "escape"- , ifreq = [("escape", 1)]- , iflavour = zipPlain [BrYellow]- , ieffects = [Escape]- , idesc = ""+subtleFresco = ItemKind+ { isymbol = '*'+ , iname = "subtle mural"+ , ifreq = [("subtle fresco", 1)]+ , iflavour = zipPlain [BrGreen]+ , icount = 1+ , irarity = [(1, 1)]+ , iverbHit = "sooth"+ , iweight = 1000+ , idamage = 0+ , iaspects = [Timeout 7]+ , ieffects = [ Temporary "be entranced by the subtle mural"+ , RefillCalm 2+ , Recharging $ toOrganGood "far-sighted" (3 + 1 `d` 2)+ , Recharging $ toOrganGood "keen-smelling" (3 + 1 `d` 2) ]+ , ifeature = [Durable]+ , idesc = "Expensive yet tasteful."+ , ikit = [] }-terrainCache = stairsUp+treasureCache = stairsUp { isymbol = 'O'- , iname = "treasure cache"- , ifreq = [("terrain cache", 1)]- , iflavour = zipPlain [BrYellow]- , ieffects = [CreateItem CGround "useful" TimerNone]- , idesc = "Glittering gold, just waiting to be taken."+ , iname = "intact deposit box"+ , ifreq = [("treasure cache", 1)]+ , iflavour = zipPlain [BrBlue]+ , ieffects = [CreateItem CGround "common item" timerNone]+ , idesc = "" }-terrainCacheTrap = ItemKind+treasureCacheTrap = ItemKind { isymbol = '^'- , iname = "treasure cache trap"- , ifreq = [("terrain cache trap", 1)]- , iflavour = zipPlain [BrRed]+ , iname = "anti-theft protection"+ , ifreq = [("treasure cache trap", 1)]+ , iflavour = zipPlain [Red] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "trap"+ , iverbHit = "taint" , iweight = 1000- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [OneOf [ toOrganNone "poisoned", Explode "glue"- , ELabel "", ELabel "", ELabel ""- , ELabel "", ELabel "", ELabel ""- , ELabel "", ELabel "" ]]- , ifeature = [Identified] -- not Durable, springs at most once- , idesc = "It's a trap!"+ , ieffects = [OneOf [ toOrganBad "blind" (40 + 1 `d` 10)+ , RefillCalm (-99)+ , Explode "focused concussion"+ , RefillCalm (-1), RefillCalm (-1), RefillCalm (-1)+ , RefillCalm (-1), RefillCalm (-1), RefillCalm (-1)+ , RefillCalm (-1) ]]+ , ifeature = [] -- not Durable, springs at most once+ , idesc = "" , ikit = [] } signboardExit = ItemKind- { isymbol = 'O'- , iname = "signboard with exits"+ { isymbol = '?'+ , iname = "sticker" , ifreq = [("signboard", 80)] , iflavour = zipPlain [BrMagenta] , icount = 1 , irarity = [(1, 1)] , iverbHit = "whack" , iweight = 10000- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [DetectExit 100]- , ifeature = [Identified, Durable]- , idesc = "A battered sign, carved by unknown hands."+ , ieffects = [Detect DetectExit 100] -- low tech, hence fully operational+ , ifeature = [Durable]+ , idesc = "Mandatory emergency exit information in low-tech form." , ikit = [] }-signboardMap = signboardExit- { iname = "signboard with map"+signboardEmbed = signboardExit+ { iname = "notice" , ifreq = [("signboard", 20)]- , ieffects = [Detect 10]+ , ieffects = [Detect DetectEmbed 12] -- low tech, hence fully operational+ , idesc = "Detailed schematics for the maintenance crew." } fireSmall = ItemKind- { isymbol = '&'+ { isymbol = '%' , iname = "small fire" , ifreq = [("small fire", 1)] , iflavour = zipPlain [BrRed]@@ -112,10 +151,10 @@ , irarity = [(1, 1)] , iverbHit = "burn" , iweight = 10000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [Burn 1, Explode "single spark"]- , ifeature = [Identified, Durable]+ , ifeature = [Durable] , idesc = "A few small logs, burning brightly." , ikit = [] }@@ -124,13 +163,13 @@ , iname = "big fire" , ifreq = [("big fire", 1)] , ieffects = [ Burn 2, Explode "spark"- , CreateItem CInv "wooden torch" TimerNone ]- , ifeature = [Identified, Durable]+ , CreateItem CInv "wooden torch" timerNone ]+ , ifeature = [Durable] , idesc = "Glowing with light and warmth." , ikit = [] } frost = ItemKind- { isymbol = '%'+ { isymbol = '^' , iname = "frost" , ifreq = [("frost", 1)] , iflavour = zipPlain [BrBlue]@@ -138,49 +177,115 @@ , irarity = [(1, 1)] , iverbHit = "burn" , iweight = 10000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [] , ieffects = [ Burn 1 -- sensory ambiguity between hot and cold , RefillCalm 20 -- cold reason- , PushActor (ThrowMod 200 50) ] -- slippery ice- , ifeature = [Identified, Durable]+ , PushActor (ThrowMod 100 50) ] -- slippery ice, 1 step, slow+ , ifeature = [Durable] , idesc = "Intricate patterns of shining ice." , ikit = [] } rubble = ItemKind- { isymbol = ':'+ { isymbol = '&' , iname = "rubble" , ifreq = [("rubble", 1)]- , iflavour = zipPlain [BrWhite]+ , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(1, 1)] , iverbHit = "bury" , iweight = 100000- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [OneOf [ Explode "glass piece", Explode "waste"- , Summon "animal" 1, toOrganNone "poisoned"- , CreateItem CGround "useful" TimerNone- , ELabel "", ELabel "", ELabel ""- , ELabel "", ELabel "", ELabel "" ]]- , ifeature = [Identified, Durable]- , idesc = "Broken chunks of rock and glass."+ , ieffects = [OneOf [ Explode "focused glass hail"+ , Summon "animal" $ 1 `dL` 2+ , toOrganNoTimer "poisoned"+ , CreateItem CGround "common item" timerNone+ , RefillCalm (-1), RefillCalm (-1), RefillCalm (-1)+ , RefillCalm (-1), RefillCalm (-1), RefillCalm (-1) ]]+ , ifeature = [Durable]+ , idesc = "Broken chunks of foam concrete and glass." , ikit = [] }+doorwayTrapTemplate = ItemKind+ { isymbol = '+'+ , iname = "doorway trap"+ , ifreq = [("doorway trap unknown", 1)]+ , iflavour = zipPlain brightCol+ , icount = 1+ , irarity = [(1, 1)]+ , iverbHit = "cripple"+ , iweight = 10000+ , idamage = 0+ , iaspects = []+ , ieffects = []+ , ifeature = [HideAs "doorway trap unknown"]+ -- not Durable, springs at most once+ , idesc = "Just turn the handle..."+ , ikit = []+ }+doorwayTrap1 = doorwayTrapTemplate+ { ifreq = [("doorway trap", 50)]+ , ieffects = [toOrganBad "blind" $ (1 `dL` 4) * 10]+ -- , idesc = ""+ }+doorwayTrap2 = doorwayTrapTemplate+ { ifreq = [("doorway trap", 25)]+ , ieffects = [toOrganBad "slowed" $ (1 `dL` 4) * 10]+ -- , idesc = ""+ }+doorwayTrap3 = doorwayTrapTemplate+ { ifreq = [("doorway trap", 25)]+ , ieffects = [toOrganBad "weakened" $ (1 `dL` 4) * 10 ]+ -- , idesc = ""+ }+stairsUp = ItemKind+ { isymbol = '<'+ , iname = "flight of steps"+ , ifreq = [("staircase up", 1)]+ , iflavour = zipPlain [BrWhite]+ , icount = 1+ , irarity = [(1, 1)]+ , iverbHit = "crash" -- the verb is only used when the item hits,+ -- not when it's applied otherwise, e.g., from tile+ , iweight = 100000+ , idamage = 0+ , iaspects = []+ , ieffects = [Ascend True]+ , ifeature = [Durable]+ , idesc = "Stairs that rise towards the spaceship core."+ , ikit = []+ }+stairsDown = stairsUp+ { isymbol = '>'+ , iname = "flight of steps"+ , ifreq = [("staircase down", 1)]+ , ieffects = [Ascend False]+ , idesc = "Stairs that descend towards the outer ring."+ }+escape = stairsUp+ { isymbol = 'E'+ , iname = "way"+ , ifreq = [("escape", 1)]+ , iflavour = zipPlain [BrYellow]+ , ieffects = [Escape]+ , idesc = "" -- generic: moon outdoors, in spaceship, everywhere+ } staircaseTrapUp = ItemKind { isymbol = '^' , iname = "staircase trap" , ifreq = [("staircase trap up", 1)]- , iflavour = zipPlain [BrRed]+ , iflavour = zipPlain [Red] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "taint"+ , iverbHit = "buffet" , iweight = 10000- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [Temporary "be caught in an updraft", Teleport 5]- , ifeature = [Identified] -- not Durable, springs at most once- , idesc = "A hidden spring, to help the unwary soar."+ , ieffects = [ Temporary "be caught in decompression blast"+ , Teleport $ 3 + 1 `dL` 10 ]+ , ifeature = [] -- not Durable, springs at most once+ , idesc = "" , ikit = [] } -- Needs to be separate from staircaseTrapUp, to make sure the item is@@ -188,99 +293,117 @@ -- so that effects are invoked in the proper order and, e.g., teleport works. staircaseTrapDown = staircaseTrapUp { ifreq = [("staircase trap down", 1)]+ , iverbHit = "open up under" , ieffects = [ Temporary "tumble down the stairwell"- , toOrganActorTurn "drunk" (20 + 1 `d` 5) ]+ , toOrganGood "drunk" (20 + 1 `d` 5) ] , idesc = "A treacherous slab, to teach those who are too proud." }-doorwayTrap = ItemKind- { isymbol = '^'- , iname = "doorway trap"- , ifreq = [("doorway trap", 1)]- , iflavour = zipPlain [BrRed]+pulpit = ItemKind+ { isymbol = '?'+ , iname = "VR harness"+ , ifreq = [("pulpit", 1)]+ , iflavour = zipFancy [BrYellow] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "trap"+ , iverbHit = "immerse" , iweight = 10000- , idamage = toDmg 0+ , idamage = 0 , iaspects = []- , ieffects = [OneOf [ toOrganActorTurn "blind" (20 + 1 `d` 5)- , toOrganActorTurn "slowed" (20 + 1 `d` 5)- , toOrganActorTurn "weakened" (20 + 1 `d` 5) ]]- , ifeature = [Identified] -- not Durable, springs at most once- , idesc = "Just turn the handle..."+ , ieffects = [ OneOf [ CreateItem CGround "any scroll" timerNone+ , Detect DetectAll 20+ , Paralyze $ (1 `dL` 6) * 10+ , toOrganGood "drunk" (20 + 1 `d` 5) ]+ , Explode "story-telling" ]+ , ifeature = [] -- not Durable, springs at most once+ , idesc = "" , ikit = [] }-obscenePictograms = ItemKind- { isymbol = '*'- , iname = "repulsing graffiti"- , ifreq = [("obscene pictograms", 1)]- , iflavour = zipPlain [BrRed]++-- * Allure-specific++blackStarrySky = ItemKind+ { isymbol = ' '+ , iname = "black starry sky"+ , ifreq = [("black starry sky", 1)]+ , iflavour = zipPlain [Black] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "infuriate"+ , iverbHit = "awe" , iweight = 1000- , idamage = toDmg 0- , iaspects = [Timeout 7]- , ieffects = [ Temporary "enter unexplainable rage at a glimpse of the inscrutable graffiti"- , RefillCalm (-20)- , Recharging $ OneOf- [ toOrganActorTurn "strengthened" (3 + 1 `d` 3)- , CreateItem CInv "sandstone rock" TimerNone ] ]- , ifeature = [Identified, Durable]- , idesc = ""+ , idamage = 0+ , iaspects = []+ , ieffects = [ Temporary "look into the void and it looks back"+ , OneOf [RefillCalm 5, RefillCalm (-5)] ]+ , ifeature = [Durable]+ , idesc = "Occasionally a planet zips by, but is unable to disperse the blackness. The black starscape is constantly rotating. The frantic dance is silent, muted, indifferent. There is not even a hint of vibration, just the sense of heaviness and dizziness. At the outermost deck, the curvature of the floor is unnoticeable, but artificial gravity apparently stronger than on Earth." -- appears only on 100% flavour tiles, useless and trivial to notice, so the writeup can be longer , ikit = [] }-subtleFresco = ItemKind- { isymbol = '*'- , iname = "subtle mural"- , ifreq = [("subtle fresco", 1)]+ruinedFirstAidKit = ItemKind+ { isymbol = '?'+ , iname = "ruined first aid kit"+ , ifreq = [("ruined first aid kit", 1)] , iflavour = zipPlain [BrGreen] , icount = 1 , irarity = [(1, 1)]- , iverbHit = ""+ , iverbHit = "prick" , iweight = 1000- , idamage = toDmg 0- , iaspects = [Timeout 7]- , ieffects = [ Temporary "be entranced by the subtle mural"- , RefillCalm 2- , Recharging $ toOrganActorTurn "far-sighted" (3 + 1 `d` 3)- , Recharging $ toOrganActorTurn "keen-smelling" (3 + 1 `d` 3) ]- , ifeature = [Identified, Durable]- , idesc = "Expensive yet tasteful."+ , idamage = 0+ , iaspects = []+ , ieffects = [ Temporary "inspect a tattered CPR instruction soaked in a residue of oily drugs"+ , OneOf [ toOrganNoTimer "poison resistant"+ , toOrganNoTimer "slow resistant"+ , toOrganGood "drunk" (20 + 1 `d` 5) ]+ , CreateItem CInv "needle" timerNone ]+ , ifeature = [] -- not Durable, springs at most once+ , idesc = "" -- regulations require , ikit = [] }-scratchOnWall = ItemKind+wall3dBillboard = ItemKind { isymbol = '*'- , iname = "scratch on wall"- , ifreq = [("scratch on wall", 1)]- , iflavour = zipPlain [BrBlue]+ , iname = "3D display"+ , ifreq = [("3D display", 1)]+ , iflavour = zipPlain [BrGreen] , icount = 1 , irarity = [(1, 1)]- , iverbHit = "scratch"+ , iverbHit = "push" , iweight = 1000- , idamage = toDmg 0- , iaspects = []- , ieffects = [Temporary "start making sense of the scratches", DetectHidden 3]- , ifeature = [Identified, Durable]- , idesc = "A seemingly random series of scratches, carved deep into the wall."+ , idamage = 0+ , iaspects = [Timeout 3]+ , ieffects = [ Recharging $ Temporary "make it cough up a wobbly standalone hologram once more"+ , Recharging $ OneOf [ Explode "advertisement"+ , Explode "story-telling" ] ]+ , ifeature = [Durable]+ , idesc = "One can still make out excited moves of bleached shapes." , ikit = [] }-pulpit = ItemKind- { isymbol = 'O'- , iname = "VR harness"- , ifreq = [("pulpit", 1)]- , iflavour = zipFancy [BrBlue]- , icount = 1- , irarity = [(1, 1)]- , iverbHit = "ask"- , iweight = 10000- , idamage = toDmg 0- , iaspects = []- , ieffects = [ CreateItem CGround "any scroll" TimerNone- , Detect 20- , Paralyze 20- , toOrganActorTurn "drunk" (20 + 1 `d` 5) ]- , ifeature = [Identified] -- not Durable, springs at most once+jewelryDisplay = treasureCache+ { iname = "jewelry case"+ , ifreq = [("jewelry case", 1)]+ , ieffects = [CreateItem CGround "any jewelry" timerNone] , idesc = ""- , ikit = []+ }+liftUp = stairsUp+ { iname = "carriage"+ , ifreq = [("lift up", 1)]+ , idesc = ""+ }+liftDown = stairsDown+ { iname = "carriage"+ , ifreq = [("lift down", 1)]+ , idesc = ""+ }+liftTrap = staircaseTrapUp+ { iname = "elevator trap" -- hat tip to US heroes+ , ifreq = [("lift trap", 100)]+ , iverbHit = "squeeze"+ , ieffects = [ Temporary "be crushed by the sliding doors"+ , DropBestWeapon, Paralyze 10 ]+ , idesc = ""+ }+liftTrap2 = liftTrap+ { ifreq = [("lift trap", 50)]+ , iverbHit = "choke"+ , ieffects = [ Temporary "inhale the gas lingering inside the cab"+ , toOrganBad "slowed" $ (1 `dL` 4) * 10 ]+ , idesc = "" }
GameDefinition/Content/ItemKindOrgan.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,16 +17,17 @@ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..)) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind organs :: [ItemKind] organs =- [fist, foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP]+ [fist, foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, antler, horn, rhinoHorn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP, impressed] -- Allure-specific ++ [razor, liveWire, robotBrain, wasteContainer, spotlight] -fist, foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP :: ItemKind+fist, foot, hookedClaw, smallClaw, snout, smallJaw, jaw, largeJaw, antler, horn, rhinoHorn, tentacle, thorn, boilingFissure, arsenicFissure, sulfurFissure, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision5, vision6, vision7, vision8, vision10, vision12, vision14, vision16, nostril, insectMortality, sapientBrain, animalBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, arsenicVent, sulfurVent, bonusHP, impressed :: ItemKind -- Allure-specific razor, liveWire, robotBrain, wasteContainer, spotlight :: ItemKind @@ -43,10 +44,10 @@ , irarity = [(1, 1)] , iverbHit = "punch" , iweight = 2000- , idamage = toDmg $ 4 `d` 1+ , idamage = 4 `d` 1 , iaspects = [] , ieffects = []- , ifeature = [Durable, Identified, Meleeable]+ , ifeature = [Durable, Meleeable] , idesc = "Simple but effective." , ikit = [] }@@ -54,27 +55,27 @@ { iname = "foot" , ifreq = [("foot", 50)] , iverbHit = "kick"- , idamage = toDmg $ 4 `d` 1+ , idamage = 4 `d` 1 , idesc = "A weapon you can still use if disarmed." } --- * Universal weapon organs+-- * Other weapon organs hookedClaw = fist { iname = "hooked claw" , ifreq = [("hooked claw", 50)] , icount = 2 -- even if more, only the fore claws used for fighting , iverbHit = "hook"- , idamage = toDmg $ 2 `d` 1- , iaspects = [Timeout $ 4 + 1 `d` 4]- , ieffects = [Recharging (toOrganGameTurn "slowed" 2)]+ , idamage = 2 `d` 1+ , iaspects = [Timeout $ 12 - 1 `dL` 3]+ , ieffects = [Recharging (toOrganBad "slowed" 2)] , idesc = "A curved talon." } smallClaw = fist { iname = "small claw" , ifreq = [("small claw", 50)] , iverbHit = "slash"- , idamage = toDmg $ 2 `d` 1+ , idamage = 2 `d` 1 , idesc = "A pearly spike." } snout = fist@@ -82,7 +83,7 @@ , ifreq = [("snout", 10)] , icount = 1 , iverbHit = "bite"- , idamage = toDmg $ 2 `d` 1+ , idamage = 2 `d` 1 , idesc = "Sensitive and wide-nostrilled." } smallJaw = fist@@ -90,7 +91,7 @@ , ifreq = [("small jaw", 20)] , icount = 1 , iverbHit = "rip"- , idamage = toDmg $ 3 `d` 1+ , idamage = 3 `d` 1 , idesc = "Filled with small, even teeth." } jaw = fist@@ -98,7 +99,7 @@ , ifreq = [("jaw", 20)] , icount = 1 , iverbHit = "rip"- , idamage = toDmg $ 5 `d` 1+ , idamage = 5 `d` 1 , idesc = "Delivers a powerful bite." } largeJaw = fist@@ -106,27 +107,44 @@ , ifreq = [("large jaw", 100)] , icount = 1 , iverbHit = "crush"- , idamage = toDmg $ 10 `d` 1+ , idamage = 10 `d` 1 , idesc = "Enough to swallow anything in a single gulp." }+antler = fist+ { iname = "antler"+ , ifreq = [("antler", 100)]+ , icount = 2+ , iverbHit = "ram"+ , idamage = 4 `d` 1+ , iaspects = [Timeout $ 3 + (1 `d` 3) * 3, AddArmorMelee 10] -- bonus doubled+ , ieffects = [Recharging (PushActor (ThrowMod 100 50))] -- 1 step, slow+ , idesc = ""+ } horn = fist { iname = "horn"- , ifreq = [("horn", 20)]+ , ifreq = [("horn", 100)] , icount = 2 , iverbHit = "impale"- , idamage = toDmg $ 6 `d` 1- , iaspects = [AddHurtMelee 20]- , idesc = "Sharp and solid, for defence or attack."+ , idamage = 5 `d` 1+ , iaspects = [AddHurtMelee 10, AddArmorMelee 10] -- bonus doubled+ , idesc = "Sharp and long, for defence or attack." }---- * Special weapon organs-+rhinoHorn = fist+ { iname = "ugly horn" -- made of keratin, unlike real horns+ , ifreq = [("rhino horn", 20)]+ , icount = 1 -- single, unlike real horns+ , iverbHit = "impale"+ , idamage = 5 `d` 1+ , iaspects = [Timeout 7, AddHurtMelee 20]+ , ieffects = [Recharging Impress] -- the owner is a mid-boss, after all+ , idesc = "Very solid, considering it has the same composition as fingernails."+ } tentacle = fist { iname = "tentacle" , ifreq = [("tentacle", 50)] , icount = 4 , iverbHit = "slap"- , idamage = toDmg $ 4 `d` 1+ , idamage = 4 `d` 1 , idesc = "Damp and dextrous." } thorn = fist@@ -134,8 +152,8 @@ , ifreq = [("thorn", 100)] , icount = 2 + 1 `d` 3 , iverbHit = "impale"- , idamage = toDmg $ 1 `d` 3- , ifeature = [Identified, Meleeable] -- not Durable+ , idamage = 2 `d` 1+ , ifeature = [Meleeable] -- not Durable , idesc = "Sharp yet brittle." } boilingFissure = fist@@ -143,25 +161,25 @@ , ifreq = [("boiling fissure", 100)] , icount = 5 + 1 `d` 5 , iverbHit = "hiss at"- , idamage = toDmg $ 1 `d` 1+ , idamage = 1 `d` 1 , iaspects = [AddHurtMelee 20] -- decreasing as count decreases- , ieffects = [InsertMove $ 1 `d` 3]- , ifeature = [Identified, Meleeable] -- not Durable+ , ieffects = [DropItem 1 1 COrgan "condition"] -- useful; limited+ , ifeature = [Meleeable] -- not Durable , idesc = "" } arsenicFissure = boilingFissure { iname = "fissure" , ifreq = [("biogas fissure", 100)] , icount = 3 + 1 `d` 3- , idamage = toDmg $ 2 `d` 1- , ieffects = [toOrganGameTurn "weakened" (2 + 1 `d` 2)]+ , idamage = 2 `d` 1+ , ieffects = [] -- nothing interesting fits the weaken/poison biological data , idesc = "" } sulfurFissure = boilingFissure { iname = "fissure" , ifreq = [("medbot fissure", 100)] , icount = 2 + 1 `d` 2- , idamage = toDmg 0+ , idamage = 0 -- heal not via (negative) idamage, for armour would block it , ieffects = [RefillHP 5] , idesc = "" }@@ -170,10 +188,10 @@ , ifreq = [("bee sting", 100)] , icount = 1 , iverbHit = "sting"- , idamage = toDmg 0- , iaspects = [AddArmorMelee 90, AddArmorRanged 45]+ , idamage = 0+ , iaspects = [AddArmorMelee 200, AddArmorRanged 45] , ieffects = [Paralyze 6, RefillHP 4]- , ifeature = [Identified, Meleeable] -- not Durable+ , ifeature = [Meleeable] -- not Durable , idesc = "Painful, but beneficial." } sting = fist@@ -181,8 +199,8 @@ , ifreq = [("sting", 100)] , icount = 1 , iverbHit = "sting"- , idamage = toDmg $ 1 `d` 1- , iaspects = [Timeout $ 1 + 1 `d` 5, AddHurtMelee 40]+ , idamage = 1 `d` 1+ , iaspects = [Timeout $ 10 - 1 `dL` 4, AddHurtMelee 40] , ieffects = [Recharging (Paralyze 4)] , idesc = "Painful, debilitating and harmful." }@@ -191,9 +209,9 @@ , ifreq = [("venom tooth", 100)] , icount = 2 , iverbHit = "bite"- , idamage = toDmg $ 2 `d` 1- , iaspects = [Timeout $ 5 + 1 `d` 3]- , ieffects = [Recharging (toOrganGameTurn "slowed" (3 + 1 `d` 3))]+ , idamage = 2 `d` 1+ , iaspects = [Timeout $ 7 - 1 `dL` 3]+ , ieffects = [Recharging (toOrganBad "slowed" (3 + 1 `d` 3))] , idesc = "A chilling numbness spreads from its bite." } venomFang = fist@@ -201,9 +219,9 @@ , ifreq = [("venom fang", 100)] , icount = 2 , iverbHit = "bite"- , idamage = toDmg $ 2 `d` 1- , iaspects = [Timeout $ 7 + 1 `d` 5]- , ieffects = [Recharging (toOrganNone "poisoned")]+ , idamage = 2 `d` 1+ , iaspects = [Timeout $ 10 - 1 `dL` 4]+ , ieffects = [Recharging (toOrganNoTimer "poisoned")] , idesc = "Dripping with deadly venom." } screechingBeak = fist@@ -211,9 +229,9 @@ , ifreq = [("screeching beak", 100)] , icount = 1 , iverbHit = "peck"- , idamage = toDmg $ 2 `d` 1- , iaspects = [Timeout $ 5 + 1 `d` 5]- , ieffects = [Recharging $ Summon "scavenger" $ 1 + 1 `dl` 2]+ , idamage = 2 `d` 1+ , iaspects = [Timeout $ 7 - 1 `dL` 3]+ , ieffects = [Recharging $ Summon "scavenger" $ 1 `dL` 3] , idesc = "Both a weapon and a beacon, calling more scavengers to the meal." } largeTail = fist@@ -221,9 +239,9 @@ , ifreq = [("large tail", 50)] , icount = 1 , iverbHit = "knock"- , idamage = toDmg $ 6 `d` 1+ , idamage = 7 `d` 1 , iaspects = [Timeout $ 1 + 1 `d` 3, AddHurtMelee 20]- , ieffects = [Recharging (PushActor (ThrowMod 400 25))]+ , ieffects = [Recharging (PushActor (ThrowMod 400 50))] -- 2 steps , idesc = "Slow but heavy." } @@ -240,10 +258,10 @@ , irarity = [(1, 1)] , iverbHit = "bash" , iweight = 2000- , idamage = toDmg 0+ , idamage = 0 , iaspects = [AddArmorMelee 30, AddArmorRanged 15] , ieffects = []- , ifeature = [Durable, Identified]+ , ifeature = [Durable] , idesc = "Homemade armour is just as good." , ikit = [] }@@ -298,8 +316,9 @@ { iname = "insect mortality" , ifreq = [("insect mortality", 100)] , iverbHit = "age"- , iaspects = [Timeout $ 40 + 1 `d` 10]- , ieffects = [Periodic, Recharging (RefillHP (-1))]+ , iaspects = [Timeout $ 30 + (1 `d` 2) * 10]+ , ieffects = [Recharging (RefillHP (-1))]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" } sapientBrain = armoredSkin@@ -327,7 +346,8 @@ , iverbHit = "spit at" , iaspects = [ AddSpeed $ intToDice n , Timeout $ intToDice $ 100 `div` n ]- , ieffects = [Periodic, Recharging (RefillHP 1)]+ , ieffects = [Recharging (RefillHP 1)]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" } speedGland2 = speedGland 2@@ -338,10 +358,13 @@ scentGland = armoredSkin { iname = "scent gland" , ifreq = [("scent gland", 100)]+ , icount = 2 + 1 `d` 3 -- runs out , iverbHit = "spray at"- , iaspects = [Timeout $ (10 + 1 `d` 2) * 5 ]- , ieffects = [ Periodic, Recharging (Explode "distressing odor")+ , iaspects = [Timeout $ (1 `d` 3) * 10]+ , ieffects = [ Recharging (Temporary "look spent")+ , Recharging (Explode "distressing odor") , Recharging ApplyPerfume ]+ , ifeature = [Periodic] -- not Durable , idesc = "" } boilingVent = armoredSkin@@ -350,9 +373,9 @@ , iflavour = zipPlain [BrBlue] , iverbHit = "menace" , iaspects = [Timeout $ (2 + 1 `d` 2) * 5]- , ieffects = [Periodic- , Recharging (Explode "boiling water")+ , ieffects = [ Recharging (Explode "boiling water") , Recharging (RefillHP 2) ]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" } arsenicVent = armoredSkin@@ -361,9 +384,9 @@ , iflavour = zipPlain [BrGreen] , iverbHit = "menace" , iaspects = [Timeout $ (2 + 1 `d` 2) * 5]- , ieffects = [ Periodic- , Recharging (Explode "sparse shower")+ , ieffects = [ Recharging (Explode "sparse shower") , Recharging (RefillHP 2) ]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" } sulfurVent = armoredSkin@@ -372,21 +395,37 @@ , iflavour = zipPlain [BrYellow] , iverbHit = "menace" , iaspects = [Timeout $ (2 + 1 `d` 2) * 5]- , ieffects = [ Periodic- , Recharging (Explode "dense shower")+ , ieffects = [ Recharging (Explode "dense shower") , Recharging (RefillHP 2) ]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" }++-- * Special+ bonusHP = armoredSkin- { isymbol = '+'+ { isymbol = 'H' -- '+' reserved for conditions , iname = "bonus HP" , iflavour = zipPlain [BrBlue] , ifreq = [("bonus HP", 1)] , iverbHit = "intimidate"- , iweight = 1 -- weight 0 reserved for tmp organs+ , iweight = 0 , iaspects = [AddMaxHP 1] , idesc = "" }+impressed = armoredSkin+ { isymbol = '!'+ , iname = "impressed"+ , iflavour = zipPlain [BrRed]+ , ifreq = [("impressed", 1), ("condition", 1)]+ , iverbHit = "confuse"+ , iweight = 0+ , iaspects = [AddMaxCalm (-1)] -- to help player notice on main screen+ -- and to count as bad condition+ , ieffects = [OnSmash $ tmpNoLonger "impressed"] -- not @Periodic@+ , ifeature = [Fragile, Durable] -- hack: destroy on drop+ , idesc = ""+ } -- * Allure-specific @@ -395,7 +434,7 @@ , ifreq = [("razor", 100)] , icount = 2 + 1 `d` 5 , iverbHit = "slice"- , idamage = toDmg $ 2 `d` 1+ , idamage = 2 `d` 1 , idesc = "" } liveWire = fist@@ -403,9 +442,9 @@ , ifreq = [("live wire", 100)] , icount = 1 , iverbHit = "shock"- , idamage = toDmg $ 1 `d` 1- , iaspects = [Timeout $ 3 + 1 `d` 3, AddHurtMelee 20]- , ieffects = [ Recharging (DropItem 1 maxBound COrgan "temporary condition")+ , idamage = 0+ , iaspects = [Timeout $ 3 + 1 `d` 2, AddHurtMelee 20]+ , ieffects = [ Recharging $ Paralyze 6 , Recharging $ RefillHP (-2) ] , idesc = ""@@ -422,11 +461,11 @@ { iname = "waste container" , ifreq = [("waste container", 100)] , iverbHit = "spill over"- , iaspects = [Timeout $ (5 + 1 `d` 5) * 10]- , ieffects = [ Periodic- , Recharging (Summon "mobile animal" 1)+ , iaspects = [Timeout $ (1 + 1 `d` 2) * 30]+ , ieffects = [ Recharging (Summon "mobile animal" $ 1 `dL` 2) , Recharging (RefillHP 1) , Recharging (Explode "waste") ]+ , ifeature = [Periodic] ++ ifeature armoredSkin , idesc = "" } spotlight = armoredSkin
GameDefinition/Content/ItemKindTemporary.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,84 +16,74 @@ import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.ItemAspect (Aspect (..)) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind temporaries :: [ItemKind] temporaries =- [tmpStrengthened, tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant, tmpImpressed]--tmpStrengthened, tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant, tmpImpressed :: ItemKind+ [tmpStrengthened, tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant] -tmpNoLonger :: Text -> Effect-tmpNoLonger name = Temporary $ "be no longer" <+> name+tmpStrengthened, tmpWeakened, tmpProtectedMelee, tmpProtectedRanged, tmpVulnerable, tmpResolute, tmpFast20, tmpSlow10, tmpFarSighted, tmpBlind, tmpKeenSmelling, tmpNoctovision, 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] -> ItemKind-tmpAs name aspects = ItemKind+tmpAspects :: Text -> [Aspect] -> ItemKind+tmpAspects name aspects = ItemKind { isymbol = '+' , iname = name- , ifreq = [(toGroupName name, 1), ("temporary condition", 1)]+ , ifreq = [(toGroupName name, 1), ("condition", 1)] , iflavour = zipPlain [BrWhite] , icount = 1 , irarity = [(1, 1)] , iverbHit = "affect" , iweight = 0- , idamage = toDmg 0+ , idamage = 0 , iaspects = -- timeout is 0; activates and vanishes soon, -- depending on initial timer setting aspects- , ieffects = [ Periodic- , Recharging $ tmpNoLonger name- , OnSmash $ tmpNoLonger name ]- , ifeature = [Identified, Fragile, Durable] -- hack: destroy on drop+ , ieffects = [ Recharging $ tmpLess name+ , OnSmash $ tmpLess name ]+ , ifeature = [Periodic, Fragile, Durable] -- hack: destroy on drop , idesc = "" -- no description needed; stats are enough , ikit = [] } -tmpStrengthened = tmpAs "strengthened" [AddHurtMelee 20]-tmpWeakened = tmpAs "weakened" [AddHurtMelee (-20)]-tmpProtectedMelee = tmpAs "protected from melee" [AddArmorMelee 50]-tmpProtectedRanged = tmpAs "protected from ranged" [AddArmorRanged 25]-tmpVulnerable = tmpAs "painted red" [ AddArmorMelee (-50)- , AddArmorRanged (-25) ]-tmpResolute = tmpAs "resolute" [AddMaxCalm 60]-tmpFast20 = tmpAs "hasted" [AddSpeed 20]-tmpSlow10 = tmpAs "slowed" [AddSpeed (-10)]-tmpFarSighted = tmpAs "far-sighted" [AddSight 5]-tmpBlind = tmpAs "blind" [AddSight (-99)]-tmpKeenSmelling = tmpAs "keen-smelling" [AddSmell 2]-tmpNoctovision = tmpAs "shiny-eyed" [AddNocto 2]-tmpDrunk = tmpAs "drunk" [ AddHurtMelee 30 -- fury- , AddArmorMelee (-20)- , AddArmorRanged (-20)- , AddSight (-8)- ]-tmpRegenerating =- let tmp = tmpAs "regenerating" []- in tmp { icount = 4 + 1 `d` 2- , ieffects = Recharging (RefillHP 1) : ieffects tmp+tmpEffects :: Text -> Dice -> [Effect] -> ItemKind+tmpEffects name icount effects =+ let tmp = tmpAspects name []+ in tmp { icount+ , ieffects = effects+ ++ [ Recharging $ tmpNoLonger name+ , OnSmash $ tmpNoLonger name ] }++tmpStrengthened = tmpAspects "strengthened" [AddHurtMelee 20]+tmpWeakened = tmpAspects "weakened" [AddHurtMelee (-30)] -- don't cancel out ^+tmpProtectedMelee = tmpAspects "protected from melee" [AddArmorMelee 50]+tmpProtectedRanged = tmpAspects "protected from ranged" [AddArmorRanged 25]+tmpVulnerable = tmpAspects "painted red" [ AddArmorMelee (-50)+ , AddArmorRanged (-25) ]+tmpResolute = tmpAspects "resolute" [AddMaxCalm 60]+tmpFast20 = tmpAspects "hasted" [AddSpeed 20]+tmpSlow10 = tmpAspects "slowed" [AddSpeed (-10)]+tmpFarSighted = tmpAspects "far-sighted" [AddSight 5]+tmpBlind = tmpAspects "blind" [AddSight (-99)]+tmpKeenSmelling = tmpAspects "keen-smelling" [AddSmell 2]+tmpNoctovision = tmpAspects "shiny-eyed" [AddNocto 2]+tmpDrunk = tmpAspects "drunk" [ AddHurtMelee 30 -- fury+ , AddArmorMelee (-20)+ , AddArmorRanged (-20)+ , AddSight (-8)+ ]++tmpRegenerating =+ tmpEffects "regenerating" (4 + 1 `d` 2) [Recharging (RefillHP 1)] tmpPoisoned =- let tmp = tmpAs "poisoned" []- in tmp { icount = 4 + 1 `d` 2- , ieffects = Recharging (RefillHP (-1)) : ieffects tmp- }+ tmpEffects "poisoned" (4 + 1 `d` 2) [Recharging (RefillHP (-1))] tmpSlow10Resistant =- let tmp = tmpAs "slow resistant" []- in tmp { icount = 8 + 1 `d` 4- , ieffects = Recharging (DropItem 1 1 COrgan "slowed") : ieffects tmp- }+ tmpEffects "slow resistant" (8 + 1 `d` 4)+ [Recharging (DropItem 1 1 COrgan "slowed")] tmpPoisonResistant =- let tmp = tmpAs "poison resistant" []- in tmp { icount = 8 + 1 `d` 4- , ieffects = Recharging (DropItem 1 maxBound COrgan "poisoned")- : ieffects tmp- }-tmpImpressed =- let tmp = tmpAs "impressed" []- in tmp { isymbol = '!'- , ifreq = [("impressed", 1)] -- no "temporary condition"- , ieffects = [OnSmash $ tmpNoLonger "impressed"] -- not @Periodic@- }+ tmpEffects "poison resistant" (8 + 1 `d` 4)+ [Recharging (DropItem 1 maxBound COrgan "poisoned")]
GameDefinition/Content/ModeKind.hs view
@@ -1,12 +1,12 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game mode definitions. module Content.ModeKind- ( cdefs+ ( content ) where import Prelude ()@@ -16,22 +16,15 @@ import qualified Data.IntMap.Strict as IM import Content.ModeKindPlayer-import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice import Game.LambdaHack.Content.ModeKind -cdefs :: ContentDef ModeKind-cdefs = ContentDef- { getSymbol = msymbol- , getName = mname- , getFreq = mfreq- , validateSingle = validateSingleModeKind- , validateAll = validateAllModeKind- , content = contentFromList- [raid, brawl, shootout, escape, zoo, ambush, crawl, crawlSurvival, safari, safariSurvival, battle, battleSurvival, defense, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverCrawl, screensaverSafari]- }-raid, brawl, shootout, escape, zoo, ambush, crawl, crawlSurvival, safari, safariSurvival, battle, battleSurvival, defense, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverCrawl, screensaverSafari :: ModeKind+content :: [ModeKind]+content =+ [raid, brawl, shootout, escape, zoo, ambush, crawl, crawlEmpty, crawlSurvival, safari, safariSurvival, battle, battleSurvival, defense, defenseEmpty, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverCrawl, screensaverSafari] +raid, brawl, shootout, escape, zoo, ambush, crawl, crawlEmpty, crawlSurvival, safari, safariSurvival, battle, battleSurvival, defense, defenseEmpty, screensaverRaid, screensaverBrawl, screensaverShootout, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverCrawl, screensaverSafari :: ModeKind+ -- What other symmetric (two only-one-moves factions) and asymmetric vs crowd -- scenarios make sense (e.g., are good for a tutorial or for standalone -- extreme fun or are impossible as part of a crawl)?@@ -135,6 +128,15 @@ -- * Testing modes +crawlEmpty = ModeKind+ { msymbol = 'c'+ , mname = "crawl empty"+ , mfreq = [("crawl empty", 1)]+ , mroster = rosterCrawlEmpty+ , mcaves = cavesCrawl+ , mdesc = "Enjoy the free space."+ }+ crawlSurvival = ModeKind { msymbol = 'd' , mname = "crawl survival"@@ -180,6 +182,15 @@ , mdesc = "Don't let the half-witted humans derail your operation and flee, like the puny, naked, tentacle-less beasts that they are!" } +defenseEmpty = ModeKind+ { msymbol = 'e'+ , mname = "defense empty"+ , mfreq = [("defense empty", 1)]+ , mroster = rosterDefenseEmpty+ , mcaves = cavesCrawl+ , mdesc = "Lord over."+ }+ -- * Screensaver modes screensave :: AutoLeader -> Roster -> Roster@@ -238,7 +249,7 @@ screensave (AutoLeader False True) rosterSafari } -rosterRaid, rosterBrawl, rosterShootout, rosterEscape, rosterZoo, rosterAmbush, rosterCrawl, rosterCrawlSurvival, rosterSafari, rosterSafariSurvival, rosterBattle, rosterBattleSurvival, rosterDefense :: Roster+rosterRaid, rosterBrawl, rosterShootout, rosterEscape, rosterZoo, rosterAmbush, rosterCrawl, rosterCrawlEmpty, rosterCrawlSurvival, rosterSafari, rosterSafariSurvival, rosterBattle, rosterBattleSurvival, rosterDefense, rosterDefenseEmpty :: Roster rosterRaid = Roster { rosterList = [ ( playerHero {fhiCondPoly = hiRaid}@@ -297,6 +308,7 @@ , [(7, 1, "scout hero"), (7, 2, "escapist hero")] ) , ( playerAntiHero { fname = "Red Collar Bro" , fcanEscape = False -- start on escape+ , fneverEmpty = False -- loot after killing , fhiCondPoly = hiDweller } , [(7, 1, "scout hero"), (7, 7, "ambusher hero")] ) , (playerHorror, []) ]@@ -320,14 +332,14 @@ { rosterList = [ ( playerHero { fcanEscape = False , fhiCondPoly = hiDweller } , [(9, 1, "scout hero"), (9, 5, "ambusher hero")] )- , ( playerAntiHero { fname = "Gray Off-world Mercenary"+ , ( playerAntiHero { fname = "Gray Off-World Mercenary" , fcanEscape = False , fhiCondPoly = hiDweller } , [(9, 1, "scout hero"), (9, 5, "ambusher hero")] ) , (playerHorror, []) ]- , rosterEnemy = [ ("Spacefarer", "Gray Off-world Mercenary")+ , rosterEnemy = [ ("Spacefarer", "Gray Off-World Mercenary") , ("Spacefarer", "Horror Den")- , ("Gray Off-world Mercenary", "Horror Den") ]+ , ("Gray Off-World Mercenary", "Horror Den") ] , rosterAlly = [] } rosterCrawl = Roster@@ -347,6 +359,13 @@ , ("Alien Hierarchy", "Robot Anarchy") , ("Robot Anarchy", "Animal Kingdom") ] } +rosterCrawlEmpty = Roster+ { rosterList = [ ( playerHero+ , [(1, 1, "hero")] )+ , (playerHorror, []) ] -- for summoned monsters+ , rosterEnemy = []+ , rosterAlly = [] }+ rosterCrawlSurvival = rosterCrawl { rosterList = [ ( playerHero { fleaderMode = LeaderAI $ AutoLeader True False@@ -444,6 +463,13 @@ , (12, 100, "mobile animal") ] ) , ( playerRobot , [] ) ] } -- gentle introduction++rosterDefenseEmpty = rosterCrawl+ { rosterList = [ ( playerAntiMonster {fneverEmpty = True}+ , [(4, 1, "scout monster")] )+ , (playerHorror, []) ] -- for summoned animals+ , rosterEnemy = []+ , rosterAlly = [] } cavesRaid, cavesBrawl, cavesShootout, cavesEscape, cavesZoo, cavesAmbush, cavesCrawl, cavesSafari, cavesBattle :: Caves
GameDefinition/Content/ModeKindPlayer.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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.@@ -19,7 +19,6 @@ import Game.LambdaHack.Common.Prelude import Game.LambdaHack.Common.Ability-import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind @@ -59,7 +58,7 @@ playerMonster = Player { fname = "Alien Hierarchy"- , fgroups = ["monster", "mobile monster", "immobile monster"]+ , fgroups = ["monster", "mobile monster"] , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False@@ -137,13 +136,13 @@ hiHero, hiRaid, hiDweller, hiEscapist :: HiCondPoly -- Heroes rejoice in loot.-hiHero = [ ( [(HiLoot, 1)]+hiHero = [ ( [(HiLoot, 1000)] -- multiplied by fraction of collected , [minBound..maxBound] ) , ( [(HiConst, 1000), (HiLoss, -1)] , victoryOutcomes ) ] -hiRaid = [ ( [(HiLoot, 1)]+hiRaid = [ ( [(HiLoot, 100)] , [minBound..maxBound] ) , ( [(HiConst, 100)] , victoryOutcomes )@@ -161,7 +160,7 @@ , [minBound..maxBound] \\ victoryOutcomes ) ] -hiEscapist = ( [(HiLoot, 1)] -- loot matters a little bit+hiEscapist = ( [(HiLoot, 200)] -- loot matters a little bit , [minBound..maxBound] ) : hiDweller @@ -169,7 +168,7 @@ playerRobot = Player { fname = "Robot Anarchy"- , fgroups = ["robot", "mobile robot", "immobile robot"]+ , fgroups = ["robot", "mobile robot", "immobile robot", "construction robot"] , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False
GameDefinition/Content/PlaceKind.hs view
@@ -1,37 +1,30 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Room, hall and passage definitions. module Content.PlaceKind- ( cdefs+ ( content ) where import Prelude () import Game.LambdaHack.Common.Prelude -import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.PlaceKind -cdefs :: ContentDef PlaceKind-cdefs = ContentDef- { getSymbol = psymbol- , getName = pname- , getFreq = pfreq- , validateSingle = validateSinglePlaceKind- , validateAll = validateAllPlaceKind- , content = contentFromList $- [rect, rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown]- ++ map makeStaircaseUp lstaircase- ++ map makeStaircaseDown lstaircase- -- Allure-specific- ++ [staircaseLift, escapeSpaceshipDown, escapeSpaceshipDown2, escapeSpaceshipDown3, escapeSpaceshipDown4, escapeSpaceshipDown5, colonnadeWide, oval, ovalFloor, ovalSquare, maze, maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells, cells2, cells3, cells4, cells5, cells6, cells7]- }-rect, rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown :: PlaceKind+content :: [PlaceKind]+content =+ [rect, rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown]+ ++ map makeStaircaseUp lstaircase+ ++ map makeStaircaseDown lstaircase+ -- Allure-specific+ ++ [staircaseLift, escapeSpaceshipDown, escapeSpaceshipDown2, escapeSpaceshipDown3, escapeSpaceshipDown4, escapeSpaceshipDown5, colonnadeWide, oval, ovalFloor, ovalSquare, maze, maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells, cells2, cells3, cells4, cells5, cells6, cells7]++rect, rectWindows, glasshouse, pulpit, ruin, collapsed, collapsed2, collapsed3, collapsed4, collapsed5, collapsed6, collapsed7, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnade5, colonnade6, lampPost, lampPost2, lampPost3, lampPost4, treeShade, fogClump, fogClump2, smokeClump, smokeClump2FGround, bushClump, staircase, staircase2, staircase3, staircase4, staircase5, staircase6, staircase7, staircase8, staircase9, staircase10, staircase11, staircase12, staircase13, staircase14, staircase15, staircase16, staircase17, staircaseOutdoor, staircaseGated, escapeUp, escapeUp2, escapeUp3, escapeUp4, escapeUp5, escapeDown, escapeDown2, escapeDown3, escapeDown4, escapeDown5, escapeOutdoorDown :: PlaceKind -- Allure-specific staircaseLift, escapeSpaceshipDown, escapeSpaceshipDown2, escapeSpaceshipDown3, escapeSpaceshipDown4, escapeSpaceshipDown5, colonnadeWide, oval, ovalFloor, ovalSquare, maze, maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells, cells2, cells3, cells4, cells5, cells6, cells7 :: PlaceKind @@ -54,7 +47,7 @@ rectWindows = PlaceKind { psymbol = 'w' , pname = "room"- , pfreq = [("empty", 10), ("park", 7)]+ , pfreq = [("empty", 10), ("park", 6)] , prarity = [(1, 10), (10, 8)] , pcover = CStretch , pfence = FNone@@ -103,7 +96,7 @@ } collapsed = PlaceKind -- in a dark cave, they have little lights --- that's OK { psymbol = 'c'- , pname = "collapsed cavern"+ , pname = "hardware stack" , pfreq = [("noise", 1)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch@@ -153,7 +146,7 @@ } pillar = PlaceKind { psymbol = 'p'- , pname = "pillar room"+ , pname = "commercial space" , pfreq = [ ("rogue", 500), ("arena", 1000), ("laboratory", 1000) , ("empty", 300), ("noise", 1000) ] , prarity = [(1, 10), (10, 10)]@@ -165,7 +158,7 @@ , "····" , "····" ]- , poverride = [('&', "cachable")]+ , poverride = [('&', "cache deposit")] } pillar2 = pillar { ptopLeft = [ "··#·"@@ -194,7 +187,7 @@ { psymbol = 'c' , pname = "colonnade" , pfreq = [ ("rogue", 30), ("arena", 70), ("laboratory", 40)- , ("empty", 100), ("mine", 10000), ("park", 3000) ]+ , ("empty", 100), ("mine", 10000), ("park", 4000) ] , prarity = [(1, 3), (10, 3)] , pcover = CAlternate , pfence = FFloor@@ -300,7 +293,7 @@ , poverride = [('f', "fogClumpOver_f_Lit"), (';', "lit fog")] } fogClump2 = fogClump- { pfreq = [("shootout", 400), ("empty", 1500)]+ { pfreq = [("shootout", 400), ("empty", 7000)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FNone@@ -313,7 +306,7 @@ smokeClump = PlaceKind { psymbol = 's' , pname = "smoky patch"- , pfreq = [("zoo", 100), ("ambush", 50)]+ , pfreq = [("zoo", 50), ("ambush", 50)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FNone@@ -325,7 +318,7 @@ , ('·', "floorActorLit") ] } smokeClump2FGround = smokeClump- { pfreq = [("laboratory", 100), ("zoo", 1000), ("ambush", 500)]+ { pfreq = [("laboratory", 100), ("zoo", 500), ("ambush", 500)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FGround@@ -355,7 +348,7 @@ , prarity = [(1, 1)] , pcover = CVerbatim , pfence = FGround- , ptopLeft = [ "<·>"+ , ptopLeft = [ "<#>" ] , poverride = [ ('<', "staircase up"), ('>', "staircase down") , ('I', "signboard") ]@@ -365,7 +358,7 @@ , pfence = FFloor , ptopLeft = [ "#·#" , "···"- , "<·>"+ , "<#>" , "···" , "#·#" ]@@ -373,11 +366,11 @@ staircase3 = staircaseLift { pfreq = [("staircase lift", 1000)] , pfence = FWall- , ptopLeft = [ "#·I·#"+ , ptopLeft = [ "#···#" , "·····"- , "·<·>·"+ , "·<I>·" , "·····"- , "#·I·#"+ , "#···#" ] } staircase4 = staircaseLift@@ -385,7 +378,7 @@ , pfence = FWall , ptopLeft = [ "#·#·#·#" , "·······"- , "#·<·>·#"+ , "#·<#>·#" , "·······" , "#·#·#·#" ]@@ -393,26 +386,26 @@ staircase5 = staircase { pfreq = [("staircase", 100)] , pfence = FGround- , ptopLeft = [ "#·<·>·#"+ , ptopLeft = [ "#·<#>·#" ] } staircase6 = staircase { pfreq = [("staircase", 100)] , pfence = FGround- , ptopLeft = [ "#··<·>··#"+ , ptopLeft = [ "#··<#>··#" ] } staircase7 = staircase { pfreq = [("staircase", 100)] , pfence = FGround- , ptopLeft = [ "#·I·<·>·I·#"+ , ptopLeft = [ "I·#·<#>·#·I" ] } staircase8 = staircase { pfreq = [("staircase", 1000)] , pfence = FFloor , ptopLeft = [ "#·····#"- , "··<·>··"+ , "··<#>··" , "#·····#" ] }@@ -420,7 +413,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "#·······#"- , "·#·<·>·#·"+ , "·#·<#>·#·" , "#·······#" ] }@@ -428,7 +421,7 @@ { pfreq = [("staircase", 1000)] , pfence = FFloor , ptopLeft = [ "·#·····#·"- , "#··<·>··#"+ , "#··<#>··#" , "·#·····#·" ] }@@ -437,7 +430,7 @@ , pfence = FGround , ptopLeft = [ "··#·#··" , "#·····#"- , "··<·>··"+ , "··<#>··" , "#·····#" , "··#·#··" ]@@ -446,7 +439,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "·····"- , "·<·>·"+ , "·<#>·" , "·····" ] }@@ -454,7 +447,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "·······"- , "#·<·>·#"+ , "#·<#>·#" , "·······" ] }@@ -462,7 +455,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "·········"- , "·#·<·>·#·"+ , "·#·<#>·#·" , "·········" ] }@@ -470,7 +463,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "···········"- , "#·I·<·>·I·#"+ , "#·I·<#>·I·#" , "···········" ] }@@ -478,7 +471,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "#·····#"- , "··<·>··"+ , "··<#>··" , "#·····#" ] }@@ -486,7 +479,7 @@ { pfreq = [("staircase lift", 1000)] , pfence = FWall , ptopLeft = [ "·#·····#·"- , "#··<·>··#"+ , "#··<#>··#" , "·#·····#·" ] }@@ -502,7 +495,7 @@ } escapeUp = PlaceKind { psymbol = '<'- , pname = "escape up"+ , pname = "escape airlock up" , pfreq = [("escape up", 1)] , prarity = [(1, 1)] , pcover = CVerbatim@@ -522,7 +515,7 @@ escapeUp3 = escapeUp { pfreq = [("escape down", 2000)] , pcover = CMirror- , pfence = FFloor+ , pfence = FWall , ptopLeft = [ "#··" , "·<·" , "#·#"@@ -530,7 +523,7 @@ } escapeUp4 = escapeUp { pfreq = [("escape up", 1000)]- , pfence = FWall+ , pfence = FFloor , ptopLeft = [ "·#·" , "#<#" , "·#·"@@ -547,7 +540,7 @@ } escapeDown = PlaceKind { psymbol = '>'- , pname = "escape down"+ , pname = "escape airlock down" , pfreq = [("escape down", 1)] , prarity = [(1, 1)] , pcover = CVerbatim@@ -567,7 +560,7 @@ escapeDown3 = escapeDown { pfreq = [("escape down", 2000)] , pcover = CMirror- , pfence = FFloor+ , pfence = FWall , ptopLeft = [ "#··" , "·>·" , "#·#"@@ -575,7 +568,7 @@ } escapeDown4 = escapeDown { pfreq = [("escape down", 1000)]- , pfence = FWall+ , pfence = FFloor , ptopLeft = [ "·#·" , "#>#" , "·#·"@@ -598,7 +591,7 @@ -- * Allure-specific staircaseLift = staircase- { pname = "staircase lift"+ { pname = "lift" , pfreq = [("staircase lift", 1)] , poverride = [ ('<', "staircase lift up"), ('>', "staircase lift down") , ('I', "signboard") ]@@ -670,7 +663,7 @@ } maze = PlaceKind { psymbol = 'm'- , pname = "maze"+ , pname = "mysterious maze" , pfreq = [("rogue", 20), ("arena", 20), ("empty", 20)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch@@ -680,7 +673,7 @@ , "##··#" , "#··#·" ]- , poverride = [('&', "cachable")]+ , poverride = [('&', "cache jewelry")] } maze2 = maze { pfreq = [("rogue", 40), ("arena", 40), ("empty", 40)]@@ -726,7 +719,7 @@ } cells = PlaceKind { psymbol = '#'- , pname = "cells"+ , pname = "broken holding pens" , pfreq = [ ("rogue", 20), ("arena", 20), (" laboratory", 20) , ("empty", 20), ("noise", 20), ("zoo", 200) ] , prarity = [(1, 10), (10, 10)]@@ -766,7 +759,7 @@ } cells6 = cells { pfreq = [ ("rogue", 1), ("arena", 2), ("laboratory", 2)- , ("empty", 2), ("noise", 1), ("zoo", 100) ]+ , ("empty", 2), ("noise", 1), ("zoo", 10) ] , ptopLeft = [ "··#" , "##·" ]@@ -787,9 +780,7 @@ { psymbol = '<' , pname = pname s <+> "up" , pfreq = map (\(t, k) -> (toGroupName $ tshow t <+> "up", k)) $ pfreq s- , poverride = [ ('>', "stair terminal")- , ('<', toGroupName $ pname s <+> "up")- , ('I', "signboard") ]+ , poverride = ('>', "stair terminal") : filter ((/= '>') . fst) (poverride s) } makeStaircaseDown :: PlaceKind -> PlaceKind@@ -797,7 +788,5 @@ { psymbol = '>' , pname = pname s <+> "down" , pfreq = map (\(t, k) -> (toGroupName $ tshow t <+> "down", k)) $ pfreq s- , poverride = [ ('<', "stair terminal")- , ('>', toGroupName $ pname s <+> "down")- , ('I', "signboard") ]+ , poverride = ('<', "stair terminal") : filter ((/= '<') . fst) (poverride s) }
GameDefinition/Content/RuleKind.hs view
@@ -1,13 +1,13 @@ {-# LANGUAGE TemplateHaskell #-} -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game rules and assorted game setup data. module Content.RuleKind- ( cdefs+ ( content ) where import Prelude ()@@ -21,19 +21,10 @@ -- Cabal import qualified Paths_Allure as Self (getDataFileName, version) -import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Content.RuleKind -cdefs :: ContentDef RuleKind-cdefs = ContentDef- { getSymbol = rsymbol- , getName = rname- , getFreq = rfreq- , validateSingle = validateSingleRuleKind- , validateAll = validateAllRuleKind- , content = contentFromList- [standard]- }+content :: [RuleKind]+content = [standard] standard :: RuleKind standard = RuleKind@@ -53,19 +44,41 @@ qAddDependentFile path x <- qRunIO (readFile path) lift x)- -- ASCII art for the Main Menu. Only pure 7-bit ASCII characters are allowed- -- for the art part. The picture should be exactly 24 rows by 80 columns.- -- For a different screen size, the picture is centered and padded.- -- with spaces. When displayed in the Main Menu screen, the picture- -- is overwritten with game and engine version strings and keybindings.+ -- ASCII art for the main menu. Only pure 7-bit ASCII characters are allowed.+ -- When displayed in the main menu screen, the picture is overwritten+ -- with game and engine version strings and keybindings. -- The keybindings overwrite places marked with left curly brace signs.- -- The sign is forbidden anywhere else. The Main Menu is displayed dull- -- white on black.+ -- This sign is forbidden anywhere else in the picture.+ -- The picture and the whole main menu is displayed dull white on black.+ --+ -- The picture should be exactly 60 rows by 110 columns,+ -- but only the middle rectangle of 24 rows by 80 columns is partially+ -- overwritten with UI information and the curly brace signs are allowed+ -- only there. So, the rectangle is 15 characters distant from the left+ -- and 18 from top. For screen sizes larger than 60 by 100,+ -- the picture is centered and padded with spaces, so it makes sense+ -- for some or all of the picture borders to be spaces, as well.+ -- If the screen is smaller than 60 by 100, borders of the picture+ -- are cut off. Minimal screes size is 24 by 80 and the picture+ -- should look well at this size, as well. , rmainMenuArt = $(do let path = "GameDefinition/MainMenu.ascii" qAddDependentFile path x <- qRunIO (readFile path) lift x)+ , rintroScreen = $(do+ let path = "GameDefinition/PLAYING.md"+ qAddDependentFile path+ x <- qRunIO (readFile path)+ let paragraphs :: [String] -> [String] -> [[String]]+ paragraphs [] rows = [reverse rows]+ paragraphs (l : ls) rows = if null l+ then reverse rows : paragraphs ls []+ else paragraphs ls (l : rows)+ intro = case paragraphs (lines x) [] of+ _title : _blurb : par1 : par2 : _rest -> par1 ++ [""] ++ par2+ _ -> error "not enough paragraphs in intro screen text"+ lift intro) , rfirstDeathEnds = False , rwriteSaveClips = 1000 , rleadLevelClips = 50
GameDefinition/Content/TileKind.hs view
@@ -1,12 +1,12 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Terrain tile definitions. module Content.TileKind- ( cdefs+ ( content ) where import Prelude ()@@ -16,29 +16,22 @@ import qualified Data.Text as T import Game.LambdaHack.Common.Color-import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.TileKind -cdefs :: ContentDef TileKind-cdefs = ContentDef- { getSymbol = tsymbol- , getName = tname- , getFreq = tfreq- , validateSingle = validateSingleTileKind- , validateAll = validateAllTileKind- , content = contentFromList $- [unknown, hardRock, wall, wallSuspect, wallObscured, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorArenaShade ]- ++ map makeDarkColor ldarkColorable- -- Allure-specific- ++ [oriel, outerHullWall, doorlessWall, machineWall, wallObscuredDefaced, wallObscuredFrescoed, rock, stairsLiftUp, stairsLiftDown, escapeSpaceshipDown]- }-unknown, hardRock, wall, wallSuspect, wallObscured, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorArenaShade :: TileKind+content :: [TileKind]+content =+ [unknown, unknownOuterFence, basicOuterFence, wall, wallSuspect, wallObscured, wallObscuredDefaced, wallObscuredFrescoed, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTrappedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTrappedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorBrown, floorArenaShade ]+ ++ map makeDarkColor ldarkColorable+ -- Allure-specific+ ++ [oriel, outerHullWall, doorlessWall, machineWall, wallObscuredSafety, wallObscured3dBillboard, rock, pillarCache2, stairsLiftUp, stairsLiftTrappedUp, stairsLiftDown, stairsLiftTrappedDown, escapeSpaceshipDown, floorWindow]++unknown, unknownOuterFence, basicOuterFence, wall, wallSuspect, wallObscured, wallObscuredDefaced, wallObscuredFrescoed, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTrappedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTrappedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorBrown, floorArenaShade :: TileKind -- Allure-specific-oriel, outerHullWall, doorlessWall, machineWall, wallObscuredDefaced, wallObscuredFrescoed, rock, stairsLiftUp, stairsLiftDown, escapeSpaceshipDown :: TileKind+oriel, outerHullWall, doorlessWall, machineWall, wallObscuredSafety, wallObscured3dBillboard, rock, pillarCache2, stairsLiftUp, stairsLiftTrappedUp, stairsLiftDown, stairsLiftTrappedDown, escapeSpaceshipDown, floorWindow :: TileKind ldarkColorable :: [TileKind]-ldarkColorable = [tree, bush, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem]+ldarkColorable = [tree, bush, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorWindow] -- Symbols to be used: -- LOS noLOS@@ -74,7 +67,16 @@ , talter = 1 , tfeature = [Dark] }-hardRock = TileKind+unknownOuterFence = TileKind+ { tsymbol = ' '+ , tname = "unknown space"+ , tfreq = [("unknown outer fence", 1)]+ , tcolor = defFG+ , tcolor2 = defFG+ , talter = maxBound -- impenetrable+ , tfeature = [Dark]+ }+basicOuterFence = TileKind { tsymbol = '#' , tname = "habitat containment wall" , tfreq = [("basic outer fence", 1)]@@ -87,23 +89,24 @@ { tsymbol = '#' , tname = "wall" , tfreq = [ ("fillerWall", 1), ("legendLit", 100), ("legendDark", 100)- , ("cachable", 80), ("stair terminal", 100)+ , ("cachable deposit", 80), ("cachable jewelry", 80)+ , ("stair terminal", 100) , ("battleSet", 250), ("rectWindowsOver_%_Lit", 80) ] , tcolor = BrWhite , tcolor2 = defFG , talter = 100- , tfeature = [BuildAs "suspect wall", Indistinct]+ , tfeature = [BuildAs "suspect wall"] } wallSuspect = TileKind -- only on client { tsymbol = '#'- , tname = "suspect uneven wall"+ , tname = "suspect wall" , tfreq = [("suspect wall", 1)] , tcolor = BrWhite , tcolor2 = defFG , talter = 2 , tfeature = [ RevealAs "trapped door" , ObscureAs "obscured wall"- , Indistinct ]+ ] } wallObscured = TileKind { tsymbol = '#'@@ -114,29 +117,55 @@ , talter = 5 , tfeature = [ Embed "scratch on wall" , HideAs "suspect wall"- , Indistinct+ ] }+wallObscuredDefaced = TileKind+ { tsymbol = '#'+ , tname = "defaced wall"+ , tfreq = [("obscured wall", 45), ("escapeSetDark", 1)]+ , tcolor = BrWhite+ , tcolor2 = defFG+ , talter = 5+ , tfeature = [ Embed "obscene pictogram"+ , HideAs "suspect wall"++ ]+ }+wallObscuredFrescoed = TileKind+ { tsymbol = '#'+ , tname = "subtle mural"+ , tfreq = [("obscured wall", 5), ("brawlSetLit", 1)]+ , tcolor = BrWhite+ , tcolor2 = defFG+ , talter = 5+ , tfeature = [ Embed "subtle fresco"+ , HideAs "suspect wall"++ ] -- a bit beneficial, but AI would loop if allowed to trigger+ -- so no @ConsideredByAI@+ } pillar = TileKind { tsymbol = 'O'- , tname = "pillar"+ , tname = "construction beam" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrCyan -- not BrWhite, to tell from heroes , tcolor2 = Cyan , talter = 100- , tfeature = [Indistinct]+ , tfeature = [] } pillarCache = TileKind { tsymbol = '#'- , tname = "cache"- , tfreq = [("cachable", 20), ("stair terminal", 1), ("escapeSetDark", 1)]+ , tname = "rack of deposit boxes"+ , tfreq = [ ("cachable deposit", 20), ("cache deposit", 1)+ , ("stair terminal", 1) ] , tcolor = BrBlue , tcolor2 = Blue , talter = 5- , tfeature = [ Embed "terrain cache", Embed "terrain cache trap"- , ChangeTo "cachable", ConsideredByAI, Indistinct ]+ , tfeature = [ Embed "treasure cache", Embed "treasure cache trap"+ , ChangeTo "cachable deposit", ConsideredByAI ] -- Not explorable, but prominently placed, so hard to miss.- -- Very beneficial, so AI eager to trigger.+ -- Very beneficial, so AI eager to trigger, unless wary of traps. } lampPost = TileKind { tsymbol = 'O'@@ -156,23 +185,23 @@ , talter = 5 , tfeature = [ ConsideredByAI -- changes after use, so safe for AI , RevealAs "signboard" -- to display as hidden- , Indistinct+ ] } signboardRead = TileKind { tsymbol = 'O' , tname = "signboard"- , tfreq = [("signboard", 1), ("zooSet", 2), ("ambushSet", 1)]+ , tfreq = [("signboard", 1), ("escapeSetDark", 1)] , tcolor = BrCyan , tcolor2 = Cyan , talter = 5- , tfeature = [Embed "signboard", HideAs "signboard unread", Indistinct]+ , tfeature = [Embed "signboard", HideAs "signboard unread"] } tree = TileKind { tsymbol = 'O' , tname = "tree" , tfreq = [ ("brawlSetLit", 140), ("shootoutSetLit", 10)- , ("escapeSetLit", 30), ("treeShadeOver_O_Lit", 1) ]+ , ("escapeSetLit", 35), ("treeShadeOver_O_Lit", 1) ] , tcolor = BrGreen , tcolor2 = Green , talter = 50@@ -180,14 +209,14 @@ } treeBurnt = tree { tname = "burnt tree"- , tfreq = [("zooSet", 3), ("tree with fire", 30)]+ , tfreq = [("zooSet", 7), ("tree with fire", 30)] , tcolor = BrBlack , tcolor2 = BrBlack , tfeature = Dark : tfeature tree } treeBurning = tree { tname = "burning tree"- , tfreq = [("zooSet", 30), ("tree with fire", 70)]+ , tfreq = [("zooSet", 70), ("tree with fire", 70)] , tcolor = BrRed , tcolor2 = Red , talter = 5@@ -197,7 +226,7 @@ } rubble = TileKind { tsymbol = '&'- , tname = "rubble"+ , tname = "rubble pile" , tfreq = [] -- [("floorCorridorLit", 1)] -- disabled while it's all or nothing per cave and per room; -- we need a new mechanism, Spice is not enough, because@@ -206,18 +235,19 @@ -- until we can sync change of tile and activation, it always takes 1 turn , tcolor = BrYellow , tcolor2 = Brown- , talter = 5- , tfeature = [OpenTo "rubbleOrNot", Embed "rubble", Indistinct]+ , talter = 4 -- boss can dig through+ , tfeature = [OpenTo "rubbleOrNot", Embed "rubble"] } rubbleSpice = TileKind { tsymbol = '&'- , tname = "rubble"- , tfreq = [ ("smokeClumpOver_f_Lit", 1), ("emptySet", 1), ("noiseSet", 10)- , ("zooSet", 100), ("ambushSet", 20) ]+ , tname = "rubble pile"+ , tfreq = [ ("smokeClumpOver_f_Lit", 1), ("emptySet", 1)+ , ("emptyExitSet", 1), ("noiseSet", 10), ("zooSet", 100)+ , ("ambushSet", 20) ] , tcolor = BrYellow , tcolor2 = Brown- , talter = 5- , tfeature = [Spice, OpenTo "rubbleSpiceOrNot", Embed "rubble", Indistinct]+ , talter = 4 -- boss can dig through+ , tfeature = [Spice, OpenTo "rubbleSpiceOrNot", Embed "rubble"] -- It's not explorable, due to not being walkable nor clear and due -- to being a door (@OpenTo@), which is kind of OK, because getting -- the item is risky and, e.g., AI doesn't attempt it.@@ -250,12 +280,12 @@ , tfreq = [("staircase up", 9), ("ordinary staircase up", 1)] , tcolor = BrWhite , tcolor2 = defFG- , talter = talterForStairs+ , talter = 0 -- very easy stairs, unlike all others , tfeature = [Embed "staircase up", ConsideredByAI] }-stairsTaintedUp = TileKind+stairsTrappedUp = TileKind { tsymbol = '<'- , tname = "tainted staircase up"+ , tname = "windy staircase up" , tfreq = [("staircase up", 1)] , tcolor = BrRed , tcolor2 = Red@@ -267,11 +297,12 @@ stairsOutdoorUp = stairsUp { tname = "signpost pointing backward" , tfreq = [("staircase outdoor up", 1)]+ , talter = talterForStairs } stairsGatedUp = stairsUp { tname = "gated staircase up" , tfreq = [("gated staircase up", 1)]- , talter = talterForStairs + 1 -- animals and bosses can't use+ , talter = talterForStairs + 2 -- animals and bosses can't use } stairsDown = TileKind { tsymbol = '>'@@ -279,12 +310,12 @@ , tfreq = [("staircase down", 9), ("ordinary staircase down", 1)] , tcolor = BrWhite , tcolor2 = defFG- , talter = talterForStairs+ , talter = 0 -- very easy stairs, unlike all others , tfeature = [Embed "staircase down", ConsideredByAI] }-stairsTaintedDown = TileKind+stairsTrappedDown = TileKind { tsymbol = '>'- , tname = "tainted staircase down"+ , tname = "crooked staircase down" , tfreq = [("staircase down", 1)] , tcolor = BrRed , tcolor2 = Red@@ -295,11 +326,12 @@ stairsOutdoorDown = stairsDown { tname = "signpost pointing forward" , tfreq = [("staircase outdoor down", 1)]+ , talter = talterForStairs } stairsGatedDown = stairsDown { tname = "gated staircase down" , tfreq = [("gated staircase down", 1)]- , talter = talterForStairs + 1 -- animals and bosses can't use+ , talter = talterForStairs + 2 -- animals and bosses can't use } escapeUp = TileKind { tsymbol = '<'@@ -345,7 +377,7 @@ , tfreq = [("brawlSetLit", 20)] , tcolor = BrBlue , tcolor2 = Blue- , talter = 5+ , talter = 4 -- boss can dig through , tfeature = [Clear, Embed "frost", OpenTo "damp stone floor"] -- Is door, due to @OpenTo@, so is not explorable, but it's OK, because -- it doesn't generate items nor clues. This saves on the need to@@ -353,18 +385,18 @@ } pulpit = TileKind { tsymbol = '%'- , tname = "VR harness"- , tfreq = [("pulpit", 1), ("zooSet", 2)]+ , tname = "VR booth"+ , tfreq = [("pulpit", 1)] , tcolor = BrYellow , tcolor2 = Brown , talter = 5- , tfeature = [Clear, Embed "pulpit", Indistinct]+ , tfeature = [Clear, Embed "pulpit"] -- mixed blessing, so AI ignores, saved for player fun } bush = TileKind { tsymbol = '%' , tname = "bush"- , tfreq = [ ("bush Lit", 1), ("shootoutSetLit", 30), ("escapeSetLit", 30)+ , tfreq = [ ("bush Lit", 1), ("shootoutSetLit", 30), ("escapeSetLit", 40) , ("arenaSetLit", 3), ("bushClumpOver_f_Lit", 1) ] , tcolor = BrGreen , tcolor2 = Green@@ -396,35 +428,34 @@ { tsymbol = ';' , tname = "faint fog" , tfreq = [ ("lit fog", 1), ("emptySet", 5), ("shootoutSetLit", 20)- , ("fogClumpOver_f_Lit", 60) ]+ , ("emptyExitSet", 2)+ , ("noiseSet", 10), ("fogClumpOver_f_Lit", 60) ] -- lit fog is OK for shootout, because LOS is mutual, as opposed -- to dark fog, and so camper has little advantage, especially -- on big maps, where he doesn't know on which side of fog patch to hide , tcolor = BrCyan , tcolor2 = Cyan , talter = 0- , tfeature = [Walkable, NoItem, Indistinct, OftenActor]+ , tfeature = [Walkable, NoItem, OftenActor] } floorFogDark = floorFog { tname = "thick fog"- , tfreq = [("noiseSet", 10), ("escapeSetDark", 60)]+ , tfreq = [("noiseSet", 10), ("escapeSetDark", 50)] , tfeature = Dark : tfeature floorFog } floorSmoke = TileKind { tsymbol = ';' , tname = "billowing smoke"- , tfreq = [ ("lit smoke", 1)- , ("ambushSet", 30), ("zooSet", 30), ("battleSet", 5)- , ("labTrailLit", 1), ("stair terminal", 2)- , ("smokeClumpOver_f_Lit", 1) ]+ , tfreq = [ ("lit smoke", 1), ("labTrailLit", 1), ("stair terminal", 2)+ , ("smokeClumpOver_f_Lit", 1), ("emptyExitSet", 2) ] , tcolor = Brown , tcolor2 = BrBlack , talter = 0- , tfeature = [Walkable, NoItem, Indistinct] -- not dark, embers+ , tfeature = [Walkable, NoItem] -- not dark, embers } floorSmokeDark = floorSmoke { tname = "lingering smoke"- , tfreq = [("ambushSet", 30)]+ , tfreq = [("ambushSet", 60), ("zooSet", 20), ("battleSet", 5)] , tfeature = Dark : tfeature floorSmoke } @@ -448,15 +479,15 @@ , tcolor = BrWhite , tcolor2 = defFG , talter = 0- , tfeature = [Walkable, Clear, Indistinct]+ , tfeature = [Walkable, Clear] } floorArena = floorCorridor { tfreq = [ ("floorArenaLit", 1), ("rubbleSpiceOrNot", 30)- , ("arenaSetLit", 96), ("emptySet", 94), ("zooSet", 1000) ]+ , ("arenaSetLit", 96), ("emptySet", 91), ("zooSet", 600) ] } floorNoise = floorArena { tname = "oily floor"- , tfreq = [("noiseSet", 60), ("damp stone floor", 1)]+ , tfreq = [("noiseSet", 60), ("emptyExitSet", 88), ("damp stone floor", 1)] } floorDirt = floorArena { tname = "dirt"@@ -479,14 +510,15 @@ } floorRed = floorCorridor { tname = "emergency walkway"- , tfreq = [("emergency walkway", 1), ("trailLit", 20)]+ , tfreq = [ ("emergency walkway", 1)+ , ("trailLit", 20), ("alarmingTrailLit", 70) ] , tcolor = BrRed , tcolor2 = Red- , tfeature = Trail : tfeature floorCorridor -- no Indistinct+ , tfeature = [Trail, Walkable, Clear] } floorBlue = floorRed { tname = "transport route"- , tfreq = [("trailLit", 100)]+ , tfreq = [("transport route", 1), ("trailLit", 100)] , tcolor = BrBlue , tcolor2 = Blue }@@ -496,6 +528,12 @@ , tcolor = BrGreen , tcolor2 = Green }+floorBrown = floorRed+ { tname = "overgrown path"+ , tfreq = [("alarmingTrailLit", 30)]+ , tcolor = BrMagenta+ , tcolor2 = Magenta+ } floorArenaShade = floorActor { tname = "shaded ground" , tfreq = [("shaded ground", 1), ("treeShadeOver_s_Lit", 2)]@@ -510,15 +548,15 @@ oriel = TileKind { tsymbol = '%' -- story-wise it's transparent, hence the symbol , tname = "oriel"- , tfreq = [("oriels fence", 4)]+ , tfreq = [("oriels fence", 5)] , tcolor = White , tcolor2 = Black- , talter = maxBound -- impenetrable- , tfeature = [Dark, Indistinct]+ , talter = 5+ , tfeature = [Embed "black starry sky", Dark] }-outerHullWall = hardRock+outerHullWall = basicOuterFence { tname = "outer hull wall"- , tfreq = [("oriels fence", 96), ("noise fence", 1)]+ , tfreq = [("oriels fence", 95), ("noise fence", 1)] } doorlessWall = TileKind { tsymbol = '#'@@ -527,56 +565,97 @@ , tcolor = BrWhite , tcolor2 = defFG , talter = 100- , tfeature = [HideAs "fillerWall", Indistinct]+ , tfeature = [HideAs "fillerWall"] } machineWall = TileKind { tsymbol = '%' , tname = "hardware rack"- , tfreq = [("noiseSet", 35), ("doorlessWallOver_#", 80)]+ , tfreq = [ ("noiseSet", 35), ("emptyExitSet", 7)+ , ("doorlessWallOver_#", 80) ] , tcolor = White , tcolor2 = BrBlack , talter = 100- , tfeature = [Spice, Clear, Indistinct]+ , tfeature = [Spice, Clear] }-wallObscuredDefaced = TileKind+wallObscuredSafety = TileKind { tsymbol = '#'- , tname = "defaced wall"- , tfreq = [("obscured wall", 45), ("escapeSetDark", 1)]+ , tname = "safety procedures wall"+ , tfreq = [("obscured wall", 5)] , tcolor = BrWhite , tcolor2 = defFG , talter = 5- , tfeature = [ Embed "obscene pictograms"+ , tfeature = [ Embed "ruined first aid kit" , HideAs "suspect wall"- , Indistinct+ ] }-wallObscuredFrescoed = TileKind+wallObscured3dBillboard = TileKind { tsymbol = '#'- , tname = "subtle mural"- , tfreq = [("obscured wall", 5), ("brawlSetLit", 1)]+ , tname = "3D billboard"+ , tfreq = [("obscured wall", 45)] , tcolor = BrWhite , tcolor2 = defFG , talter = 5- , tfeature = [ Embed "subtle fresco"+ , tfeature = [ Embed "3D display" , HideAs "suspect wall"- , Indistinct+ ] } rock = pillar { tname = "rock" , tfreq = [("brawlSetLit", 30), ("arenaSetLit", 1), ("arenaSetDark", 1)] }+pillarCache2 = pillarCache+ { tname = "jewelry display"+ , tfreq = [ ("cachable jewelry", 20), ("cache jewelry", 1)+ , ("escapeSetDark", 1) ]+ , tfeature = [ Embed "jewelry case", Embed "treasure cache trap"+ , ChangeTo "cachable jewelry", ConsideredByAI ]+ } stairsLiftUp = stairsUp { tname = "lift up"+ , tfreq = [("staircase lift up", 9), ("ordinary lift up", 1)]+ , talter = talterForStairs+ , tcolor = BrCyan+ , tcolor2 = Cyan+ , tfeature = [Embed "lift up", ConsideredByAI]+ }+stairsLiftTrappedUp = stairsTrappedUp+ { tname = "corroded lift up" , tfreq = [("staircase lift up", 1)]+ , tcolor = BrBlue+ , tcolor2 = Blue+ , tfeature = [ Embed "lift up", Embed "lift trap"+ , ConsideredByAI, ChangeTo "ordinary lift up" ]+ -- AI uses despite the trap; exploration more important } stairsLiftDown = stairsDown { tname = "lift down"+ , tfreq = [("staircase lift down", 9), ("ordinary lift down", 1)]+ , talter = talterForStairs+ , tcolor = BrCyan+ , tcolor2 = Cyan+ , tfeature = [Embed "lift down", ConsideredByAI]+ }+stairsLiftTrappedDown = stairsTrappedDown+ { tname = "corroded lift down" , tfreq = [("staircase lift down", 1)]+ , tcolor = BrBlue+ , tcolor2 = Blue+ , tfeature = [ Embed "lift down", Embed "lift trap"+ , ConsideredByAI, ChangeTo "ordinary lift down" ] } escapeSpaceshipDown = escapeDown { tname = "airlock to the shuttle" , tfreq = [("escape spaceship down", 1)]+ }+floorWindow = floorArena+ { tsymbol = ' ' -- story-wise it's transparent, hence the symbol+ , tname = "floor window"+ , tfreq = [("emptySet", 3)]+ , tcolor = defFG+ , tcolor2 = defFG+ , tfeature = Embed "black starry sky" : tfeature floorCorridor } -- ** Walkable
GameDefinition/InGameHelp.txt view
@@ -1,5 +1,6 @@ This is a snapshot of in-game help, rendered with default config file.-For more general gameplay information see PLAYING.md.+For more general gameplay information see+https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/PLAYING.md Minimal cheat sheet for casual play (1/2).@@ -16,13 +17,13 @@ 1 2 3 j k l b j n In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair).- Press 'KP_5' ('5' on keypad, if present) to wait, bracing for impact,+ Press 'KP_5' ('5' on keypad, or 'i' or '.') to wait, bracing for impact, which reduces any damage taken and prevents displacement by foes. Press 'C-KP_5' (the same key with Control) to wait 0.1 of a turn, without bracing. You displace enemies by running into them with Shift/Control or RMB. Search, open, descend and attack by bumping into walls, doors, stairs and enemies.- The best item to attack with is automatically chosen from among- weapons in your personal equipment and your unwounded organs.+ The best item to attack with is automatically chosen from among weapons+ in your personal equipment and your body parts. Minimal cheat sheet for casual play (2/2).@@ -30,38 +31,44 @@ The following commands, joined with the basic set above, let you accomplish anything in the game, though not necessarily with the fewest keystrokes. You can also play the game exclusively with a mouse, or both mouse and- keyboard. See the ending help screens for mouse commands.- Lastly, you can select a command with arrows or mouse directly from the help- screen and execute it on the spot.+ keyboard. See the ending help screens for mouse commands. Lastly, you can+ select a command with arrows or mouse directly from the help screen+ or the dashboard and execute it on the spot. keys command g or , grab item(s)- c close door- P manage item pack of the leader- KP_* or ! cycle x-hair among enemies- + swerve the aiming line- ESC cancel aiming/open Main Menu- RET or INS accept target/open Help+ ESC cancel aiming/open main menu+ RET or INS accept target/open dashboard SPACE clear messages/display history S-TAB cycle among all party members- = select (or deselect) party member+ KP_* or ! cycle x-hair among enemies+ C-c open or close or alter+ + swerve the aiming line +Here is the complete list of commands from the snapshot of in-game help.+For more general gameplay information see+https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/PLAYING.md+ All terrain exploration and alteration commands. keys command- g or , grab item(s)- d or . drop item(s)+ S-TAB cycle among all party members+ C-c open or close or alter+ TAB cycle among party members on the level+ c close door+ = select (or deselect) party member+ _ deselect (or select) all on the level ; go to x-hair for 25 steps : run to x-hair collectively for 25 steps x explore nearest unknown spot X autoexplore 25 times R rest (wait 25 times) C-R lurk (wait 0.1 turns 100 times)- c close door+ 0, 1 ... 6 pick a particular actor as the new leader -Item Menu commands.+Item menu commands. keys command g or , grab item(s)@@ -78,7 +85,7 @@ Remaining item-related commands. keys command- ^ sort items by kind and stats+ ^ sort items by ownership, kind and stats P manage item pack of the leader G manage items on the ground E manage equipment of the leader@@ -87,45 +94,42 @@ @ describe organs of the leader # show stat summary of the leader ~ display known lore- q quaff potion- r read scroll+ q quaff liquid+ r read chip t throw missile Aiming. keys command+ ESC cancel aiming/open main menu+ RET or INS accept target/open dashboard KP_* or ! cycle x-hair among enemies- KP_/ or / cycle x-hair among items- \ cycle aiming modes + swerve the aiming line+ KP_/ or / cycle x-hair among items - unswerve the aiming line+ \ cycle aiming modes C-? set x-hair to nearest unknown spot C-I set x-hair to nearest item C-{ set x-hair to nearest upstairs- C-} set x-hair to nearest downstairs- < move aiming one level higher- > move aiming one level lower+ C-} set x-hair to nearest dnstairs+ < move aiming one level up+ > move aiming one level down BACKSPACE clear chosen item and target- ESC cancel aiming/open Main Menu- RET or INS accept target/open Help Assorted. keys command SPACE clear messages/display history- ? or F1 display Help- TAB cycle among party members on the level- S-TAB cycle among all party members- = select (or deselect) party member- _ deselect (or select) all on the level+ F12 open dashboard+ ? or F1 display help v voice again the recorded commands V voice recorded commands 100 times C-v voice recorded commands 1000 times C-V voice recorded commands 25 times ' start recording commands- 0, 1 ... 6 pick a particular actor as the new leader+ C-P print screen Mouse overview.@@ -134,13 +138,13 @@ Here is an overview of effects of each button over most of the game map area. The list includes not only left and right buttons, but also the optional middle mouse button (MMB) and even the mouse wheel, which is normally used- over menus, to page-scroll them, rather than over game map.+ over menus, to page-scroll them. For mice without RMB, one can use C-LMB (Control key and left mouse button). keys command LMB set x-hair to enemy/go to pointer for 25 steps RMB or C-LMB fling at enemy/run to pointer collectively for 25 steps- C-RMB open or close door+ C-RMB open or close or alter at pointer MMB snap x-hair to floor under pointer WHEEL-UP swerve the aiming line WHEEL-DN unswerve the aiming line@@ -149,30 +153,30 @@ Mouse in aiming mode. area LMB (left mouse button) RMB (right mouse button)- message line clear messages/display history display known lore+ message line clear messages/display history display help the map area set x-hair to enemy fling at enemy under pointer- level number move aiming one level higher move aiming one level lower+ level number move aiming one level up move aiming one level down level caption accept target cancel aiming- percent seen set x-hair to nearest upstairs set x-hair to nearest downstai$+ percent seen set x-hair to nearest upstairs set x-hair to nearest dnstairs x-hair info cycle x-hair among enemies cycle x-hair among items party roster pick new leader on screen select party member on screen Calm gauge rest (wait 25 times) lurk (wait 0.1 turns 100 times) HP gauge wait a turn, bracing for impact wait 0.1 of a turn- target info manage item pack of the leader clear chosen item and target+ target info fling without aiming clear chosen item and target Mouse in exploration mode. area LMB (left mouse button) RMB (right mouse button)- message line clear messages/display history display known lore+ message line clear messages/display history display help leader on map grab item(s) drop item(s) party on map pick new leader on screen select party member on screen the map area go to pointer for 25 steps run to pointer collectively- level number move aiming one level higher move aiming one level lower- level caption display Help open Main Menu+ level number move aiming one level up move aiming one level down+ level caption open dashboard open main menu percent seen explore nearest unknown spot autoexplore 25 times x-hair info cycle x-hair among enemies cycle x-hair among items party roster pick new leader on screen select party member on screen Calm gauge rest (wait 25 times) lurk (wait 0.1 turns 100 times) HP gauge wait a turn, bracing for impact wait 0.1 of a turn- target info manage item pack of the leader fling without aiming+ target info fling without aiming clear chosen item and target
GameDefinition/Main.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,14 +16,18 @@ import Control.Concurrent.Async import qualified Control.Exception as Ex-import qualified GHC.IO.Handle as GHC.IO.Handle import qualified Options.Applicative as OA import System.Exit++#ifndef USE_JSFILE+import qualified GHC.IO.Handle import System.FilePath import qualified System.IO as SIO import Game.LambdaHack.Common.File (tryCreateDir) import Game.LambdaHack.Common.Misc+#endif+ import Game.LambdaHack.Server (serverOptionsPI) import TieKnot @@ -31,7 +35,9 @@ -- run the game and handle exit. main :: IO () main = do+#ifndef USE_JSFILE -- For the case when the game is started not on a console.+ -- This is broken with JS and also bloats the outcome file. isTerminal <- SIO.hIsTerminalDevice SIO.stdout unless isTerminal $ do dataDir <- appDataDir@@ -40,13 +46,19 @@ fstderr <- SIO.openFile (dataDir </> "stderr.txt") SIO.WriteMode GHC.IO.Handle.hDuplicateTo fstdout SIO.stdout GHC.IO.Handle.hDuplicateTo fstderr SIO.stderr- serverOptions <- OA.execParser serverOptionsPI+#endif+ -- Fail here, not inside server code, so that savefiles are not removed,+ -- because they are not the source of the failure.+ !serverOptions <- OA.execParser serverOptionsPI -- Avoid the bound thread that would slow down the communication. a <- async $ tieKnot serverOptions- ex <- waitCatch a- case ex of+ resOrEx <- waitCatch a+ let unwrapEx e = case Ex.fromException e of+ Just (ExceptionInLinkedThread _ ex) -> unwrapEx ex+ _ -> e+ case resOrEx of Right () -> return ()- Left e -> case Ex.fromException e of+ Left e -> case Ex.fromException $ unwrapEx e of Just ExitSuccess -> exitSuccess -- we are in the main thread, so here it really exits _ -> Ex.throwIO e
GameDefinition/MainMenu.ascii view
@@ -1,24 +1,60 @@-... jiii;.LGEDEi. . . . . ;KEKEGLLGEDt :tfL:,ittjjjjfffff-.. tii;,iGEWDL; . . . . fEDEDGfLDDG . Lf.;itjjjfffLLLLf-.tti;, GDKLt, . . . . . ,itLDEGLLGED. :.fi.;ttjjfffLEWW#DL-.tti;::GELti Allure of the Stars .KtGDEDLfGEDt ...j;:;ttjjffLD#WWW#Kf-.tti;.jGDt . . .. ,LDEDLfGEDt ...t.:itjjfffL WWWWW#K;-jtti,iLDLt <allureofthestars.com> . ;jDEEGLGEDt ,t :itjjffLG WKWWWWE-jtii: GEf; ,iGDEDGGEDt. tt :itjjffLG GWEWWWKE-jtii: GGj; {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{.fGDEDGLDDt tt :itjfffLG KKKWWWEL-jtti. GDj, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ DLDEDGLDD.tj :itjjffLD LWDKWWWD-jtti GDj, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELDEDGL.jj :itjjffLD jKDEWWWEL-jtti GGf, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELDEE.ff::itjjffLG fKEDKWKKD-ftti LGt: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELE.Lf: ijjjffLG tEEDEWKWG-fjjt.,jGf, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,K:Gf,.ijjtffLD..tjEDGDKKWEE-tti;,i;GL. {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .:ftt itiiffLGDGDDDGLDKGKfE-Ltjt;, jLj {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ :Lf;iitjifLLGfDDLijGEKEKDE..-Lffjif.Lft {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .,:LL;,ijjfffLGLGLLLGDKKEELK . .-ffjt iiGfj; {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{...:LL;;ijffffLGDEKKKKKEEKDj.......-.Lffj:j fDi {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{:::fL;,itjfffLGLGDEEDEKDGtK..........-. Lfffifiif {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{,.Lf;.ijjfffLL,,Lfijjt,E,::..........-. fffj:i;t; .tfj,.tjjfffLL;ijfLGGGGGLjt;,::......-.. Lfffjjiii, ... :LL;,,tjjfffLL;;;;iiiiiiii,;;;,:::::..-.. LfffijijjLfi; ,:::,ffj,j;tjffffLG;;;;;;;;;;;;;;;;;,,:::::..-... LLLff,i;jGLLLL LiLt:::tjjffffLG:,,,,,,,,,;;;;,,,,::.......-.Version X.X.X (frontend: xxx, engine: LambdaHack X.X.X) ,,,,,,,,,,,:::::.. .+ + + + + + + + + + + + + + + + + + + ... jiii;.LGEDEi. . . . . ;KEKEGLLGEDt :tfL:,ittjjjjfffff + .. tii;,iGEWDL; . . . . fEDEDGfLDDG . Lf.;itjjjfffLLLLf + .tti;, GDKLt, . . . . . ,itLDEGLLGED. :.fi.;ttjjfffLEWW#DL + .tti;::GELti Allure of the Stars .KtGDEDLfGEDt ...j;:;ttjjffLD#WWW#Kf + .tti;.jGDt . . .. ,LDEDLfGEDt ...t.:itjjfffL WWWWW#K; + jtti,iLDLt <allureofthestars.com> . ;jDEEGLGEDt ,t :itjjffLG WKWWWWE + jtii: GEf; ,iGDEDGGEDt. tt :itjjffLG GWEWWWKE + jtii: GGj; {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{.fGDEDGLDDt tt :itjfffLG KKKWWWEL + jtti. GDj, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ DLDEDGLDD.tj :itjjffLD LWDKWWWD + jtti GDj, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELDEDGL.jj :itjjffLD jKDEWWWEL + jtti GGf, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELDEE.ff::itjjffLG fKEDKWKKD + ftti LGt: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ELE.Lf: ijjjffLG tEEDEWKWG + fjjt.,jGf, {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,K:Gf,.ijjtffLD..tjEDGDKKWEE + tti;,i;GL. {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .:ftt itiiffLGDGDDDGLDKGKfE + Ltjt;, jLj {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ :Lf;iitjifLLGfDDLijGEKEKDE.. + Lffjif.Lft {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .,:LL;,ijjfffLGLGLLLGDKKEELK . . + ffjt iiGfj; {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{...:LL;;ijffffLGDEKKKKKEEKDj....... + .Lffj:j fDi {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{:::fL;,itjfffLGLGDEEDEKDGtK.......... + . Lfffifiif {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{,.Lf;.ijjfffLL,,Lfijjt,E,::.......... + . fffj:i;t; .tfj,.tjjfffLL;ijfLGGGGGLjt;,::...... + .. Lfffjjiii, ... :LL;,,tjjfffLL;;;;iiiiiiii,;;;,:::::.. + .. LfffijijjLfi; ,:::,ffj,j;tjffffLG;;;;;;;;;;;;;;;;;,,:::::.. + ... LLLff,i;jGLLLL LiLt:::tjjffffLG:,,,,,,,,,;;;;,,,,::....... + .Version X.X.X (frontend: xxx, engine: LambdaHack X.X.X) ,,,,,,,,,,,:::::.. . + + + + + + + + + + + + + + + + + +
GameDefinition/PLAYING.md view
@@ -1,16 +1,28 @@ Playing Allure of the Stars =========================== -Your party of trusted crew-members is about to test their fortune-by plundering an abandoned Solar System passenger cruiser.-You are going to set up ambushes for it's feral denizens, hide in shadows,-cover tracks, bump into unspeakable horrors, hidden mechanisms-and astounding technical treasures and make creative use of it all.-The mysterious inhabitants of the Solar System's outer frontier-are bound to welcome intruders with bloody surprises of their own.-As soon as you turn your back in fear, expect to be chased tirelessly-by sight, sound and smell.+The following blurb is a copy of the game intro screen. +Your party of trusted adventurers is about to test its fortune by plundering+a vast derelict passenger cruiser. The spaceship was abandoned and lost+after an accident at the Solar System's outer frontier, but recently+unexpectedly reappeared. Reportedly, deposit safes and jewelry inventories+were never salvaged. Neither were emptied the robot holds, the arboretum+nor the extravagant whole-deck habitat of natural and enhanced wild animals.+Up to this day, countless autonomous life support and damage mitigation+subsystems with redundant power sources busy themselves throughout dozens+of decks. They seem successful, because there are abundant traces of ongoing+metabolism all over the ship. That should make exploration so much easier.++Yours can't be the only shady Neptune Area crew interested in the giant wreck,+so you shouldn't count on reaching it unopposed. The feral outer frontier+denizens are not famed for scruples nor for restraint when using hazardous+nano, cyber and bio technologies, so never assume you are safe. Be ready+to hide in shadows, create distractions, set up ambushes, bump into+unspeakable horrors, puzzling machinery and astounding treasures and make+creative use of all you find, because you are on your own. If ever you turn+your back in fear, expect to be chased tirelessly by sight, sound and smell.+ Once the few basic command keys and on-screen symbols are learned, mastery and enjoyment of the game is the matter of tactical skill and literary imagination. To be honest, a lot of imagination is required@@ -33,11 +45,11 @@ *@12 4d1+5% Calm: 20/60 HP: 33/50 Target: basilisk [**__] -The line starts with the list of party members, with the leader highlighted.-Most commands involve only the leader, including movement with keyboard's-keypad or `LMB` (left mouse button). If more heroes are selected, e.g.,-by clicking on the list with `RMB` (right mouse button), they run together-whenever `:` or `RMB` over map area is pressed.+The line starts with the list of party members, with the current leader+highlighted. Most commands involve only the leader, including movement+with keyboard's keypad or `LMB` (left mouse button). If more heroes+are selected, e.g., by clicking on the list with `RMB` (right mouse button),+they run together whenever `:` or `RMB` over map area is pressed. Next on the status line is the damage of the currently best melee weapon the leader can use, then his current and maximum Calm (morale, composure,@@ -53,11 +65,12 @@ a recently spotted item on the floor or an item in inventory selected for further action or, if none are available, just display the current leader name. Weapon damage and other item stats are displayed using-the dice notation `XdY`, which means `X` rolls of `Y`-sided dice.-A variant denoted `XdlY` is additionally scaled by the level depth-in proportion to the maximal level depth. Section [Monsters](#monsters)-below describes combat resolution in detail, including the percentage-bonus seen in the example.+the dice notation `xdy`, which means `x` rolls of `y`-sided dice.+A variant denoted `xdLy` is additionally scaled by the level depth+in proportion to the maximal level depth (at the first level it's+always one, then it grows up to full rolled value at the last level).+Section [Monsters](#monsters) below describes combat resolution in detail,+including the percentage damage bonus seen in the example. The second, upper status line describes the current level in relation to the party.@@ -70,7 +83,7 @@ marked on the map and manipulated with mouse or movement keys in aiming mode. In this example, the corsshair points at an exact position on the map and at the end of the status line comes the length of the shortest-path from the leader to the spot position and the straight-line distance+path from the leader position to the spot and the straight-line distance between the two points. @@ -90,7 +103,7 @@ bush, transparent obstacle % trap, ice ^ closed door +- open door (horizontal and vertical) '+ open door ' smoke or fog ; ground, corridor . stairs or exit up <@@ -113,7 +126,7 @@ This section is a copy of the first two screens of in-game help and a screen introducing mouse commands. The help pages are automatically generated based on a game's keybinding content and-on overrides in the player's config file. The remaiing in-game help screens,+on overrides in the player's config file. The remaining in-game help screens, not shown here, list all game commands grouped by categories, in detail. A text snapshot of the complete in-game help is in [InGameHelp.txt](InGameHelp.txt).@@ -130,44 +143,42 @@ 1 2 3 j k l b j n In aiming mode, the same keys (and mouse) move the x-hair (aiming crosshair).-Press 'KP_5' ('5' on keypad, if present) to wait, bracing for impact,+Press 'KP_5' ('5' on keypad, or 'i' or '.') to wait, bracing for impact, which reduces any damage taken and prevents displacement by foes. Press 'C-KP_5' (the same key with Control) to wait 0.1 of a turn, without bracing. You displace enemies by running into them with Shift/Control or RMB. Search, open, descend and attack by bumping into walls, doors, stairs and enemies.-The best item to attack with is automatically chosen from among-weapons in your personal equipment and your unwounded organs.+The best item to attack with is automatically chosen from among weapons+in your personal equipment and your body parts. The following commands, joined with the basic set above, let you accomplish anything in the game, though not necessarily with the fewest keystrokes. You can also play the game exclusively with a mouse, or both mouse and-keyboard. See the ending help screens for mouse commands.-Lastly, you can select a command with arrows or mouse directly from the help-screen and execute it on the spot.+keyboard. See the ending help screens for mouse commands. Lastly, you can+select a command with arrows or mouse directly from the help screen+or the dashboard and execute it on the spot. keys command g or , grab item(s)- c close door- P manage item pack of the leader- KP_* or ! cycle x-hair among enemies- + swerve the aiming line- ESC cancel aiming/open Main Menu- RET or INS accept target/open Help+ ESC cancel aiming/open main menu+ RET or INS accept target/open dashboard SPACE clear messages/display history S-TAB cycle among all party members- = select (or deselect) party member+ KP_* or ! cycle x-hair among enemies+ C-c open or close or alter+ + swerve the aiming line Screen area and UI mode (aiming/exploration) determine mouse click effects. Here is an overview of effects of each button over most of the game map area. The list includes not only left and right buttons, but also the optional middle mouse button (MMB) and even the mouse wheel, which is normally used-over menus, to page-scroll them, rather than over game map.+over menus, to page-scroll them. For mice without RMB, one can use C-LMB (Control key and left mouse button). keys command LMB set x-hair to enemy/go to pointer for 25 steps RMB or C-LMB fling at enemy/run to pointer collectively for 25 steps- C-RMB open or close door+ C-RMB open or close or alter at pointer MMB snap x-hair to floor under pointer WHEEL-UP swerve the aiming line WHEEL-DN unswerve the aiming line@@ -196,7 +207,7 @@ Commands for saving and exiting the current game, starting a new game, configuring convenience settings for the current game and challenges-for the next game are listed in the Main Menu, brought up by the `ESC` key.+for the next game are listed in the main menu, brought up by the `ESC` key. Game difficulty, from the challenges menu, determines hitpoints at birth for any actor of any UI-using faction. The "lone wolf" challenge mode reduces player's starting actors to exactly@@ -210,13 +221,13 @@ squad combat, stealth, opportunity fire, asymmetric battles and more. Starting from the second scenario, the player controls a whole team of characters and will develop his repertoire of squad formations,-varying, depending on environment, the bound length, the preferred-rendezvous locations and the use of light sources. The last scenario-takes place in a multi-floor setting, giving player the choice+preferred rendezvous locations and the use of light sources. The last+scenario takes place in a multi-floor setting, giving player the choice of exploration of a single level at a time or portions of many levels along a single staircase and also of guarding staircases against enemies from other levels or, inversely, avoiding the staircases. + Monsters -------- @@ -226,7 +237,7 @@ and take care to move one at a time, monsters don't care about each other and all move at once, sometimes brutally colliding by accident. -When the hero bumps into a monster or a monster attacks the hero,+When a hero bumps into a monster or a monster attacks the hero, melee combat occurs. Heroes and monsters running into one another (with the `Shift` or `Control` key) do not inflict damage, but change places. This gives the opponent a free blow, but can improve the tactical situation@@ -261,12 +272,12 @@ In-game detailed item descriptions contain melee and ranged damage estimates. They do not take into account damage from effects and, if bonuses are not-known, they are guessed based on average bonuses for that kind of item.+known, guesses are based on averages for the item kind in question. The displayed figures are rounded, but the game internally keeps track of minute fractions of HP. The stress of combat drains Calm, gradually limiting the use of items and,-if Calm reaches zero and the actor is sufficiently impressed by his foes,+if Calm reaches zero and the actor is impressed by his foes, making him defect and surrender to their domination. Whenever the monster's or hero's hit points reach zero, the combatant is incapacitated and promptly dies.@@ -276,17 +287,19 @@ On Winning and Dying -------------------- -You win a scenario if you escape the location alive or, in scenarios with-no exit locations, if you eliminate all opposition. In the former case,-your score is based predominantly on the gold and precious gems you've-plundered. In the latter case, your score is most influenced by the number+You win a scenario if you escape the location alive (which may prove+difficult, because your foes gradually build up the ambush squads+blocking your escape routes) or, in scenarios with no exit locations,+if you eliminate all opposition. In the former case, your score+is based predominantly on the gold and precious gems you've plundered.+In the latter case, your score is most influenced by the number of turns you spent overcoming your foes (the quicker the victory, the better; the slower the demise, the better). Bonus points, affected by the number of heroes lost, are awarded only if you win. The score is heavily modified by the chosen game difficulty, but not by any other challenges. When all your heroes fall, you are going to invariably see a new foolhardy-party of adventurers clamoring to be led into danger. They start+party of adventurers clamoring to be led into the unknown. They start their conquest from a new entrance, with no experience and no equipment, and new, undaunted enemies bar their way. Lead the new hopeful explorers to fame, wealth and glory!
GameDefinition/TieKnot.hs view
@@ -1,5 +1,5 @@ -- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+-- Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) -- 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,10 +16,14 @@ import qualified System.Random as R -import Game.LambdaHack.Common.ContentDef-import qualified Game.LambdaHack.Common.Kind as Kind+import Game.LambdaHack.Common.Kind import qualified Game.LambdaHack.Common.Tile as Tile+import qualified Game.LambdaHack.Content.CaveKind as CK import qualified Game.LambdaHack.Content.ItemKind as IK+import qualified Game.LambdaHack.Content.ModeKind as MK+import qualified Game.LambdaHack.Content.PlaceKind as PK+import qualified Game.LambdaHack.Content.RuleKind as RK+import qualified Game.LambdaHack.Content.TileKind as TK import Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer) import Game.LambdaHack.Server @@ -47,24 +51,29 @@ -- equal to what was generated last time, ensures the same item boost. initialGen <- maybe R.getStdGen return sdungeonRng let soptionsNxt = options {sdungeonRng = Just initialGen}- cotile = Kind.createOps Content.TileKind.cdefs boostedItems = IK.boostItemKindList initialGen Content.ItemKind.items- coitem = Kind.createOps $+ coitem = IK.makeData $ if sboostRandomItem- then Content.ItemKind.cdefs- {content = contentFromList- $ boostedItems ++ Content.ItemKind.otherItemContent}- else Content.ItemKind.cdefs+ then boostedItems ++ Content.ItemKind.otherItemContent+ else Content.ItemKind.content+ coItemSpeedup = IK.speedupItem coitem+ cotile = TK.makeData coitem Content.TileKind.content+ coTileSpeedup = Tile.speedupTile sallClear cotile+ coplace = PK.makeData cotile Content.PlaceKind.content+ cocave = CK.makeData coitem coplace cotile Content.CaveKind.content -- Common content operations, created from content definitions. -- Evaluated fully to discover errors ASAP and to free memory.- !cops = Kind.COps- { cocave = Kind.createOps Content.CaveKind.cdefs+ -- Fail here, not inside server code, so that savefiles are not removed,+ -- because they are not the source of the failure.+ !cops = COps+ { cocave , coitem- , comode = Kind.createOps Content.ModeKind.cdefs- , coplace = Kind.createOps Content.PlaceKind.cdefs- , corule = Kind.createOps Content.RuleKind.cdefs+ , comode = MK.makeData cocave coitem Content.ModeKind.content+ , coplace+ , corule = RK.makeData Content.RuleKind.content , cotile- , coTileSpeedup = Tile.speedup sallClear cotile+ , coItemSpeedup+ , coTileSpeedup } -- Client content operations containing default keypresses -- and command descriptions.
GameDefinition/config.ui.default view
@@ -1,5 +1,5 @@ ; Copyright (c) 2008--2011 Andres Loeh-; Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+; Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) ; 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.@@ -20,7 +20,7 @@ [extra_commands] ; Angband compatibility (accept target)-Cmd_2 = ("KP_Insert", ([CmdAim], "", ByAimMode {exploration = Help, aiming = Accept}))+Cmd_2 = ("KP_Insert", ([CmdAim], "", ByAimMode {exploration = ExecuteIfClear Dashboard, aiming = Accept})) [hero_names] HeroName_0 = ("Haskell Alvin", "he")@@ -37,14 +37,17 @@ ; Monospace fonts that have fixed size regardless of boldness (on some OSes at least) gtkFontFamily = "DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace" ;sdlFontFile = "Fix15Mono-Bold.woff"-sdlFontFile = "16x16x.fon"+fontSize = 16 sdlTtfSizeAdd = -2+sdlFontFile = "16x16x.fon" sdlFonSizeAdd = 1-fontSize = 16+;sdlFontFile = "8x8x.fon"+;sdlFonSizeAdd = 2 colorIsBold = True ; New historyMax takes effect after removal of savefiles. historyMax = 5000 maxFps = 30 noAnim = False runStopMsgs = False+hpWarningPercent = 20 overrideCmdline = ""
Makefile view
@@ -1,13 +1,19 @@ # Copyright (c) 2008--2011 Andres Loeh-# Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+# Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) # 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. # play:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --dumpInitRngs+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix play --dumpInitRngs +shot:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix play --dumpInitRngs --printEachScreen++expose-lore:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --dumpInitRngs --savePrefix know --newGame 2 --gameMode crawl --knowItems --benchmark --noAnim --maxFps 1000+ configure-debug: cabal configure --enable-profiling --profiling-detail=all-functions -fwith_expensive_assertions --disable-optimization @@ -21,45 +27,58 @@ google-chrome --no-sandbox --js-flags="--logfile=%t.log --prof" ../allureofthestars.github.io/play/index.html minific:- ccjs dist/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --jscomp_off="*" --externs=node > ../allureofthestars.github.io/play/allure.all.js+ ccjs dist/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --jscomp_off="*" --externs=node --externs=dist/build/Allure/Allure.jsexe/all.js.externs > ../allureofthestars.github.io/play/allure.all.js +# Low delay to display animations swiftly and not bore the public too much.+# Delay can't be lower than 2, because browsers sometimes treat delay 1+# specially and add their extra delay.+create-gif :+ find ~/.Allure/screenshots/ -name 'prtscn*.bmp' -print0 | xargs -0 -r mogrify -format gif+ gifsicle -O3 --careful -d2 -l ~/.Allure/screenshots/prtscn*.gif -o ~/.Allure/screenshots/screenshot.gif+ frontendRaid:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode raid+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode raid frontendBrawl:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode brawl+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode brawl frontendShootout:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode shootout+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode shootout frontendEscape:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 3 --dumpInitRngs --automateAll --gameMode escape+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 3 --dumpInitRngs --automateAll --gameMode escape frontendZoo:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode zoo+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode zoo frontendAmbush:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode ambush+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode ambush frontendCrawl:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 1 --dumpInitRngs --automateAll --gameMode crawl+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 1 --dumpInitRngs --automateAll --gameMode crawl +frontendCrawlEmpty:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 1 --dumpInitRngs --automateAll --gameMode "crawl empty"+ frontendSafari:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode safari+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode safari frontendSafariSurvival:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "safari survival"+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "safari survival" frontendBattle:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode battle+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode battle frontendBattleSurvival:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "battle survival"+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode "battle survival" frontendDefense:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix test --newGame 9 --dumpInitRngs --automateAll --gameMode defense+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 9 --dumpInitRngs --automateAll --gameMode defense +frontendDefenseEmpty:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --savePrefix test --newGame 9 --dumpInitRngs --automateAll --gameMode "defense empty" + benchMemoryAnim: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --newGame 1 --maxFps 100000 --benchmark --stopAfterFrames 33000 --automateAll --keepAutomated --gameMode crawl --setDungeonRng 120 --setMainRng 47 --frontendNull --noAnim +RTS -s -A1M -RTS @@ -105,7 +124,7 @@ test-short: test-short-new test-short-load -test-medium: testRaid-medium testBrawl-medium testShootout-medium testEscape-medium testZoo-medium testAmbush-medium testCrawl-medium testSafari-medium testSafariSurvival-medium testBattle-medium testBattleSurvival-medium+test-medium: testRaid-medium testBrawl-medium testShootout-medium testEscape-medium testZoo-medium testAmbush-medium testCrawl-medium testCrawlEmpty-medium testCrawl-medium-know testSafari-medium testSafariSurvival-medium testBattle-medium testBattleSurvival-medium testDefenseEmpty-medium testRaid-medium: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode raid 2> /tmp/teletypetest.log@@ -120,29 +139,38 @@ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 3 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode escape 2> /tmp/teletypetest.log testZoo-medium:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 2 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 100 --dumpInitRngs --automateAll --keepAutomated --gameMode zoo 2> /tmp/teletypetest.log+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 2 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode zoo 2> /tmp/teletypetest.log testAmbush-medium: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush 2> /tmp/teletypetest.log testCrawl-medium:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 1 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 200 --dumpInitRngs --automateAll --keepAutomated --gameMode crawl 2> /tmp/teletypetest.log+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --newGame 1 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 200 --dumpInitRngs --automateAll --keepAutomated --gameMode crawl 2> /tmp/teletypetest.log +testCrawlEmpty-medium:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --newGame 1 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode "crawl empty" 2> /tmp/teletypetest.log++testCrawl-medium-know:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix know --newGame 3 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 100 --dumpInitRngs --automateAll --keepAutomated --gameMode crawl --knowItems 2> /tmp/teletypetest.log+ testSafari-medium: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 2 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 100 --dumpInitRngs --automateAll --keepAutomated --gameMode safari 2> /tmp/teletypetest.log testSafariSurvival-medium:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 8 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 60 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" 2> /tmp/teletypetest.log+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 8 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" 2> /tmp/teletypetest.log testBattle-medium: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 3 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode battle 2> /tmp/teletypetest.log testBattleSurvival-medium:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 7 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 60 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" 2> /tmp/teletypetest.log+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 7 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" 2> /tmp/teletypetest.log testDefense-medium:- dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 9 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 300 --dumpInitRngs --automateAll --keepAutomated --gameMode defense 2> /tmp/teletypetest.log+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 9 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 200 --dumpInitRngs --automateAll --keepAutomated --gameMode defense 2> /tmp/teletypetest.log +testDefenseEmpty-medium:+ dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 9 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode "defense empty" 2> /tmp/teletypetest.log+ test-short-new: dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log dist/build/Allure/Allure --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix brawl --dumpInitRngs --automateAll --keepAutomated --gameMode brawl --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log@@ -181,7 +209,15 @@ build-binary-common: cabal install --disable-library-profiling --disable-profiling --disable-documentation -f-release --only-dependencies cabal configure --disable-library-profiling --disable-profiling -f-release --prefix=/ --datadir=. --datasubdir=.- cabal build exe:Allure+ which ld+ which ld.gold+ which ld.bfd+ which gcc+ ld --version+ ld.gold --version+ ld.bfd --version+ gcc --version+ cabal build -v2 exe:Allure mkdir -p AllureOfTheStars/GameDefinition/fonts cabal copy --destdir=AllureOfTheStarsInstall cp GameDefinition/config.ui.default AllureOfTheStars/GameDefinition
README.md view
@@ -5,46 +5,46 @@ [](https://hackage.haskell.org/package/Allure) [](https://gitter.im/AllureOfTheStars/Allure?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Allure of the Stars[6] is a near-future Sci-Fi roguelike[2]-and tactical squad game.-Try out the browser version of the LambdaHack sample game at-[http://allureofthestars.com/play](http://allureofthestars.com/play)!+Allure of the Stars is a near-future Sci-Fi roguelike[2]+and tactical squad game. Binaries and the game manual+are available at the homepage[6], where you can also+try the game out in the browser: http://allureofthestars.com/play (It runs fastest on Chrome. Keyboard commands and savefiles are supported only on recent enough versions of browsers. Mouse should work everywhere.) -+ +Not a single picture in this game. You have to imagine everything+yourself, like with a book (a grown-up book, without pictures).+Once you learn to imagine things, though, you can keep exploring+and mastering the world and making up stories for a long time.++The game is written in Haskell[1] using the LambdaHack[10]+roguelike game engine. Please see the changelog file for recent improvements and the issue tracker for short-term plans. Long term goals are high replayability and auto-balancing through procedural content generation and persistent content modification based on player behaviour. Contributions are welcome. -The game is written in Haskell[1] using the LambdaHack [10]-roguelike game engine. Long-term goals of the project are high-replayability and auto-balancing through procedural content generation-and persistent content modification based on player behaviour. - Game installation from binary archives -------------------------------------- The game runs rather slowly in the browser (fastest on Chrome) and you are limited to only one font, though it's scalable.-Keyboard input and saving game progress requires recent enough-version of a browser (but mouse input is enough to play the game). Also, savefiles are prone to corruption on the browser, e.g., when it's closed while the game is still saving progress (which takes a long time). Hence, after trying out the game, you may prefer to use a native binary for your architecture, if it exists. -Pre-compiled game binaries for some platforms are available through+Pre-compiled game binaries are available through the release page[11] (and continuously from AppVeyor[18]). Note that Windows binaries no longer work on Windows XP, since Cygwin-and MSYS2 dropped support for XP). To use a pre-compiled binary archive,-unpack it and run the executable in the unpacked directory.-Or use program shortcuts from the installer, if available.+and MSYS2 dropped support for XP. To use a pre-compiled binary archive,+unpack it and run the executable in the unpacked directory+or use program shortcuts from the installer, if available. On Linux, make sure you have the SDL2 libraries installed on your system (e.g., libsdl2-2.0-0, libsdl2-ttf-2.0-0 on Ubuntu; also libdw1).@@ -56,8 +56,8 @@ --------------------------------- The game UI can be configured via a config file.-A file with the default settings, the same that is built into the binary,-is in [GameDefinition/config.ui.default](https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/config.ui.default).+The default settings, the same that are built into the binary,+are in [GameDefinition/config.ui.default](https://github.com/AllureOfTheStars/Allure/blob/master/GameDefinition/config.ui.default). When the game is run for the first time, the file is copied to the default user data folder, which is `~/.Allure/` on Linux, `C:\Users\<username>\AppData\Roaming\Allure\`@@ -67,14 +67,11 @@ Screen font can be changed by editing the config file in the user data folder. For a small game window, the highly optimized-bitmap fonts 16x16x.fon, 8x8x.fon and 8x8xb.fon are the best,+16x16x.fon and 8x8x.fon bitmap fonts are the best, but for larger window sizes or if you require international characters (e.g. to give custom names to player characters), a modern scalable font supplied with the game is the only option. The game window automatically-scales according to the specified font size. Display on SDL2-and in the browser is superior to all the other frontends,-due to custom square font and less intrusive ways of highlighting-interesting squares.+scales according to the specified font size. If you don't have a numeric keypad, you can use mouse or laptop keys (uk8o79jl) for movement or you can enable the Vi keys (aka roguelike keys)@@ -85,16 +82,7 @@ but the most efficient combination for some players is mouse for go-to, inspecting, and aiming at distant positions and keyboard for everything else. -If you are using a terminal frontend, numeric keypad may not work-correctly depending on versions of the libraries, terminfo and terminal-emulators. Toggling the Num Lock key may help.-The curses frontend is not fully supported due to the limitations-of the curses library. With the vty frontend started in an xterm,-Control-keypad keys for running seem to work OK, but on rxvt they do not.-The commands that require pressing Control and Shift together won't-work either, but fortunately they are not crucial to gameplay. - Compilation from source ----------------------- @@ -105,11 +93,9 @@ The recommended frontend is based on SDL2, so you need the SDL2 libraries for your OS. On Linux, remember to install the -dev versions as well, e.g., libsdl2-dev and libsdl2-ttf-dev on Ubuntu Linux 16.04.-(Compilation to Javascript for the browser is more complicated+(Compilation to JavaScript for the browser is more complicated and requires the ghcjs[15] compiler and optionally the Google Closure-Compiler[16] as well. See the-[Makefile](https://github.com/AllureOfTheStars/Allure/blob/master/Makefile)-for more details.)+Compiler[16] as well.) The latest official version of the game can be downloaded, compiled for SDL2 and installed automatically by Cabal from Hackage[3]@@ -146,7 +132,7 @@ ------------ Stylish Haskell is used for slight auto-formatting at buffer save; see-[.stylish-haskell.yaml](https://github.com/LambdaHack/LambdaHack/blob/master/.stylish-haskell.yaml).+[.stylish-haskell.yaml](https://github.com/AllureOfTheStars/Allure/blob/master/.stylish-haskell.yaml). As defined in the file, indentation is 2 spaces wide and screen is 80-columns wide. Spaces are used, not tabs. Spurious whitespace avoided. Spaces around arithmetic operators encouraged.@@ -155,11 +141,11 @@ Haddocks are provided for all module headers and for all functions and types from major modules, in particular the modules that are interfaces-for a whole directory of modules. Apart of that only very important+for a whole directory of modules. Apart of that, only very important functions and types are distinguished by having a haddock. If minor ones have comments, they should not be haddocks and they are permitted to describe implementation details and be out of date.-Prefer assertions in place of comments, unless too verbose.+Prefer assertions to comments, unless too verbose. Further information@@ -177,7 +163,7 @@ --------- Copyright (c) 2008--2011 Andres Loeh-Copyright (c) 2010--2017 Mikolaj Konarski and others (see git history)+Copyright (c) 2010--2018 Mikolaj Konarski and others (see git history) 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