Allure 0.10.3.0 → 0.11.0.0
raw patch · 27 files changed
+1563/−1158 lines, 27 filesdep ~LambdaHackPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: LambdaHack
API changes (from Hackage documentation)
- Content.CaveKind: pattern CAVE_ESCAPE :: GroupName CaveKind
- Content.CaveKind: pattern CAVE_EXIT :: GroupName CaveKind
- Content.ModeKind: pattern ESCAPE :: GroupName ModeKind
- Content.ModeKindPlayer: hiDweller :: HiCondPoly
- Content.ModeKindPlayer: hiHeroLong :: HiCondPoly
- Content.ModeKindPlayer: hiHeroMedium :: HiCondPoly
- Content.ModeKindPlayer: hiHeroShort :: HiCondPoly
- Content.ModeKindPlayer: playerAnimal :: Player
- Content.ModeKindPlayer: playerAnimalExquisite :: Player
- Content.ModeKindPlayer: playerAnimalMagnificent :: Player
- Content.ModeKindPlayer: playerAntiHero :: Player
- Content.ModeKindPlayer: playerAntiMonster :: Player
- Content.ModeKindPlayer: playerCivilian :: Player
- Content.ModeKindPlayer: playerHero :: Player
- Content.ModeKindPlayer: playerHorror :: Player
- Content.ModeKindPlayer: playerHunamConvict :: Player
- Content.ModeKindPlayer: playerMonster :: Player
- Content.ModeKindPlayer: playerMonsterTourist :: Player
- Content.ModeKindPlayer: playerRobot :: Player
- Content.PlaceKind: pattern ESCAPE :: GroupName PlaceKind
- Content.PlaceKind: pattern ESCAPE_FROM_SPACESHIP_DOWN :: GroupName PlaceKind
- Content.PlaceKind: pattern EXIT :: GroupName PlaceKind
- Content.TileKind: pattern ESCAPE_DOWN :: GroupName TileKind
- Content.TileKind: pattern ESCAPE_OUTDOOR_DOWN :: GroupName TileKind
- Content.TileKind: pattern ESCAPE_SET_DARK :: GroupName TileKind
- Content.TileKind: pattern ESCAPE_SET_LIT :: GroupName TileKind
- Content.TileKind: pattern ESCAPE_SPACESHIP_DOWN :: GroupName TileKind
- Content.TileKind: pattern ESCAPE_UP :: GroupName TileKind
- Content.TileKind: pattern EXIT_SET_LIT :: GroupName TileKind
+ Content.CaveKind: pattern CAVE_EGRESS :: GroupName CaveKind
+ Content.CaveKind: pattern CAVE_FLIGHT :: GroupName CaveKind
+ Content.CaveKind: pattern CAVE_GAUNTLET :: GroupName CaveKind
+ Content.CaveKind: pattern CAVE_VIRUS :: GroupName CaveKind
+ Content.FactionKind: content :: [FactionKind]
+ Content.FactionKind: groupNames :: [GroupName FactionKind]
+ Content.FactionKind: groupNamesSingleton :: [GroupName FactionKind]
+ Content.FactionKind: hiHeroExterminator :: HiCondPoly
+ Content.FactionKind: pattern ANIMAL_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_CAPTIVE_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_EXQUISITE :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_MAGNIFICENT :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_MAGNIFICENT_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_OR_ROBOT_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern ANIMAL_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern CIVILIAN_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern COMPETITOR_NO_ESCAPE :: GroupName FactionKind
+ Content.FactionKind: pattern COMPETITOR_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern COMPETITOR_SHORT :: GroupName FactionKind
+ Content.FactionKind: pattern CONVICT_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_AUTOMATED :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_AUTOMATED_TRAPPED :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_EXTERMINATOR :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_MEDIUM :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_NO_ESCAPE :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_PACIFIST :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_SHORT :: GroupName FactionKind
+ Content.FactionKind: pattern EXPLORER_TRAPPED :: GroupName FactionKind
+ Content.FactionKind: pattern HORROR_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern HORROR_PACIFIST :: GroupName FactionKind
+ Content.FactionKind: pattern HORROR_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_ANTI :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_ANTI_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_ANTI_PACIFIST :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_CAPTIVE_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_TOURIST :: GroupName FactionKind
+ Content.FactionKind: pattern MONSTER_TOURIST_PASSIVE :: GroupName FactionKind
+ Content.FactionKind: pattern OFF_WORLD_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern ROBOT_CAPTIVE :: GroupName FactionKind
+ Content.FactionKind: pattern ROBOT_GAUNTLET :: GroupName FactionKind
+ Content.FactionKind: pattern ROBOT_NARRATING :: GroupName FactionKind
+ Content.FactionKind: pattern ROBOT_REPRESENTATIVE :: GroupName FactionKind
+ Content.FactionKind: pattern ROBOT_VIRUS :: GroupName FactionKind
+ Content.ItemKindActor: pattern EXTERMINATOR_HERO :: GroupName ItemKind
+ Content.ItemKindActor: pattern GAUNTLET_ROBOT :: GroupName ItemKind
+ Content.ItemKindActor: pattern INSECT :: GroupName ItemKind
+ Content.ItemKindActor: pattern MECHANICAL_CONTRAPTION :: GroupName ItemKind
+ Content.ItemKindActor: pattern RAIDER_HERO :: GroupName ItemKind
+ Content.ModeKind: pattern FLIGHT :: GroupName ModeKind
+ Content.ModeKind: pattern FUN :: GroupName ModeKind
+ Content.ModeKind: pattern GAUNTLET :: GroupName ModeKind
+ Content.PlaceKind: pattern ALARM_ESCAPE_UP :: GroupName PlaceKind
+ Content.PlaceKind: pattern EGRESS :: GroupName PlaceKind
+ Content.PlaceKind: pattern FLIGHT :: GroupName PlaceKind
+ Content.PlaceKind: pattern GAUNTLET :: GroupName PlaceKind
+ Content.PlaceKind: pattern SPACESHIP_ESCAPE_DOWN :: GroupName PlaceKind
+ Content.PlaceKind: pattern VIRUS :: GroupName PlaceKind
+ Content.TileKind: pattern EGRESS_SET_LIT :: GroupName TileKind
+ Content.TileKind: pattern FLIGHT_SET_DARK :: GroupName TileKind
+ Content.TileKind: pattern FLIGHT_SET_LIT :: GroupName TileKind
+ Content.TileKind: pattern TILE_ALARM_ESCAPE_UP :: GroupName TileKind
+ Content.TileKind: pattern TILE_INDOOR_ESCAPE_DOWN :: GroupName TileKind
+ Content.TileKind: pattern TILE_INDOOR_ESCAPE_UP :: GroupName TileKind
+ Content.TileKind: pattern TILE_OUTDOOR_ESCAPE_DOWN :: GroupName TileKind
+ Content.TileKind: pattern TILE_SPACESHIP_ESCAPE_DOWN :: GroupName TileKind
+ Content.TileKind: pattern VIRUS_SET_DARK :: GroupName TileKind
+ Content.TileKind: pattern VIRUS_SET_LIT :: GroupName TileKind
- Implementation.MonadClientImplementation: executorCli :: CCUI -> UIOptions -> ClientOptions -> COps -> Bool -> FactionId -> ChanServer -> IO ()
+ Implementation.MonadClientImplementation: executorCli :: CCUI -> UIOptions -> ClientOptions -> Bool -> COps -> FactionId -> ChanServer -> IO ()
Files
- Allure.cabal +14/−6
- CHANGELOG.md +49/−1
- CREDITS +8/−0
- GameDefinition/Content/CaveKind.hs +170/−96
- GameDefinition/Content/FactionKind.hs +471/−0
- GameDefinition/Content/ItemKind.hs +41/−47
- GameDefinition/Content/ItemKindActor.hs +106/−75
- GameDefinition/Content/ItemKindBlast.hs +4/−3
- GameDefinition/Content/ItemKindEmbed.hs +10/−8
- GameDefinition/Content/ItemKindOrgan.hs +28/−14
- GameDefinition/Content/ItemKindTemporary.hs +4/−2
- GameDefinition/Content/ModeKind.hs +322/−390
- GameDefinition/Content/ModeKindPlayer.hs +0/−211
- GameDefinition/Content/PlaceKind.hs +144/−163
- GameDefinition/Content/RuleKind.hs +3/−3
- GameDefinition/Content/TileKind.hs +89/−71
- GameDefinition/InGameHelp.txt +1/−1
- GameDefinition/Main.hs +7/−5
- GameDefinition/PLAYING.md +10/−5
- GameDefinition/config.ui.default +1/−1
- GameDefinition/game-src/Client/UI/Content/Input.hs +21/−19
- GameDefinition/game-src/Implementation/MonadClientImplementation.hs +6/−6
- GameDefinition/game-src/Implementation/MonadServerImplementation.hs +12/−7
- GameDefinition/game-src/TieKnot.hs +17/−10
- Makefile +20/−9
- README.md +2/−2
- test/Spec.hs +3/−3
Allure.cabal view
@@ -6,7 +6,7 @@ -- PVP summary:+-+------- breaking API changes -- | | +----- minor or non-breaking API additions -- | | | +--- code changes with no API change-version: 0.10.3.0+version: 0.11.0.0 synopsis: Near-future Sci-Fi roguelike and tactical squad combat game description: Allure of the Stars is a near-future Sci-Fi roguelike and tactical squad combat game. Binaries and the game manual@@ -28,7 +28,7 @@ . This is a workaround .cabal file, flattened to eliminate internal libraries until generating haddocks for them- is fixed. The original .cabal file is stored in the github repo.+ is fixed. The original .cabal file is in .cabal.bkp file. homepage: http://allureofthestars.com bug-reports: http://github.com/AllureOfTheStars/Allure/issues license: AGPL-3.0-or-later@@ -74,6 +74,11 @@ default: False manual: True +flag with_costly_optimizations+ description: turn on costly (mostly GHC heap size) optimizations (that give 15-25% speedup)+ default: True+ manual: True+ flag release description: prepare for a release (expose internal functions and types, etc.) default: True@@ -98,9 +103,12 @@ ExistentialQuantification, GADTs, StandaloneDeriving, DataKinds, KindSignatures, DeriveGeneric, DeriveLift ghc-options: -Wall -Wcompat -Worphans -Wincomplete-uni-patterns -Wincomplete-record-updates -Wimplicit-prelude -Wmissing-home-modules -Widentities -Wredundant-constraints -Wmissing-export-lists -Wpartial-fields -Wunused-packages -Winvalid-haddock- ghc-options: -Wall-missed-specialisations- ghc-options: -fno-ignore-asserts -fexpose-all-unfoldings -fspecialise-aggressively -fsimpl-tick-factor=200+-- TODO: remove -Winvalid-haddock when added to -Wall in a GHC I use for haddock+ ghc-options: -fno-ignore-asserts + if flag(with_costly_optimizations)+ ghc-options: -fexpose-all-unfoldings -fspecialise-aggressively -fsimpl-tick-factor=200+ if flag(with_expensive_assertions) cpp-options: -DWITH_EXPENSIVE_ASSERTIONS @@ -134,6 +142,7 @@ import: options hs-source-dirs: GameDefinition, GameDefinition/game-src exposed-modules: Content.CaveKind+ Content.FactionKind Content.ItemKind Content.ItemKindEmbed Content.ItemKindActor@@ -141,7 +150,6 @@ Content.ItemKindBlast Content.ItemKindTemporary Content.ModeKind- Content.ModeKindPlayer Content.PlaceKind Content.RuleKind Content.TileKind@@ -152,7 +160,7 @@ Implementation.MonadServerImplementation other-modules: Paths_Allure autogen-modules: Paths_Allure- build-depends: ,LambdaHack >= 0.10.3.0 && < 0.10.4.0+ build-depends: ,LambdaHack >= 0.11.0.0 && < 0.11.1.0 ,async ,base >= 4.10 && < 99 ,enummapset
CHANGELOG.md view
@@ -1,6 +1,54 @@+## [v0.11.0.0](https://github.com/LambdaHack/LambdaHack/compare/v0.10.3.0...v0.11.0.0)++- Partially work around regression in libsdl2 2.0.16 (https://github.com/LambdaHack/LambdaHack/issues/281); to also avoid deformed boxes around tiles on the game map, please switch to a different SDL2 version+- Deduplicate UI code for exiting game, with extra style points+- Create monadic test harness and use it for UI and other unit tests+- Validate empty content and fix other soundness issues revealed by unit tests+- Add extra hints in --more and similar lines when tutorial is on+- Show full history at SPACE press and let second SPACE close it+- Spawn insects in the swamp+- Remove slot letter display in menus and instead display subtle bullets+- Repurpose item slots to item roles+- Redo display and control of main menu and its submenus+- Make Teletype frontend a bit closer to playable+- Switch right pane item description display from mono to prop font+- Ensure score not zero if victory+- Add a custom SDL cursor, working around a bug in SDL2 bindings+- Gut out most content symbols; weren't used even in lore menus after all+- Add a flag to disable the costly optimizations (that give 15-25% speedup)+- Add faction kind content and redo game mode content to use it+- Display seen faction lore+- Simplify and fortify faction and client assignment code+- Make a few unique items that were identified meta-game identifiable instead+- Fix persistence of meta-game discoveries in save files+- When assigning a faction, first try the group actor was picked from+- When assigned faction is dead, don't spawn the actor+- Don't use benign weapons on projectiles not to lose the fun+- Make the unique harpoon worth saving for a unique foe+- Spawn enemies closer and fix too random spawning location+- Improve display of item's range+- Warn when SDL game windows is resized not via config file+- Ban or force sleep on levels+- Protect against unset or primitive OS locale+- Add temporary hearing aids+- Disallow generating a door beside an opening in room's wall+- Permit smaller caves and validate cave content more accurately+- Try harder to generate escape from dungeon in a level corner+- Avoid exit/escape confusion in content names and descriptions+- Add Gauntlet game mode and Machinarium spaceship level+- Don't require identification for cooked plants+- Make Bob speak less often and explode more often+- Make Bob's monologue less repetitive+- Make oriels lit, until there is any game-play fun in having to go to them+- Make loot in initial caves more consistent+- Rule out giant octopus on initial levels to teach simple tactics better+- Give player more time to hunt bees before they die+- Fix raid heroes not having genetic flaws contrary to description+- Many fixes, refactorings, tweaks and balancing changes+ ## [v0.10.3.0](https://github.com/AllureOfTheStars/Allure/compare/v0.10.2.0...v0.10.3.0) -- Work around regression https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 by making the scalable square font the default as the map font; the tiny map fonts, for which there is no such workaround, wont work for anybody with freetype 2.11.0+- Work around regression https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 by making the scalable square font the default as the map font; the tiny map fonts, for which there is no such workaround, won't work for anybody with freetype 2.11.0 - Enable display of details in right pane in many menus - Switch mouse wheel to move selection now that it changes right pane display - Make the line where messages wrap configurable in config file
CREDITS view
@@ -11,6 +11,14 @@ +Binary distributions of this package may be linked or bundled with libraries+such as SDL2, SDL_ttf, FreeType and many others. These libraries+are copyright of their respective owners, with all rights reserved.+In particular, portions of this software are copyright © 2021 The FreeType+Project (www.freetype.org). All rights reserved.+++ Fonts 16x16xw.woff, 16x16xw.bdf, 16x16x.fnt, 8x8x.fnt and 8x8xb.fnt are are derived from fonts taken from https://github.com/angband/angband, copyrighted by Leon Marrick,
GameDefinition/Content/CaveKind.hs view
@@ -8,8 +8,8 @@ -- cave kind. module Content.CaveKind ( -- * Group name patterns- pattern CAVE_ROGUE, pattern CAVE_ARENA, pattern CAVE_LABORATORY, pattern CAVE_NOISE, pattern CAVE_SHALLOW_ROGUE, pattern CAVE_OUTERMOST, pattern CAVE_RAID, pattern CAVE_BRAWL, pattern CAVE_BRAWL_ALT, pattern CAVE_SHOOTOUT, pattern CAVE_HUNT, pattern CAVE_ESCAPE, pattern CAVE_ZOO, pattern CAVE_AMBUSH, pattern CAVE_BATTLE, pattern CAVE_SAFARI_1, pattern CAVE_SAFARI_2, pattern CAVE_SAFARI_3- , pattern CAVE_BRIDGE, pattern CAVE_RESIDENTIAL, pattern CAVE_MUSEUM, pattern CAVE_EXIT, pattern CAVE_CASINO, pattern CAVE_POWER+ pattern CAVE_ROGUE, pattern CAVE_ARENA, pattern CAVE_LABORATORY, pattern CAVE_NOISE, pattern CAVE_SHALLOW_ROGUE, pattern CAVE_OUTERMOST, pattern CAVE_RAID, pattern CAVE_BRAWL, pattern CAVE_BRAWL_ALT, pattern CAVE_SHOOTOUT, pattern CAVE_HUNT, pattern CAVE_FLIGHT, pattern CAVE_ZOO, pattern CAVE_AMBUSH, pattern CAVE_BATTLE, pattern CAVE_SAFARI_1, pattern CAVE_SAFARI_2, pattern CAVE_SAFARI_3+ , pattern CAVE_BRIDGE, pattern CAVE_VIRUS, pattern CAVE_RESIDENTIAL, pattern CAVE_MUSEUM, pattern CAVE_EGRESS, pattern CAVE_CASINO, pattern CAVE_POWER, pattern CAVE_GAUNTLET , groupNamesSingleton, groupNames , -- * Content content@@ -19,16 +19,9 @@ import Game.LambdaHack.Core.Prelude -import Data.Ratio+import Data.Ratio+import qualified Data.Text as T -import Content.ItemKind hiding- (content, groupNames, groupNamesSingleton)-import Content.ItemKindActor-import Content.ItemKindEmbed hiding (ESCAPE)-import Content.PlaceKind hiding- (content, groupNames, groupNamesSingleton)-import Content.TileKind hiding- (content, groupNames, groupNamesSingleton) import Game.LambdaHack.Content.CaveKind import qualified Game.LambdaHack.Content.ItemKind as IK import Game.LambdaHack.Content.TileKind@@ -36,6 +29,12 @@ import Game.LambdaHack.Definition.Defs import Game.LambdaHack.Definition.DefsInternal +import Content.ItemKind hiding (content, groupNames, groupNamesSingleton)+import Content.ItemKindActor+import Content.ItemKindEmbed+import Content.PlaceKind hiding (content, groupNames, groupNamesSingleton)+import Content.TileKind hiding (content, groupNames, groupNamesSingleton)+ -- * Group name patterns groupNamesSingleton :: [GroupName CaveKind]@@ -43,12 +42,12 @@ groupNames :: [GroupName CaveKind] groupNames =- [CAVE_ROGUE, CAVE_ARENA, CAVE_LABORATORY, CAVE_NOISE, CAVE_SHALLOW_ROGUE, CAVE_OUTERMOST, CAVE_RAID, CAVE_BRAWL, CAVE_BRAWL_ALT, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_ESCAPE, CAVE_ZOO, CAVE_AMBUSH, CAVE_BATTLE, CAVE_SAFARI_1, CAVE_SAFARI_2, CAVE_SAFARI_3]- ++ [CAVE_BRIDGE, CAVE_RESIDENTIAL, CAVE_MUSEUM, CAVE_EXIT, CAVE_CASINO, CAVE_POWER]+ [CAVE_ROGUE, CAVE_ARENA, CAVE_LABORATORY, CAVE_NOISE, CAVE_SHALLOW_ROGUE, CAVE_OUTERMOST, CAVE_RAID, CAVE_BRAWL, CAVE_BRAWL_ALT, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_FLIGHT, CAVE_ZOO, CAVE_AMBUSH, CAVE_BATTLE, CAVE_SAFARI_1, CAVE_SAFARI_2, CAVE_SAFARI_3]+ ++ [CAVE_BRIDGE, CAVE_VIRUS, CAVE_RESIDENTIAL, CAVE_MUSEUM, CAVE_EGRESS, CAVE_CASINO, CAVE_POWER, CAVE_GAUNTLET] -pattern CAVE_ROGUE, CAVE_ARENA, CAVE_LABORATORY, CAVE_NOISE, CAVE_SHALLOW_ROGUE, CAVE_OUTERMOST, CAVE_RAID, CAVE_BRAWL, CAVE_BRAWL_ALT, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_ESCAPE, CAVE_ZOO, CAVE_AMBUSH, CAVE_BATTLE, CAVE_SAFARI_1, CAVE_SAFARI_2, CAVE_SAFARI_3 :: GroupName CaveKind+pattern CAVE_ROGUE, CAVE_ARENA, CAVE_LABORATORY, CAVE_NOISE, CAVE_SHALLOW_ROGUE, CAVE_OUTERMOST, CAVE_RAID, CAVE_BRAWL, CAVE_BRAWL_ALT, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_FLIGHT, CAVE_ZOO, CAVE_AMBUSH, CAVE_BATTLE, CAVE_SAFARI_1, CAVE_SAFARI_2, CAVE_SAFARI_3 :: GroupName CaveKind -pattern CAVE_BRIDGE, CAVE_RESIDENTIAL, CAVE_MUSEUM, CAVE_EXIT, CAVE_CASINO, CAVE_POWER :: GroupName CaveKind+pattern CAVE_BRIDGE, CAVE_VIRUS, CAVE_RESIDENTIAL, CAVE_MUSEUM, CAVE_EGRESS, CAVE_CASINO, CAVE_POWER, CAVE_GAUNTLET :: GroupName CaveKind pattern CAVE_ROGUE = GroupName "caveRogue" pattern CAVE_ARENA = GroupName "caveArena"@@ -61,7 +60,7 @@ pattern CAVE_BRAWL_ALT = GroupName "caveBrawlAlt" pattern CAVE_SHOOTOUT = GroupName "caveShootout" pattern CAVE_HUNT = GroupName "caveHunt"-pattern CAVE_ESCAPE = GroupName "caveEscape"+pattern CAVE_FLIGHT = GroupName "caveFlight" pattern CAVE_ZOO = GroupName "caveZoo" pattern CAVE_AMBUSH = GroupName "caveAmbush" pattern CAVE_BATTLE = GroupName "caveBattle"@@ -71,25 +70,26 @@ -- ** Allure-specific pattern CAVE_BRIDGE = GroupName "caveBridge"+pattern CAVE_VIRUS = GroupName "caveVirus" pattern CAVE_RESIDENTIAL = GroupName "caveResidential" pattern CAVE_MUSEUM = GroupName "caveMuseum"-pattern CAVE_EXIT = GroupName "caveExit"+pattern CAVE_EGRESS = GroupName "caveEgress" pattern CAVE_CASINO = GroupName "caveCasino" pattern CAVE_POWER = GroupName "cavePower"+pattern CAVE_GAUNTLET = GroupName "caveGauntlet" -- * Content content :: [CaveKind] content =- [rogue, residential, arena, casino, museum, laboratory, noise, power, empty, exit, outermost, bridge, shallowRogue, raid, brawl, brawlAlt, shootout, hunt, escape, zoo, ambush, battle, safari1, safari2, safari3]+ [rogue, residential, arena, casino, museum, laboratory, noise, power, empty, egress, outermost, bridge, shallowRogue, virus, gauntlet, raid, brawl, brawlAlt, shootout, hunt, flight, zoo, ambush, battle, safari1, safari2, safari3] -rogue, residential, arena, casino, museum, laboratory, noise, power, empty, exit, outermost, bridge, shallowRogue, raid, brawl, brawlAlt, shootout, hunt, escape, zoo, ambush, battle, safari1, safari2, safari3 :: CaveKind+rogue, residential, arena, casino, museum, laboratory, noise, power, empty, egress, outermost, bridge, shallowRogue, virus, gauntlet, raid, brawl, brawlAlt, shootout, hunt, flight, zoo, ambush, battle, safari1, safari2, safari3 :: CaveKind -- * On-ship "caves", that is, decks, most of mediocre height and size rogue = CaveKind- { csymbol = 'R'- , cname = "Maintenance and storage"+ { cname = "Maintenance and storage" , cfreq = [(DEFAULT_RANDOM, 100), (CAVE_ROGUE, 1)] , cXminSize = 80 , cYminSize = 42@@ -105,7 +105,7 @@ , cdoorChance = 3%4 , copenChance = 1%5 , chidden = 7- , cactorCoeff = 50 -- the maze requires time to explore+ , cactorCoeff = 70 -- the maze requires time to explore , cactorFreq = [(MONSTER, 50), (ANIMAL, 20), (ROBOT, 30)] , citemNum = 17 `d` 2 + 25 - 25 `dL` 1 -- deep down quality over quantity; generally not too random,@@ -117,7 +117,7 @@ , (IK.TREASURE, 40) ] , cplaceFreq = [(ROGUE, 1)] , cpassable = False- , labyrinth = False+ , clabyrinth = False , cdefTile = ROGUE_SET , cdarkCorTile = FLOOR_CORRIDOR_DARK , clitCorTile = FLOOR_CORRIDOR_LIT@@ -128,7 +128,7 @@ , cfenceTileS = S_BASIC_OUTER_FENCE , cfenceTileW = HABITAT_CONTAINMENT_WALL , cfenceApart = False- , cminStairDist = 30+ , cminStairDist = 15 -- to help Casino stay small , cmaxStairsNum = 2 + 1 `d` 2 , cescapeFreq = [] , cstairFreq = [ (WALLED_LIFT, 50), (OPEN_LIFT, 50)@@ -136,6 +136,7 @@ , cstairAllowed = [ (WALLED_STAIRCASE, 50), (OPEN_STAIRCASE, 50) , (TINY_STAIRCASE, 1) ] , cskip = []+ , cinitSleep = InitSleepPermitted , cdesc = "Winding tunnels stretch into the dark. A few areas are passable but the remainder is packed with tanks and cells of raw materials and machinery." } residential = rogue -- an alternative with lit corridors but dark rooms@@ -157,8 +158,7 @@ , cdesc = "The area has been powered down, except for emergency corridors. Many suites are depressurized and sealed." } arena = rogue- { csymbol = 'A'- , cname = "Recreational deck"+ { cname = "Recreational deck" , cfreq = [(CAVE_ARENA, 1)] , cXminSize = 80 , cYminSize = 25@@ -173,7 +173,7 @@ , cauxConnects = 1 , cmaxVoid = 1%20 , chidden = 0- , cactorCoeff = 40 -- smallish level, but easy to view and plan+ , cactorCoeff = 50 -- smallish level, but easy to view and plan , cactorFreq = [ (EXPLOSIVE_MONSTER, 50), (ANIMAL, 50), (ROBOT, 5) , (IK.AQUATIC, 10) ] , citemNum = 16 `d` 2@@ -188,7 +188,7 @@ , clitCorTile = TRAIL_LIT -- may be rolled different than the above , cwallTile = OPENABLE_WALL , cminStairDist = 20- , cmaxStairsNum = 1 `d` 2+ , cmaxStairsNum = 1 `d` 3 , cstairFreq = [ (WALLED_LIFT, 20), (CLOSED_LIFT, 80) , (TINY_LIFT, 1) ] , cstairAllowed = [ (WALLED_STAIRCASE, 20), (CLOSED_STAIRCASE, 80)@@ -200,10 +200,11 @@ , cfreq = [(CAVE_CASINO, 1)] , cXminSize = 21 , cYminSize = 21+ , ccellSize = DiceXY 19 (1 `d` 3 + 5) , cdarkOdds = 41 + 1 `d` 10 -- almost all rooms lit (1 in 10 dark) -- Trails provide enough light for fun stealth, though level too small. , cnightOdds = 51 -- always night- , cactorCoeff = 70 -- cramped, don't overcrowd+ , cactorCoeff = 100 -- cramped, don't overcrowd , cactorFreq = [(MONSTER, 50), (ANIMAL, 25), (ROBOT, 50)] , citemNum = 14 `d` 2 -- rare, so make it exciting by keeping many items , citemFreq = [ (IK.COMMON_ITEM, 20)@@ -216,19 +217,21 @@ , cfenceTileW = HABITAT_CONTAINMENT_WALL , cminStairDist = 10 , cmaxStairsNum = 2 -- to make possible 2 stairs in the last cave- , cdesc = "The establishment is no longer filled with hollow-eyed gamblers; more dangerous things now lurk in the dark."+ , cinitSleep = InitSleepBanned+ , cdesc = "The establishment is no longer filled with hollow-eyed gamblers; more dangerous things now lurk in the dark. But the greedy excitement is not gone, even if out of place. Flashing colourful lights and enticing sounds make it a place where one couldn't sleep." } museum = arena { cname = "Museum" , cfreq = [(CAVE_MUSEUM, 1)] , cXminSize = 25 , cYminSize = 25+ , ccellSize = DiceXY 23 (1 `d` 3 + 5) , cdarkOdds = 41 + 1 `d` 10 -- almost all rooms lit (1 in 10 dark) -- Trails provide enough light for fun stealth, though level too small. , cnightOdds = 51 -- always night- , cactorCoeff = 70 -- cramped, don't overcrowd+ , cactorCoeff = 100 -- cramped, don't overcrowd , cactorFreq = [(MONSTER, 100), (ANIMAL, 25), (ROBOT, 25)]- , citemNum = 16 `d` 2 -- rare, so make it exciting+ , citemNum = 12 `d` 2 -- rare, so make it exciting despite sleeping foes , citemFreq = [ (IK.COMMON_ITEM, 20) , (IK.CRAWL_ITEM, 20) , (IK.TREASURE, 20)@@ -240,11 +243,11 @@ , cfenceTileS = HABITAT_CONTAINMENT_WALL , cfenceTileW = HABITAT_CONTAINMENT_WALL , cminStairDist = 10- , cdesc = "History has shown that museal treasures are safer in space than anywhere on Earth. Passengers eagerly attend exhibitions, even if over the weeks of the journey they become increasingly a captive audience. Spaceship crew are not that enthusiastic but even they find reasons to pay visits despite misgivings of museum security. Quite often a museum is the only place within millions of kilometers to house a desperately needed tool, old but sturdy beyond anything a 3D printer can produce."+ , cinitSleep = InitSleepAlways+ , cdesc = "History has shown that museal treasures are safer in space than anywhere on Earth. Passengers eagerly attend exhibitions, even if over the weeks of the journey they become increasingly a captive audience and stifle many a yawn. Spaceship crew are not that enthusiastic but even they find reasons to pay visits despite misgivings of museum security. Quite often a museum is the only place within millions of kilometers to house a desperately needed tool, old but sturdy beyond anything a 3D printer can produce." } laboratory = rogue- { csymbol = 'L'- , cname = "Laboratory"+ { cname = "Laboratory" , cfreq = [(CAVE_LABORATORY, 1)] , cXminSize = 60 , cYminSize = 42@@ -278,8 +281,7 @@ , cdesc = "Shattered glassware and the sharp scent of spilt chemicals show that something terrible happened here. The reinforced bulkheads muffle furious roars." -- a fair warning to skip the level or regroup } noise = rogue- { csymbol = 'N'- , cname = "Computing hardware hub"+ { cname = "Computing hardware hub" , cfreq = [(CAVE_NOISE, 1)] , cXminSize = 25 , cYminSize = 42@@ -292,27 +294,27 @@ , cnightOdds = 0 -- harder variant, but looks cheerful , cauxConnects = 1%10 , cmaxVoid = 1%100- , cdoorChance = 1 -- to enable the doorlessWall hack+ , cdoorChance = 1 -- to prevent openings in solid rooms , chidden = 0- , cactorCoeff = 70 -- the maze requires time to explore; also, small+ , cactorCoeff = 100 -- the maze requires time to explore; also, small , cactorFreq = [(MONSTER, 100), (ANIMAL, 5), (ROBOT, 25)] , citemNum = 16 `d` 2 -- an incentive to explore the labyrinth , citemFreq = [ (IK.COMMON_ITEM, 40), (IK.CRAWL_ITEM, 40) , (IK.TREASURE, 40), (IK.ANY_SCROLL, 200) ] , cplaceFreq = [(NOISE, 1)] , cpassable = True- , labyrinth = True+ , clabyrinth = True , cdefTile = NOISE_SET_LIT , cwallTile = OPENABLE_WALL , cfenceApart = True -- ensures no cut-off parts from collapsed , cdarkCorTile = DAMP_FLOOR_DARK , clitCorTile = DAMP_FLOOR_LIT- , cminStairDist = 15 , cmaxStairsNum = 1 , cstairFreq = [ (CLOSED_LIFT, 50), (OPEN_LIFT, 50) , (TINY_LIFT, 1) ] , cstairAllowed = [ (CLOSED_STAIRCASE, 50), (OPEN_STAIRCASE, 50) , (TINY_STAIRCASE, 1) ]+ , cinitSleep = InitSleepBanned , cdesc = "Several machines still function, processors whirring through routines scheduled by dead men. Some scattered chips can still be read." } power = noise@@ -324,9 +326,9 @@ , cminPlaceSize = DiceXY 7 7 , cmaxPlaceSize = DiceXY 20 20 , cnightOdds = 51 -- easier variant, but looks sinister- , citemNum = 16 `d` 2 , citemFreq = [(IK.COMMON_ITEM, 20), (IK.CRAWL_ITEM, 10), (GEM, 80)] -- can't be "valuable" or template items generated+ , clabyrinth = True , cdefTile = POWER_SET_DARK , cdarkCorTile = OILY_FLOOR_DARK , clitCorTile = OILY_FLOOR_LIT@@ -338,22 +340,22 @@ , cstairAllowed = [ (GATED_CLOSED_LIFT, 50) , (GATED_OPEN_LIFT, 50) , (GATED_TINY_LIFT, 1) ]+ , cinitSleep = InitSleepBanned , cdesc = "A trickle of energy flows through a hub that could power a city. The air is warm and carries organic stench. Once in a while a young animal scurries across a lit patch of ground, pouncing in low gravity." } empty = rogue- { csymbol = 'E'- , cname = "Construction site"+ { cname = "Construction site" , cfreq = [] -- just a template for some others- , ccellSize = DiceXY (2 `d` 8 + 14) 16+ , ccellSize = DiceXY (1 `d` 5 + 18) 16 , cminPlaceSize = DiceXY 9 9 -- normally don't merge , cmaxPlaceSize = DiceXY 50 20 -- often maximize horizontally , cdarkOdds = 1 `d` 100 + 1 `dL` 100 , cnightOdds = 0 -- always day , cauxConnects = 3%2 , cmaxVoid = 0 -- too few rooms to have void and fog common anyway- , cdoorChance = 1 -- to enable the doorlessWall hack+ , cdoorChance = 1 -- to prevent openings in solid rooms , chidden = 0- , cactorCoeff = 40 -- easy to view and plan+ , cactorCoeff = 50 -- easy to view and plan , cactorFreq = [(MONSTER, 10), (ANIMAL, 5), (ROBOT, 85)] , citemNum = 16 `d` 2 -- lots of free space, but extra loot present , cplaceFreq = [(EMPTY, 1)]@@ -363,21 +365,21 @@ , clitCorTile = FLOOR_ARENA_LIT , cwallTile = OPENABLE_WALL , cfenceApart = True -- ensures no cut-off border airlocks and tanks- , cminStairDist = 40+ , cminStairDist = 30 , cstairFreq = [ (WALLED_LIFT, 20), (CLOSED_LIFT, 80) , (TINY_LIFT, 1) ] , cstairAllowed = [ (WALLED_STAIRCASE, 20), (CLOSED_STAIRCASE, 80) , (TINY_STAIRCASE, 1) ] , cdesc = "Not much to see here yet." }-exit = empty+egress = empty { cname = "Shuttle servicing level"- , cfreq = [(CAVE_EXIT, 1)]+ , cfreq = [(CAVE_EGRESS, 1)] , ccellSize = DiceXY (1 `d` 2 + 20) 16 , cmaxPlaceSize = DiceXY 25 20 , cdarkOdds = 51 -- all dark to compensate for the always lit shuttles- , cplaceFreq = [(EXIT, 1)]- , cdefTile = EXIT_SET_LIT+ , cplaceFreq = [(EGRESS, 1)]+ , cdefTile = EGRESS_SET_LIT , cdarkCorTile = TRANSPORT_ROUTE , clitCorTile = TRANSPORT_ROUTE , cfenceTileN = S_BASIC_OUTER_FENCE@@ -385,7 +387,7 @@ , cfenceTileS = AIRLOCK_FENCE , cfenceTileW = HABITAT_CONTAINMENT_WALL , cmaxStairsNum = 2 -- too many hinder generation of shuttles- , cescapeFreq = [(ESCAPE_FROM_SPACESHIP_DOWN, 1)]+ , cescapeFreq = [(SPACESHIP_ESCAPE_DOWN, 1)] , cstairFreq = [(WALLED_LIFT, 20), (TINY_LIFT, 1)] , cstairAllowed = [(WALLED_STAIRCASE, 20), (TINY_STAIRCASE, 1)] , cdesc = "Empty husks and strewn entrails of small craft litter the hangar among cranes and welding machines. The distant main fusion thruster array can be seen to the rear of the spaceship through oriels and airlocks of all sizes."@@ -396,7 +398,8 @@ outermost = empty { cname = "Outermost deck" , cfreq = [(CAVE_OUTERMOST, 100)]- , cactorCoeff = 4 -- shallower than LH, so fewer immediate actors, so boost+ , cdarkOdds = 0 -- all rooms lit, because can be huge and few lights yet+ , cactorCoeff = 5 -- shallower than LH, so fewer immediate actors, so boost , cactorFreq = [ (ANIMAL, 3), (ROBOT, 1) , (IMMOBILE_ROBOT, 90), (IMMOBILE_ANIMAL, 2) , (AQUATIC_ANIMAL, 2) ] -- (AQUATIC_ROBOT, 2)@@ -413,31 +416,33 @@ , cfenceTileS = EMPTY_AIRLOCK_FENCE , cfenceTileW = HABITAT_CONTAINMENT_WALL , cmaxStairsNum = 2- , cdesc = "This is as far as one can go \"down\". The void outside sucks light through the oriel and airlock glass in the walls and floor of this outermost level. Each minute, the dusky melancholic light of the distant Sun attempts for a few seconds to squeeze in but is repelled by artificial lighting.\nThe mucky floor marked by unkempt greenery looks misleadingly straight, its curvature noticeable only across the whole extent of the hull section. Overflowing water basins and series of hanging and stacked tanks double as radiation shields. Hoses writhe on the ground and dangle in thick knots from the ceiling. With proper tools, some of the containers could be opened and working spaces productively employed. There is no junk is space.\nThis deck is the main pressurized cargo bay and storage, with the only other docking hub for small craft located among the giant spaceship's upper levels. Somewhere here must be the airlock you docked your shuttle to and stacked your supplies against."+ , cdesc = T.intercalate "\n"+ [ "This is as far as one can go \"down\". The void outside sucks light through the oriel and airlock glass in the walls and floor of this outermost level. Each minute, the dusky melancholic light of the distant Sun attempts for a few seconds to squeeze in but is repelled by artificial lighting."+ , "The mucky floor marked by unkempt greenery looks misleadingly straight, its curvature noticeable only across the whole extent of the hull section. Overflowing water basins and series of hanging and stacked tanks double as radiation shields. Hoses writhe on the ground and dangle in thick knots from the ceiling. With proper tools, some of the containers could be opened and working spaces productively employed. There is no junk is space."+ , "This deck is the main pressurized cargo bay and storage, with the only other docking hub for small craft located among the giant spaceship's upper levels. Somewhere here must be the airlock you docked your shuttle to and stacked your supplies against." ] -- E and W sides are borders with other level sections, so no oriels. } bridge = rogue- { csymbol = 'B'- , cname = "Captain's bridge"+ { cname = "Captain's bridge" , cfreq = [(CAVE_BRIDGE, 1)]- , cXminSize = 30+ , cXminSize = 37 , cYminSize = 30- , ccellSize = DiceXY (2 `d` 4 + 5) (1 `d` 2 + 5)- , cminPlaceSize = DiceXY (2 `d` 2 + 3) (1 `d` 2 + 4) -- sometimes merge all+ , ccellSize = DiceXY (2 `d` 2 + 7) (1 `d` 2 + 5)+ , cminPlaceSize = DiceXY (2 `d` 2 + 5) (1 `d` 2 + 4) -- sometimes merge all , cmaxPlaceSize = DiceXY 16 20 , cdarkOdds = 0 -- all rooms lit, for a gentle start- , cauxConnects = 2 -- few rooms, so many corridors- , cactorCoeff = 300 -- it's quite deep already, so spawn slowly;+ , cauxConnects = 1 -- few rooms, so many corridors+ , cmaxVoid = 1%4 -- few rooms, so increase the chance of any void+ , cactorCoeff = 400 -- it's quite deep already, so spawn slowly; -- this is initially the best level for sleeping , cactorFreq = [(ANIMAL, 100)]- , citemNum = 12 `d` 2 -- lure them in with loot+ , citemNum = 16 -- make the initial experience tamer , citemFreq = [(IK.COMMON_ITEM, 100), (GARDENING_TOOL, 800)] , cdefTile = FILLER_WALL , cfenceTileN = HABITAT_CONTAINMENT_WALL -- cave isolated for safety , cfenceTileE = HABITAT_CONTAINMENT_WALL , cfenceTileS = HABITAT_CONTAINMENT_WALL , cfenceTileW = HABITAT_CONTAINMENT_WALL- , cminStairDist = 10 , cmaxStairsNum = 1 , cstairFreq = [ (WELDED_WALLED_LIFT, 50) , (WELDED_OPEN_LIFT, 50)@@ -451,16 +456,52 @@ { cfreq = [(CAVE_SHALLOW_ROGUE, 100)] , cXminSize = 60 , cYminSize = 37- , cactorCoeff = 120 -- more difficult+ , cactorCoeff = 150 -- more difficult , cactorFreq = filter ((/= MONSTER) . fst) $ cactorFreq rogue- , citemNum = 14 `d` 2+ , citemNum = 20 -- make the initial experience tamer , citemFreq = [ (IK.COMMON_ITEM, 40), (IK.CRAWL_ITEM, 60) , (GARDENING_TOOL, 700), (IK.ANY_FLASK, 200) ]- , cminStairDist = 15 , cmaxStairsNum = 2 , cskip = [0, 1] -- ban foes camping on either stairs- , cdesc = "This close to the outermost deck, residence is not permitted and walls and doors are sturdier to contain a theoretically possible micro-meteorite breach. The entry is not closed off, though, because some passengers can't live without a regular pilgrimage to 'look outside' and the only way to the bottom-most level leads through here. Apparently, gazing at the sharp pin-points of stars and planets through the reinforced oriel glass is incomparable to watching the same through the thin polymer of wall displays.\nAnimals appear to share the fascination of outer decks, perhaps attracted by the increased gravity, nearly Earth-like, unlike elsewhere on the ship. However, they dislike many industrial fluids stored on these floors, so flinging random flasks at them works as an effective deterrent. Moreover, if you throw an unidentified flask, you can be sure you won't waste a badly needed nano medicine, because it's never stored in such large containers. Even tiny vials cost a fortune."+ , cdesc = T.intercalate "\n"+ [ "This close to the outermost deck, residence is not permitted and walls and doors are sturdier to contain a theoretically possible micro-meteorite breach. The entry is not closed off, though, because some passengers can't live without a regular pilgrimage to 'look outside' and the only way to the bottom-most level leads through here. Apparently, gazing at the sharp pin-points of stars and planets through the reinforced oriel glass is incomparable to watching the same through the thin polymer of wall displays."+ , "Animals appear to share the fascination of outer decks, perhaps attracted by the increased gravity, nearly Earth-like, unlike elsewhere on the ship. However, they dislike many industrial fluids stored on these floors, so flinging random flasks at them works as an effective deterrent. Moreover, if you throw an unidentified flask, you can be sure you won't waste a badly needed nano medicine, because it's never stored in such large containers. Even tiny vials cost a fortune." ] }+virus = rogue -- this is a hard level requiring preparation; can be skipped+ { cname = "Machinarium"+ , cfreq = [(CAVE_VIRUS, 1)]+ , cXminSize = 17+ , cYminSize = 13+ , ccellSize = DiceXY 4 4+ , cminPlaceSize = DiceXY 3 3+ , cmaxPlaceSize = DiceXY 5 4+ , cdarkOdds = 51 -- all rooms dark+ , cnightOdds = 51 -- always night+ , cauxConnects = 0+ , cmaxVoid = 0+ , cdoorChance = 0 -- openings in solid rooms are fine, because rooms tiny+ , chidden = 0+ , cactorCoeff = 4 -- fast spawning+ , cactorFreq = [(MOBILE_ROBOT, 100)] -- only mobile, for fast action+ , citemNum = 12 -- avoid random excess given the low area+ , citemFreq = [(IK.COMMON_ITEM, 70), (IK.CRAWL_ITEM, 30)]+ , cplaceFreq = [(VIRUS, 1)]+ , cpassable = True+ , clabyrinth = True -- don't let aliens explore and farm the robots+ , cdefTile = VIRUS_SET_DARK+ , cdarkCorTile = OILY_FLOOR_DARK+ , clitCorTile = OILY_FLOOR_LIT+ , cwallTile = OPENABLE_WALL+ , cfenceTileN = HABITAT_CONTAINMENT_WALL -- small cave+ , cfenceTileE = HABITAT_CONTAINMENT_WALL+ , cfenceTileS = HABITAT_CONTAINMENT_WALL+ , cfenceTileW = HABITAT_CONTAINMENT_WALL+ , cfenceApart = True -- ensures no cut-off parts from collapsed+ , cmaxStairsNum = 1+ , cstairFreq = [(TINY_LIFT, 1)]+ , cstairAllowed = [(TINY_STAIRCASE, 1)]+ , cdesc = "The hall surrounded by automated warehouses is where ship's robots are repaired, decommissioned, stored and recycled. This one has been completely cut off from the vessel's network and even lights are out. And yet, the hot darkness smelling of ozone carries echos of arcing and clanking all around."+ } -- * "Caves" on various celestial bodies (including, but not limited to, moons, -- with virtually no story-wise limits wrt height and size.@@ -469,9 +510,44 @@ -- in symmetric scenarios, where both parties can use extra loot -- equally well. +gauntlet = rogue+ { cname = "Service tunnel"+ , cfreq = [(CAVE_GAUNTLET, 1)]+ , cXminSize = 52 -- long tunnel+ , cYminSize = 8+ , ccellSize = DiceXY 6 4+ , cminPlaceSize = DiceXY 5 3+ , cmaxPlaceSize = DiceXY 6 3+ , cdarkOdds = 0 -- all rooms lit, for a gentle start+ , cnightOdds = 0+ , cauxConnects = 0+ , cmaxVoid = 0+ , cdoorChance = 1%3 -- openings in solid rooms are fine, because rooms tiny+ , chidden = 0+ , cactorCoeff = 4 -- fast spawning+ , cactorFreq = [(GAUNTLET_ROBOT, 100)] -- no drops; tutorial; avoid stash+ , citemNum = 0 -- first tutorial mode, no need for a stash+ , citemFreq = [] -- first tutorial level, no need for a stash+ , cplaceFreq = [(GAUNTLET, 1)] -- first tutorial mode; keep it simple+ , cpassable = True+ , cdefTile = VIRUS_SET_LIT -- first tutorial mode; keep it simple+ , cwallTile = OPENABLE_WALL+ , cfenceTileN = HABITAT_CONTAINMENT_WALL+ , cfenceTileE = HABITAT_CONTAINMENT_WALL+ , cfenceTileS = HABITAT_CONTAINMENT_WALL+ , cfenceTileW = HABITAT_CONTAINMENT_WALL+ , cmaxStairsNum = 0+ , cescapeFreq = [(ALARM_ESCAPE_UP, 1)]+ , cstairFreq = []+ , cstairAllowed = []+ , cinitSleep = InitSleepBanned -- to make it harder to escape freely+ , cskip = [0] -- don't start heroes nor opponents on escape+ , cdesc = T.intercalate "\n"+ [ "Triton's cryothermal vents that supply energy and resources to the city are spread far apart. That funnels the unregulated sprawl of the sublunar city wide rather than deep and favours tunnels over domes."+ , "The deepest tunnels, such as this one, serve exclusively as emergency secondary connections between Triton City forges, farms and population centers. They are devoid of amenities and normally unused except by lazy maintenance crews storing and then leaving behind defunct machinery and leftover spare parts. Nobody can be contacted from such a remote corridor, except through a red alarm console, mandatory per every 100m of transport tunnels." ]+ } raid = rogue- { csymbol = 'S'- , cname = "Triton City sewers"+ { cname = "Triton City sewers" , cfreq = [(CAVE_RAID, 1)] , cXminSize = 60 -- long sewer tunnels , cYminSize = 21@@ -479,11 +555,13 @@ , cminPlaceSize = DiceXY (2 `d` 2 + 4) 5 -- sometimes merge all , cmaxPlaceSize = DiceXY 16 20 , cdarkOdds = 0 -- all rooms lit, for a gentle start- , cmaxVoid = 1%10+ , cmaxVoid = 1%5+ , cdoorChance = 1 -- make sure enemies not seen on turn 1+ , copenChance = 0 -- make sure enemies not seen on turn 1 , cdefTile = FILLER_WALL- , cactorCoeff = 250 -- deep level with no kit, so slow spawning+ , cactorCoeff = 300 -- deep level with no kit, so slow spawning , cactorFreq = [(ANIMAL, 50), (ROBOT, 50)]- , citemNum = 9 `d` 6 -- just one level, hard enemies, treasure+ , citemNum = 20 -- make the initial experience tamer , citemFreq = [ (IK.COMMON_ITEM, 30) , (STARTING_ARMOR, 100), (STARTING_WEAPON, 300) , (WEAK_ARROW, 100), (LIGHT_ATTENUATOR, 50)@@ -499,8 +577,7 @@ brawl = rogue -- many random solid tiles, to break LOS, since it's a day -- and this scenario is not focused on ranged combat; -- also, sanctuaries against missiles in shadow under trees- { csymbol = 'S'- , cname = "Woodland biosphere"+ { cname = "Woodland biosphere" , cfreq = [(CAVE_BRAWL, 1)] , cXminSize = 60 , cYminSize = 30@@ -544,8 +621,7 @@ -- opaque tiles, to make scouting and sniping more interesting -- and to avoid obstructing view too much, since this -- scenario is about ranged combat at long range- { csymbol = 'S'- , cname = "Hydroponic farm" -- still a neutral, official wording+ { cname = "Hydroponic farm" -- still a neutral, official wording , cfreq = [(CAVE_SHOOTOUT, 1)] , ccellSize = DiceXY (1 `d` 2 + 5) 6 , cminPlaceSize = DiceXY 3 3 -- rarely merge vertically@@ -559,7 +635,9 @@ , cactorFreq = [] , citemNum = 6 `d` 16 -- less items in inventory, more to be picked up,- -- to reward explorer and aggressor and punish camper+ -- to reward explorer and aggressor and punish camper;+ -- very different experience depending on the roll,+ -- but it's symmetric, so it's fine , citemFreq = [ (IK.COMMON_ITEM, 30), (GARDENING_TOOL, 500) , (ANY_ARROW, 400), (HARPOON, 200), (IK.EXPLOSIVE, 300) ] -- Many consumable buffs are needed in symmetric maps@@ -578,8 +656,7 @@ } hunt = rogue -- a scenario with strong missiles for ranged and shade for melee; -- the human is likely to focus on melee, not having overwatch- { csymbol = 'H'- , cname = "Swamp biosphere"+ { cname = "Swamp biosphere" , cfreq = [(CAVE_HUNT, 1)] , ccellSize = DiceXY (1 `d` 2 + 5) 6 , cminPlaceSize = DiceXY 3 3 -- rarely merge vertically@@ -590,7 +667,8 @@ , cdoorChance = 1 , copenChance = 0 , chidden = 0- , cactorFreq = []+ , cactorCoeff = 400 -- spawn slowly+ , cactorFreq = [(INSECT, 100)] , citemNum = 6 `d` 10 , citemFreq = [(IK.COMMON_ITEM, 30), (ANY_ARROW, 60), (HARPOON, 30)] , cplaceFreq = [(BRAWL, 50), (SHOOTOUT, 100)]@@ -602,15 +680,14 @@ , cmaxStairsNum = 0 , cstairFreq = [] , cstairAllowed = []- , cdesc = "Mangrove trees and murky water, inspired by a habitat now eradicated from Earth."+ , cdesc = "Mangrove trees and murky water, inspired by a habitat now eradicated from Earth. A rather deadly habitat." }-escape = rogue -- a scenario with weak missiles, because heroes don't depend+flight = rogue -- a scenario with weak missiles, because heroes don't depend -- on them; dark, so solid obstacles are to hide from missiles, -- not view; obstacles are not lit, to frustrate the AI; -- lots of small lights to cross, to have some risks- { csymbol = 'E'- , cname = "Red Collar Bros den" -- tension rises; non-official name- , cfreq = [(CAVE_ESCAPE, 1)]+ { cname = "Red Collar Bros den" -- tension rises; non-official name+ , cfreq = [(CAVE_FLIGHT, 1)] , ccellSize = DiceXY (1 `d` 3 + 6) 7 , cminPlaceSize = DiceXY 5 4 -- rarely merge , cmaxPlaceSize = DiceXY 9 9 -- bias towards larger lamp areas@@ -624,9 +701,9 @@ , citemFreq = [ (IK.COMMON_ITEM, 30), (STARTING_ARMOR, 100) , (LIGHT_ATTENUATOR, 300), (GEM, 400) , (WEAK_ARROW, 400), (HARPOON, 200), (IK.EXPLOSIVE, 200) ]- , cplaceFreq = [(ESCAPE, 1)]+ , cplaceFreq = [(FLIGHT, 1)] , cpassable = True- , cdefTile = ESCAPE_SET_DARK+ , cdefTile = FLIGHT_SET_DARK , cdarkCorTile = SAFE_TRAIL_LIT -- let trails give off light , clitCorTile = SAFE_TRAIL_LIT , cwallTile = OPENABLE_WALL@@ -638,8 +715,7 @@ , cdesc = "Graffiti scrawls across the walls and the heavy scents of stimulants hang in the air." } zoo = rogue -- few lights and many solids, to help the less numerous heroes- { csymbol = 'Z'- , cname = "Municipal zoo in flames" -- non-official adjective+ { cname = "Municipal zoo in flames" -- non-official adjective , cfreq = [(CAVE_ZOO, 1)] , ccellSize = DiceXY (1 `d` 4 + 7) 8 , cminPlaceSize = DiceXY 4 4 -- don't merge@@ -652,7 +728,7 @@ , copenChance = 9%10 , chidden = 0 , cactorFreq = []- , citemNum = 9 `d` 8+ , citemNum = 10 `d` 8 , citemFreq = [ (IK.COMMON_ITEM, 100), (LIGHT_ATTENUATOR, 1000) , (STARTING_ARMOR, 500), (STARTING_WEAPON, 1000) ] , cplaceFreq = [(ZOO, 1)]@@ -676,8 +752,7 @@ -- camping doesn't pay off, because enemies can sneak and only -- active scouting, throwing flares and shooting discovers them -- and the level is big enough for all that- { csymbol = 'M'- , cname = "Ravaged spaceport" -- non-official adjective+ { cname = "Ravaged spaceport" -- non-official adjective , cfreq = [(CAVE_AMBUSH, 1)] , ccellSize = DiceXY 11 6 , cminPlaceSize = DiceXY 9 10 -- merge vertically@@ -705,8 +780,7 @@ -- * Other caves; testing, Easter egg, future work battle = rogue -- few lights and many solids, to help the less numerous heroes- { csymbol = 'B'- , cname = "Old industrial plant"+ { cname = "Old industrial plant" , cfreq = [(CAVE_BATTLE, 1)] , ccellSize = DiceXY (5 `d` 3 + 11) 7 , cminPlaceSize = DiceXY 4 4@@ -743,7 +817,7 @@ , cskip = [0] , cdesc = "\"DLC 1. Hunams scavenge in a forest in their usual disgusting way.\"" }-safari2 = escape -- lamps instead of trees, but ok, it's only a simulation+safari2 = flight -- lamps instead of trees, but ok, it's only a simulation { cname = "Deep into the jungle" , cfreq = [(CAVE_SAFARI_2, 1)] , cmaxStairsNum = 1
+ GameDefinition/Content/FactionKind.hs view
@@ -0,0 +1,471 @@+-- Copyright (c) 2008--2011 Andres Loeh+-- Copyright (c) 2010--2021 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.+--+-- | Definitions of kinds of factions present in a game, both human+-- and computer-controlled.+module Content.FactionKind+ ( -- * Group name patterns+ pattern EXPLORER_REPRESENTATIVE, pattern EXPLORER_SHORT, pattern EXPLORER_NO_ESCAPE, pattern EXPLORER_MEDIUM, pattern EXPLORER_TRAPPED, pattern EXPLORER_AUTOMATED, pattern EXPLORER_AUTOMATED_TRAPPED, pattern EXPLORER_CAPTIVE, pattern EXPLORER_PACIFIST, pattern COMPETITOR_REPRESENTATIVE, pattern COMPETITOR_SHORT, pattern COMPETITOR_NO_ESCAPE, pattern CIVILIAN_REPRESENTATIVE, pattern CONVICT_REPRESENTATIVE, pattern MONSTER_REPRESENTATIVE, pattern MONSTER_ANTI, pattern MONSTER_ANTI_CAPTIVE, pattern MONSTER_ANTI_PACIFIST, pattern MONSTER_TOURIST, pattern MONSTER_TOURIST_PASSIVE, pattern MONSTER_CAPTIVE, pattern MONSTER_CAPTIVE_NARRATING, pattern ANIMAL_REPRESENTATIVE, pattern ANIMAL_MAGNIFICENT, pattern ANIMAL_EXQUISITE, pattern ANIMAL_CAPTIVE, pattern ANIMAL_NARRATING, pattern ANIMAL_MAGNIFICENT_NARRATING, pattern ANIMAL_CAPTIVE_NARRATING, pattern HORROR_REPRESENTATIVE, pattern HORROR_CAPTIVE, pattern HORROR_PACIFIST+ , pattern EXPLORER_EXTERMINATOR, pattern ROBOT_REPRESENTATIVE, pattern ROBOT_CAPTIVE, pattern ROBOT_NARRATING, pattern ROBOT_VIRUS, pattern ROBOT_GAUNTLET, pattern OFF_WORLD_REPRESENTATIVE+ , pattern REPRESENTATIVE+ , pattern ANIMAL_OR_ROBOT_NARRATING+ , groupNamesSingleton, groupNames+ , -- * Content+ content+#ifdef EXPOSE_INTERNAL+ , hiHeroExterminator+#endif+ ) where++import Prelude ()++import Game.LambdaHack.Core.Prelude++import Game.LambdaHack.Content.FactionKind+import qualified Game.LambdaHack.Content.ItemKind as IK+import Game.LambdaHack.Definition.Ability+import Game.LambdaHack.Definition.Defs+import Game.LambdaHack.Definition.DefsInternal++import Content.ItemKindActor+import Content.ItemKindOrgan++-- * Group name patterns++groupNamesSingleton :: [GroupName FactionKind]+groupNamesSingleton =+ [EXPLORER_REPRESENTATIVE, EXPLORER_SHORT, EXPLORER_NO_ESCAPE, EXPLORER_MEDIUM, EXPLORER_TRAPPED, EXPLORER_AUTOMATED, EXPLORER_AUTOMATED_TRAPPED, EXPLORER_CAPTIVE, EXPLORER_PACIFIST, COMPETITOR_REPRESENTATIVE, COMPETITOR_SHORT, COMPETITOR_NO_ESCAPE, CIVILIAN_REPRESENTATIVE, CONVICT_REPRESENTATIVE, MONSTER_REPRESENTATIVE, MONSTER_ANTI, MONSTER_ANTI_CAPTIVE, MONSTER_ANTI_PACIFIST, MONSTER_TOURIST, MONSTER_TOURIST_PASSIVE, MONSTER_CAPTIVE, MONSTER_CAPTIVE_NARRATING, ANIMAL_REPRESENTATIVE, ANIMAL_MAGNIFICENT, ANIMAL_EXQUISITE, ANIMAL_CAPTIVE, ANIMAL_NARRATING, ANIMAL_MAGNIFICENT_NARRATING, ANIMAL_CAPTIVE_NARRATING, HORROR_REPRESENTATIVE, HORROR_CAPTIVE, HORROR_PACIFIST]+ ++ [EXPLORER_EXTERMINATOR, ROBOT_REPRESENTATIVE, ROBOT_CAPTIVE, ROBOT_NARRATING, ROBOT_VIRUS, ROBOT_GAUNTLET, OFF_WORLD_REPRESENTATIVE]++pattern EXPLORER_REPRESENTATIVE, EXPLORER_SHORT, EXPLORER_NO_ESCAPE, EXPLORER_MEDIUM, EXPLORER_TRAPPED, EXPLORER_AUTOMATED, EXPLORER_AUTOMATED_TRAPPED, EXPLORER_CAPTIVE, EXPLORER_PACIFIST, COMPETITOR_REPRESENTATIVE, COMPETITOR_SHORT, COMPETITOR_NO_ESCAPE, CIVILIAN_REPRESENTATIVE, CONVICT_REPRESENTATIVE, MONSTER_REPRESENTATIVE, MONSTER_ANTI, MONSTER_ANTI_CAPTIVE, MONSTER_ANTI_PACIFIST, MONSTER_TOURIST, MONSTER_TOURIST_PASSIVE, MONSTER_CAPTIVE, MONSTER_CAPTIVE_NARRATING, ANIMAL_REPRESENTATIVE, ANIMAL_MAGNIFICENT, ANIMAL_EXQUISITE, ANIMAL_CAPTIVE, ANIMAL_NARRATING, ANIMAL_MAGNIFICENT_NARRATING, ANIMAL_CAPTIVE_NARRATING, HORROR_REPRESENTATIVE, HORROR_CAPTIVE, HORROR_PACIFIST :: GroupName FactionKind++pattern EXPLORER_EXTERMINATOR, ROBOT_REPRESENTATIVE, ROBOT_CAPTIVE, ROBOT_NARRATING, ROBOT_VIRUS, ROBOT_GAUNTLET, OFF_WORLD_REPRESENTATIVE :: GroupName FactionKind++groupNames :: [GroupName FactionKind]+groupNames = [REPRESENTATIVE, ANIMAL_OR_ROBOT_NARRATING]++-- This pattern was supposed to be used in faction lore to distinguish+-- the faction kinds to show. Instead all factions from the current game+-- are shown. Perhaps in the future we'll also show encountered actions+-- from previous games and then this will be useful to limit the number.+pattern REPRESENTATIVE :: GroupName FactionKind++pattern ANIMAL_OR_ROBOT_NARRATING :: GroupName FactionKind++pattern REPRESENTATIVE = GroupName "representative"+pattern EXPLORER_REPRESENTATIVE = GroupName "explorer"+pattern EXPLORER_SHORT = GroupName "explorer short"+pattern EXPLORER_NO_ESCAPE = GroupName "explorer no escape"+pattern EXPLORER_MEDIUM = GroupName "explorer medium"+pattern EXPLORER_TRAPPED = GroupName "explorer trapped"+pattern EXPLORER_AUTOMATED = GroupName "explorer automated"+pattern EXPLORER_AUTOMATED_TRAPPED = GroupName "explorer automated trapped"+pattern EXPLORER_CAPTIVE = GroupName "explorer captive"+pattern EXPLORER_PACIFIST = GroupName "explorer pacifist"+pattern COMPETITOR_REPRESENTATIVE = GroupName "competitor"+pattern COMPETITOR_SHORT = GroupName "competitor short"+pattern COMPETITOR_NO_ESCAPE = GroupName "competitor no escape"+pattern CIVILIAN_REPRESENTATIVE = GroupName "civilian"+pattern CONVICT_REPRESENTATIVE = GroupName "convict"+pattern MONSTER_REPRESENTATIVE = GroupName "monster"+pattern MONSTER_ANTI = GroupName "monster anti"+pattern MONSTER_ANTI_CAPTIVE = GroupName "monster anti captive"+pattern MONSTER_ANTI_PACIFIST = GroupName "monster anti pacifist"+pattern MONSTER_TOURIST = GroupName "monster tourist"+pattern MONSTER_TOURIST_PASSIVE = GroupName "monster tourist passive"+pattern MONSTER_CAPTIVE = GroupName "monster captive"+pattern MONSTER_CAPTIVE_NARRATING = GroupName "monster captive narrating"+pattern ANIMAL_REPRESENTATIVE = GroupName "animal"+pattern ANIMAL_MAGNIFICENT = GroupName "animal magnificent"+pattern ANIMAL_EXQUISITE = GroupName "animal exquisite"+pattern ANIMAL_CAPTIVE = GroupName "animal captive"+pattern ANIMAL_NARRATING = GroupName "animal narrating"+pattern ANIMAL_MAGNIFICENT_NARRATING = GroupName "animal magnificent narrating"+pattern ANIMAL_CAPTIVE_NARRATING = GroupName "animal captive narrating"+pattern HORROR_REPRESENTATIVE = GroupName "horror"+pattern HORROR_CAPTIVE = GroupName "horror captive"+pattern HORROR_PACIFIST = GroupName "horror pacifist"++-- ** Allure-specific++pattern ANIMAL_OR_ROBOT_NARRATING = GroupName "animal or robot narrating"++pattern EXPLORER_EXTERMINATOR = GroupName "explorer exterminator"+pattern ROBOT_REPRESENTATIVE = GroupName "robot"+pattern ROBOT_CAPTIVE = GroupName "robot captive"+pattern ROBOT_NARRATING = GroupName "robot narrating"+pattern ROBOT_VIRUS = GroupName "robot replicant"+pattern ROBOT_GAUNTLET = GroupName "robot virus-infested"+pattern OFF_WORLD_REPRESENTATIVE = GroupName "off-world mercenary"++-- * Teams++teamCompetitor, teamCivilian, teamConvict, teamMonster, teamAnimal, teamHorror, teamRobot, teamOffWorld, teamOther :: TeamContinuity+teamCompetitor = TeamContinuity 2+teamCivilian = TeamContinuity 3+teamConvict = TeamContinuity 4+teamMonster = TeamContinuity 5+teamAnimal = TeamContinuity 6+teamHorror = TeamContinuity 7+teamRobot = TeamContinuity 8+teamOffWorld = TeamContinuity 9+teamOther = TeamContinuity 10++-- * Content++content :: [FactionKind]+content = [factExplorer, factExplorerShort, factExplorerNoEscape, factExplorerMedium, factExplorerTrapped, factExplorerAutomated, factExplorerAutomatedTrapped, factExplorerCaptive, factExplorerPacifist, factCompetitor, factCompetitorShort, factCompetitorNoEscape, factCivilian, factConvict, factMonster, factMonsterAnti, factMonsterAntiCaptive, factMonsterAntiPacifist, factMonsterTourist, factMonsterTouristPassive, factMonsterCaptive, factMonsterCaptiveNarrating, factAnimal, factAnimalMagnificent, factAnimalExquisite, factAnimalCaptive, factAnimalNarrating, factAnimalMagnificentNarrating, factAnimalCaptiveNarrating, factHorror, factHorrorCaptive, factHorrorPacifist]+ ++ [factExplorerExterminator, factRobot, factRobotCaptive, factRobotNarrating, factRobotVirus, factRobotGauntlet, factOffWorld]++factExplorer, factExplorerShort, factExplorerNoEscape, factExplorerMedium, factExplorerTrapped, factExplorerAutomated, factExplorerAutomatedTrapped, factExplorerCaptive, factExplorerPacifist, factCompetitor, factCompetitorShort, factCompetitorNoEscape, factCivilian, factConvict, factMonster, factMonsterAnti, factMonsterAntiCaptive, factMonsterAntiPacifist, factMonsterTourist, factMonsterTouristPassive, factMonsterCaptive, factMonsterCaptiveNarrating, factAnimal, factAnimalMagnificent, factAnimalExquisite, factAnimalCaptive, factAnimalNarrating, factAnimalMagnificentNarrating, factAnimalCaptiveNarrating, factHorror, factHorrorCaptive, factHorrorPacifist :: FactionKind++factExplorerExterminator, factRobot, factRobotCaptive, factRobotNarrating, factRobotVirus, factRobotGauntlet, factOffWorld :: FactionKind++-- * Content++-- ** teamExplorer++factExplorer = FactionKind+ { fname = "Spacefarer"+ , ffreq = [(EXPLORER_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamExplorer+ , fgroups = [(HERO, 100)] -- don't spam the escapists, etc., in description+ , fskillsOther = meleeAdjacent+ , fcanEscape = True+ , fneverEmpty = True+ , fhiCondPoly = hiHeroLong+ , fhasGender = True+ , finitDoctrine = TExplore+ , fspawnsFast = False+ , fhasPointman = True+ , fhasUI = True+ , finitUnderAI = False+ , fenemyTeams =+ [teamCompetitor, teamMonster, teamAnimal, teamRobot, teamHorror]+ , falliedTeams = []+ }+factExplorerShort = factExplorer+ { ffreq = [(EXPLORER_SHORT, 1)]+ , fhiCondPoly = hiHeroShort+ }+factExplorerNoEscape = factExplorer+ { ffreq = [(EXPLORER_NO_ESCAPE, 1)]+ , fcanEscape = False+ , fhiCondPoly = hiHeroMedium+ }+factExplorerMedium = factExplorer+ { ffreq = [(EXPLORER_MEDIUM, 1)]+ , fhiCondPoly = hiHeroMedium+ }+factExplorerTrapped = factExplorer+ { ffreq = [(EXPLORER_TRAPPED, 1)]+ , fcanEscape = False+ , fhiCondPoly = hiHeroLong+ }+factExplorerAutomated = factExplorer+ { ffreq = [(EXPLORER_AUTOMATED, 1)]+ , fhasUI = False+ , finitUnderAI = True+ }+factExplorerAutomatedTrapped = factExplorerAutomated+ { ffreq = [(EXPLORER_AUTOMATED_TRAPPED, 1)]+ , fcanEscape = False+ , fhiCondPoly = hiHeroLong+ }+factExplorerCaptive = factExplorer+ { ffreq = [(EXPLORER_CAPTIVE, 1)]+ , fneverEmpty = True -- already there+ }+factExplorerPacifist = factExplorerCaptive+ { ffreq = [(EXPLORER_PACIFIST, 1)]+ , fenemyTeams = []+ , falliedTeams = []+ }++-- ** teamCompetitor, symmetric opponents of teamExplorer++factCompetitor = factExplorer+ { fname = "Red Collar Bro"+ , ffreq = [(COMPETITOR_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamCompetitor+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamExplorer, teamMonster, teamAnimal, teamRobot, teamHorror]+ , falliedTeams = []+ }+factCompetitorShort = factCompetitor+ { ffreq = [(COMPETITOR_SHORT, 1)]+ , fhiCondPoly = hiHeroShort+ }+factCompetitorNoEscape = factCompetitor+ { ffreq = [(COMPETITOR_NO_ESCAPE, 1)]+ , fcanEscape = False+ , fhiCondPoly = hiHeroMedium+ }++-- ** teamCivilian++factCivilian = FactionKind+ { fname = "Civilian"+ , ffreq = [(CIVILIAN_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamCivilian+ , fgroups = [(HERO, 100), (CIVILIAN, 100)] -- symmetric vs player+ , fskillsOther = zeroSkills -- not coordinated by any leadership+ , fcanEscape = False+ , fneverEmpty = True+ , fhiCondPoly = hiHeroMedium+ , fhasGender = True+ , finitDoctrine = TPatrol+ , fspawnsFast = False+ , fhasPointman = False -- unorganized+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamMonster, teamAnimal, teamRobot, teamHorror]+ , falliedTeams = []+ }++-- ** teamConvict, different demographics++factConvict = factCivilian+ { fname = "Hunam Convict"+ , ffreq = [(CONVICT_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamConvict+ , fhasPointman = True -- convicts organize better+ , finitUnderAI = True+ , fenemyTeams = [teamMonster, teamAnimal, teamRobot, teamHorror]+ , falliedTeams = []+ }++-- ** teamMonster++factMonster = FactionKind+ { fname = "Alien Hierarchy"+ , ffreq = [(MONSTER_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamMonster+ , fgroups = [ (MONSTER, 100)+ , (MOBILE_MONSTER, 1), (AQUATIC_MONSTER, 1) ]+ , fskillsOther = zeroSkills+ , fcanEscape = False+ , fneverEmpty = False+ , fhiCondPoly = hiDweller+ , fhasGender = False+ , finitDoctrine = TExplore+ , fspawnsFast = True+ , fhasPointman = True+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = [teamAnimal, teamRobot]+ }+-- This has continuity @teamMonster@, despite being playable.+factMonsterAnti = factMonster+ { ffreq = [(MONSTER_ANTI, 1)]+ , fhasUI = True+ , finitUnderAI = False+ }+factMonsterAntiCaptive = factMonsterAnti+ { ffreq = [(MONSTER_ANTI_CAPTIVE, 1)]+ , fneverEmpty = True+ }+factMonsterAntiPacifist = factMonsterAntiCaptive+ { ffreq = [(MONSTER_ANTI_PACIFIST, 1)]+ , fenemyTeams = []+ , falliedTeams = []+ }+-- More flavour and special backstory, but the same team.+factMonsterTourist = factMonsterAnti+ { fname = "Alien Tourist Office"+ , ffreq = [(MONSTER_TOURIST, 1)]+ , fcanEscape = True+ , fneverEmpty = True -- no spawning+ , fhiCondPoly = hiHeroMedium+ , finitDoctrine = TFollow -- follow-the-guide, as tourists do+ , fspawnsFast = False -- on a trip, so no spawning+ , finitUnderAI = False+ , fenemyTeams =+ [teamAnimal, teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = [teamRobot]+ }+factMonsterTouristPassive = factMonsterTourist+ { ffreq = [(MONSTER_TOURIST_PASSIVE, 1)]+ , fhasUI = False+ , finitUnderAI = True+ }+factMonsterCaptive = factMonster+ { ffreq = [(MONSTER_CAPTIVE, 1)]+ , fneverEmpty = True+ }+factMonsterCaptiveNarrating = factMonsterAntiCaptive+ { ffreq = [(MONSTER_CAPTIVE_NARRATING, 1)]+ , fhasUI = True+ }++-- ** teamAnimal++factAnimal = FactionKind+ { fname = "Animal Kingdom"+ , ffreq = [(ANIMAL_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamAnimal+ , fgroups = [ (ANIMAL, 100), (INSECT, 100), (AQUATIC_ANIMAL, 100)+ -- only the distinct enough ones+ , (MOBILE_ANIMAL, 1), (IMMOBILE_ANIMAL, 1), (SCAVENGER, 1) ]+ , fskillsOther = zeroSkills+ , fcanEscape = False+ , fneverEmpty = False+ , fhiCondPoly = hiDweller+ , fhasGender = False+ , finitDoctrine = TRoam -- can't pick up, so no point exploring+ , fspawnsFast = True+ , fhasPointman = False+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = [teamMonster, teamRobot]+ }+-- These two differ from outside, but share information and boasting+-- about them tends to be general, too.+factAnimalMagnificent = factAnimal+ { fname = "Animal Magnificent Specimen Variety"+ , ffreq = [(ANIMAL_MAGNIFICENT, 1)]+ , fneverEmpty = True+ , fenemyTeams =+ [teamMonster, teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = []+ }+factAnimalExquisite = factAnimal+ { fname = "Animal Exquisite Herds and Packs Galore"+ , ffreq = [(ANIMAL_EXQUISITE, 1)]+ , fteam = teamOther+ -- in the same mode as @factAnimalMagnificent@, so borrow+ -- identity from horrors to avoid a clash+ , fneverEmpty = True+ , fenemyTeams =+ [teamMonster, teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = []+ }+factAnimalCaptive = factAnimal+ { ffreq = [(ANIMAL_CAPTIVE, 1)]+ , fneverEmpty = True+ }+factAnimalNarrating = factAnimal+ { ffreq = [(ANIMAL_NARRATING, 1), (ANIMAL_OR_ROBOT_NARRATING, 70)]+ , fhasUI = True+ }+factAnimalMagnificentNarrating = factAnimalMagnificent+ { ffreq = [(ANIMAL_MAGNIFICENT_NARRATING, 1)]+ , fhasPointman = True+ , fhasUI = True+ , finitUnderAI = False+ }+factAnimalCaptiveNarrating = factAnimalCaptive+ { ffreq = [(ANIMAL_CAPTIVE_NARRATING, 1)]+ , fhasUI = True+ }++-- ** teamHorror, not much of a continuity intended, but can't be ignored++-- | A special faction, for summoned actors that don't belong to any+-- of the main factions of a given game. E.g., animals summoned during+-- a brawl game between two hero factions land in the horror faction.+-- In every game, either all factions for which summoning items exist+-- should be present or a horror faction should be added to host them.+factHorror = FactionKind+ { fname = "Horror Den"+ , ffreq = [(HORROR_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamHorror+ , fgroups = [(IK.HORROR, 100)]+ , fskillsOther = zeroSkills+ , fcanEscape = False+ , fneverEmpty = False+ , fhiCondPoly = []+ , fhasGender = False+ , finitDoctrine = TPatrol -- disoriented+ , fspawnsFast = False+ , fhasPointman = False+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = []+ }+factHorrorCaptive = factHorror+ { ffreq = [(HORROR_CAPTIVE, 1)]+ , fneverEmpty = True+ }+factHorrorPacifist = factHorrorCaptive+ { ffreq = [(HORROR_PACIFIST, 1)]+ , fenemyTeams = []+ , falliedTeams = []+ }++-- * Allure-specific++factExplorerExterminator = factExplorer+ { ffreq = [(EXPLORER_EXTERMINATOR, 1)]+ , fhiCondPoly = hiHeroExterminator+ }++hiHeroExterminator :: HiCondPoly+hiHeroExterminator =+ hiHeroShort+ ++ [([(HiConst, 200)], [Conquer])] -- bonus for extermination over escape++-- ** teamRobot++factRobot = FactionKind+ { fname = "Robot Anarchy"+ , ffreq = [(ROBOT_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamRobot+ , fgroups = [ (ROBOT, 100), (MECHANICAL_CONTRAPTION, 100)+ , (MOBILE_ROBOT, 1), (IMMOBILE_ROBOT, 1)+ , (CONSTRUCTION_ROBOT, 1) ]+ , fskillsOther = zeroSkills+ , fcanEscape = False+ , fneverEmpty = False+ , fhiCondPoly = hiDweller+ , fhasGender = False+ , finitDoctrine = TRoam+ -- TODO:TFollow -- coordinated via net, follow alien leader+ , fspawnsFast = True+ , fhasPointman = False+ , fhasUI = False+ , finitUnderAI = True+ , fenemyTeams = [teamExplorer, teamCompetitor, teamCivilian, teamConvict]+ , falliedTeams = [teamMonster, teamAnimal]+ }+factRobotCaptive = factRobot+ { ffreq = [(ROBOT_CAPTIVE, 1)]+ , fneverEmpty = True+ }+factRobotNarrating = factRobot+ { ffreq = [(ROBOT_NARRATING, 1), (ANIMAL_OR_ROBOT_NARRATING, 30)]+ , fhasUI = True+ }+factRobotVirus = factRobot+ { fname = "Replicant Infestation"+ , ffreq = [(ROBOT_VIRUS, 1)]+ , fteam = teamOther -- not the same as other robots+ , fgroups = [(MOBILE_ROBOT, 100)] -- help assign proper actors to the faction+ , fneverEmpty = True -- faction dissolved when all killed, despite spawning+ , falliedTeams = [] -- cut off, weird+ }+factRobotGauntlet = factRobotVirus+ { ffreq = [(ROBOT_GAUNTLET, 1)]+ , fgroups = fgroups factRobotVirus ++ [(GAUNTLET_ROBOT, 1)]+ -- keep the faction description the same, despite different composition+ }++-- ** teamOffWorld++factOffWorld = factCompetitor+ { fname = "Gray Off-World Mercenary"+ , ffreq = [(OFF_WORLD_REPRESENTATIVE, 1), (REPRESENTATIVE, 1)]+ , fteam = teamOffWorld+ , fgroups = [(MERCENARY_HERO, 100)] -- summoned heroes all go to the player+ , fcanEscape = False+ , fhiCondPoly = hiHeroMedium+ , fenemyTeams = [teamExplorer, teamMonster, teamAnimal, teamRobot, teamHorror]+ , falliedTeams = []+ }
GameDefinition/Content/ItemKind.hs view
@@ -4,7 +4,7 @@ -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. ----- | Item definitions.+-- | Definitions of basic items. module Content.ItemKind ( -- * Group name patterns pattern HARPOON, pattern ARMOR_LOOSE, pattern CLOTHING_MISC@@ -18,12 +18,6 @@ import Game.LambdaHack.Core.Prelude -import Content.ItemKindActor-import Content.ItemKindBlast-import Content.ItemKindEmbed-import Content.ItemKindOrgan-import Content.ItemKindTemporary-import Content.RuleKind import Game.LambdaHack.Content.ItemKind import Game.LambdaHack.Content.RuleKind import Game.LambdaHack.Core.Dice@@ -33,6 +27,13 @@ import Game.LambdaHack.Definition.DefsInternal import Game.LambdaHack.Definition.Flavour +import Content.ItemKindActor+import Content.ItemKindBlast+import Content.ItemKindEmbed+import Content.ItemKindOrgan+import Content.ItemKindTemporary+import Content.RuleKind+ -- * Group name patterns groupNamesSingleton :: [GroupName ItemKind]@@ -40,7 +41,6 @@ [S_FRAGRANCE, S_SINGLE_SPARK, S_SPARK] ++ [FLASK_UNKNOWN, POTION_UNKNOWN, EDIBLE_PLANT_UNKNOWN, SCROLL_UNKNOWN, NECKLACE_UNKNOWN, RING_UNKNOWN, HAMMER_UNKNOWN, GEM_UNKNOWN, CURRENCY_UNKNOWN] ++ [S_RAG_TANGLE, S_GRASS_STITCHER, S_LADIES_FORK, S_SPADE, S_HOE]- ++ [COOKED_PLANT_UNKNOWN] ++ embedsGNSingleton ++ actorsGNSingleton ++ organsGNSingleton ++ blastsGNSingleton ++ temporariesGNSingleton @@ -48,8 +48,6 @@ pattern S_RAG_TANGLE, S_GRASS_STITCHER, S_LADIES_FORK, S_SPADE, S_HOE :: GroupName ItemKind -pattern COOKED_PLANT_UNKNOWN :: GroupName ItemKind- groupNames :: [GroupName ItemKind] groupNames = [CRAWL_ITEM, TREASURE, ANY_SCROLL, ANY_GLASS, ANY_POTION, ANY_FLASK, EXPLOSIVE, ANY_JEWELRY, VALUABLE, UNREPORTED_INVENTORY, AQUATIC]@@ -82,8 +80,6 @@ -- In the Content section, Allure-specific definitions are interspersed -- among generic definitions to make managing related definitions easier. -pattern COOKED_PLANT_UNKNOWN = GroupName "cooked plant unknown"- pattern COOKED_PLANT = GroupName "cooked plant" pattern LIQUID_NITROGEN = GroupName "liquid nitrogen" pattern GARDENING_TOOL = GroupName "gardening tool"@@ -336,7 +332,7 @@ harpoon = ItemKind { isymbol = symbolProjectile , iname = "harpoon"- , ifreq = [(COMMON_ITEM, 33), (HARPOON, 100), (S_HARPOON_CARGO, 1)]+ , ifreq = [(COMMON_ITEM, 40), (HARPOON, 100), (S_HARPOON_CARGO, 1)] , iflavour = zipPlain [Brown] , icount = 1 -- durable, so one piece lasts long , irarity = [(1, 17)]@@ -354,7 +350,7 @@ harpoon2 = harpoon { iname = "sharp harpoon" , ifreq = [(COMMON_ITEM, 1), (HARPOON, 2), (S_HARPOON_SHARP, 1)]- , irarity = [(10, 5)]+ , irarity = [(10, 6)] , idamage = 8 `d` 1 , idesc = "A cord ending in a sharpened cargo-hook that, in addition to entangling the victim, gains purchase biting into the body." }@@ -362,12 +358,12 @@ { iname = "The Whaling Harpoon" , ifreq = [(TREASURE, 15), (MUSEAL, 50)] , iflavour = zipFancy [Red]- , irarity = [(8, 4)]- , idamage = 7 `d` 1- , iaspects = SetFlag Unique : iaspects harpoon+ , irarity = [(8, 5)]+ , idamage = 21 `d` 1+ , iaspects = SetFlag Unique : delete (SetFlag Durable) (iaspects harpoon) , ieffects = Yell -- evoke a cry from pain; brutal : ieffects harpoon- , idesc = "A display piece harking back to the Earth's oceanic tourism heyday. Surprising sharp for its age. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the rope sends the victim flying."+ , idesc = "A display piece harking back to the Earth's oceanic tourism heyday. The age has made the edge thinner and sharper, but brittle and splintering, so it won't last beyond a single hit. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the rope sends the victim flying." } net = ItemKind { isymbol = symbolProjectile@@ -478,7 +474,8 @@ , irarity = [(1, 8)] , iverbHit = "bang" , iweight = 250- , iaspects = [SetFlag Lobable, SetFlag Fragile, toVelocity 60]+ , iaspects = SetFlag MetaGame -- weight gives it away after seen once+ : iaspects flaskTemplate , idesc = "The only redeeming quality of empty flasks is that they can be filled with any liquid." } flaskTemplate = ItemKind@@ -699,9 +696,8 @@ , ifreq = [(CRAWL_ITEM, 100), (ANY_GLASS, 50)] , icount = 1 , irarity = [(5, 6), (10, 2)]- , iaspects = [ SetFlag Unique, ELabel "of Attraction"- , SetFlag Precious, SetFlag Lobable, SetFlag Fragile- , toVelocity 50 ] -- identified+ , iaspects = [SetFlag Unique, ELabel "of Attraction", SetFlag MetaGame]+ ++ iaspects potionTemplate , ieffects = [ Dominate , toOrganGood S_HASTED (20 + 1 `d` 5) , Recharge 20 999@@ -768,9 +764,8 @@ , ifreq = [(CRAWL_ITEM, 100), (ANY_GLASS, 50)] , icount = 1 , irarity = [(10, 5)]- , iaspects = [ SetFlag Unique, ELabel "of Love"- , SetFlag Precious, SetFlag Lobable, SetFlag Fragile- , toVelocity 50 ] -- identified+ , iaspects = [SetFlag Unique, ELabel "of Love", SetFlag MetaGame]+ ++ iaspects potionTemplate , ieffects = [ RefillHP 60, RefillCalm (-60) , toOrganGood S_ROSE_SMELLING (80 + 1 `d` 20) , OnSmash (Explode S_HEALING_MIST_2)@@ -1113,13 +1108,12 @@ , idamage = 1 `d` 1 , ieffects = [DropItem maxBound 1 COrgan S_HUNGRY] }-cookedPlantTemplate = ediblePlantTemplate+cookedPlantTemplate = ediblePlantTemplate -- not secret { iname = "cooked plant"- , ifreq = [(COOKED_PLANT_UNKNOWN, 1)]+ , ifreq = [] , iflavour = zipPlain stdCol , irarity = [(1, 1)]- , iaspects = [ PresentAs COOKED_PLANT_UNKNOWN- , toVelocity 20 ] -- low density, often falling apart+ , iaspects = [toVelocity 30] -- low density, often falling apart , idesc = "Withered but fragrant bits of a colorful plant. Taste blandly, but break down easily, releasing all nutrients. Only eating may reveal the full effects." } cookedPlant1 = cookedPlantTemplate@@ -1202,7 +1196,7 @@ , (FIRE_SOURCE, 1), (S_WOODEN_TORCH, 1) ] , iflavour = zipPlain [Brown] , icount = 1- , irarity = [(3 * 10/15, 15), (4 * 10/15, 1)]+ , irarity = [(3 * 10/16, 15), (4 * 10/16, 1)] -- crafted, so rare; later taken from aliens , iverbHit = "scorch" , iweight = 1000@@ -1443,7 +1437,7 @@ necklace1 = necklaceTemplate { iname = "the Necklace" , ifreq = [(CRAWL_ITEM, 50), (ANY_JEWELRY, 25)]- , irarity = [(3 * 10/15, 0), (4 * 10/15, 1), (10, 5)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 1), (10, 5)] -- prevents camping on lvl 3 , iaspects = [ SetFlag Unique, ELabel "of Spur Life" , Timeout $ (4 - 1 `dL` 3) * 10@@ -1788,14 +1782,14 @@ , SetFlag Durable, SetFlag Equipable , EqpSlot EqpSlotArmorMelee ] , ieffects = []- , idesc = "A heavy spacesuit, with micro-suction machinery build into its boots, but requiring an external air tank for space walking. It heavily restrict arm movement, but not walking, regardless of gravity or lack thereof."+ , idesc = "A heavy spacesuit, with micro-suction machinery build into its boots, but requiring an external air tank for space walking. It heavily restricts arm movement, but not stride, regardless of gravity or lack thereof." , ikit = [] } spacesuitTorn = spacesuit { iname = "torn spacesuit" , ifreq = [(CRAWL_ITEM, 100), (S_SPACESUIT_TORN, 1)] , icount = 1 `d` 3- , irarity = [(1, 17), (8 * 10/15, 10)]+ , irarity = [(1, 17), (8 * 10/16, 10)] , iverbHit = "entangle" , iweight = 10000 , iaspects = [ AddSkill SkHurtMelee (-30)@@ -1810,7 +1804,7 @@ gloveFencing = ItemKind { isymbol = symbolMiscArmor , iname = "construction glove"- , ifreq = [ (COMMON_ITEM, 100), (ARMOR_MISC, 1), (ARMOR_RANGED, 1)+ , ifreq = [ (COMMON_ITEM, 100), (ARMOR_MISC, 1), (ARMOR_RANGED, 2) , (STARTING_ARMOR, 50) ] , iflavour = zipPlain [BrGreen] , icount = 1@@ -1832,7 +1826,7 @@ , ifreq = [ (COMMON_ITEM, 100), (S_SPACESUIT_GLOVE, 1) , (SPACESUIT_PART, 2), (ARMOR_MISC, 1), (STARTING_ARMOR, 50) ] , iflavour = zipFancy [White]- , irarity = [(1, 10), (5 * 10/15, 10), (6 * 10/15, 1)]+ , irarity = [(1, 10), (5 * 10/16, 10), (6 * 10/16, 1)] , iverbHit = "mow" , iweight = 500 , idamage = 3 `d` 1@@ -1869,7 +1863,7 @@ , (STARTING_ARMOR, 50) ] , iflavour = zipPlain [Brown] , icount = 1- , irarity = [(3, 7), (10, 4)]+ , irarity = [(3, 9), (10, 4)] , iverbHit = "tickle" , iweight = 500 , idamage = 0@@ -1910,7 +1904,7 @@ , (STARTING_ARMOR, 50) ] , iflavour = zipFancy [BrBlue] , icount = 1- , irarity = [(1, 11), (4 * 10/15, 11), (5 * 10/15, 1)]+ , irarity = [(1, 11), (4 * 10/16, 11), (5 * 10/16, 1)] , iverbHit = "headbutt" , iweight = 2000 , idamage = 4 `d` 1@@ -1934,7 +1928,7 @@ -- no STARTING_ARMOR, because the malus tricky for newbies , iflavour = zipFancy [Magenta] , icount = 1- , irarity = [(1, 12), (3 * 10/15, 12), (4 * 10/15, 1)]+ , irarity = [(1, 12), (3 * 10/16, 12), (4 * 10/16, 1)] , iverbHit = "sock" , iweight = 100000 -- including the fake gravity mass , idamage = 6 `d` 1@@ -2007,7 +2001,7 @@ -- and so attacking with buckler too early (OnUser (Recharge 4 20)) ] -- this is useful during a fight- , idesc = "An arm protection made from an outer airlock panel. Not too small to deflect projectiles occasionally. Almost harmless when used offensively, but makes room for other weapons."+ , idesc = "An arm protection made from an outer airlock panel. Not too small to deflect projectiles occasionally. Almost harmless when used offensively, but can fend foes off to make room for other weapons." , ikit = [] } -- In melee, the shield's biggest power is pushing enemies,@@ -2018,6 +2012,7 @@ -- as weapons either. This is OK, using shields smartly is totally beyond AI. shield = buckler { iname = "shield"+ , ifreq = [(COMMON_ITEM, 85), (ARMOR_LOOSE, 1)] , irarity = [(7, 5)] -- the stronger variants add to total probability , iflavour = zipPlain [Green] , iweight = 4000@@ -2125,7 +2120,7 @@ , iflavour = zipPlain [BrCyan] , icount = 1 , iweight = 1000- , irarity = [(1, 5), (3 * 10/15, 5), (4 * 10/15, 1)]+ , irarity = [(1, 5), (3 * 10/16, 5), (4 * 10/16, 1)] , iverbHit = "gouge" , idamage = 2 `d` 1 , iaspects = [ Timeout $ 2 + 1 `d` 3@@ -2146,7 +2141,7 @@ , iflavour = zipPlain [Cyan] , icount = 1 , iweight = 500- , irarity = [(1, 12), (3 * 10/15, 12), (4 * 10/15, 1)]+ , irarity = [(1, 12), (3 * 10/16, 12), (4 * 10/16, 1)] , iverbHit = "paw" , idamage = 1 `d` 1 , iaspects = [ Timeout $ 1 + 1 `d` 2@@ -2272,13 +2267,12 @@ { iname = "The Grand Smithhammer" , ifreq = [(TREASURE, 40), (BONDING_TOOL, 1), (MUSEAL, 100)] , irarity = [(5, 1), (8, 6)]- , iweight = 5000 -- weight and shape/damage gives it away; always identified+ , iweight = 5000 , iaspects = [ SetFlag Unique+ , SetFlag MetaGame -- weight and shape/damage gives it away , Timeout 8 -- 1.5m handle and heavy, but unique- , AddSkill SkHurtMelee $ (-20 + 1 `dL` 10) * 5 -- 50--95- , EqpSlot EqpSlotWeaponBig- , SetFlag Durable, SetFlag Meleeable- , toVelocity 0 ] -- totally unbalanced+ , AddSkill SkHurtMelee $ (-20 + 1 `dL` 10) * 5 ] -- 50--95+ ++ iaspects hammerTemplate , ieffects = [ Explode S_SPARK -- we can't use a focused explosion, because it would harm -- the hammer wielder as well, unlike this one; it's already@@ -2613,7 +2607,7 @@ { iname = "window cleaning pole" , ifreq = [(COMMON_ITEM, 100), (POLE_AND_STEEL, 1)] , iflavour = zipPlain [Blue]- , irarity = [(10, 6)] -- last chance of a long pole+ , irarity = [(10, 7)] -- last chance of a long pole , iweight = 3500 , idamage = 2 `d` 1 , iaspects = [ AddSkill SkArmorMelee 10 -- not sharp, so weaker
GameDefinition/Content/ItemKindActor.hs view
@@ -8,9 +8,9 @@ module Content.ItemKindActor ( -- * Group name patterns pattern S_WOODEN_TORCH, pattern S_SANDSTONE_ROCK- , pattern HERO, pattern SCOUT_HERO, pattern RANGER_HERO, pattern ESCAPIST_HERO, pattern AMBUSHER_HERO, pattern BRAWLER_HERO, pattern SOLDIER_HERO, pattern CIVILIAN, pattern MONSTER, pattern MOBILE_MONSTER, pattern SCOUT_MONSTER, pattern ANIMAL, pattern MOBILE_ANIMAL, pattern IMMOBILE_ANIMAL+ , pattern HERO, pattern SCOUT_HERO, pattern RANGER_HERO, pattern ESCAPIST_HERO, pattern AMBUSHER_HERO, pattern BRAWLER_HERO, pattern SOLDIER_HERO, pattern CIVILIAN, pattern MONSTER, pattern MOBILE_MONSTER, pattern SCOUT_MONSTER, pattern ANIMAL, pattern MOBILE_ANIMAL, pattern IMMOBILE_ANIMAL, pattern INSECT , pattern ADD_SIGHT, pattern ARMOR_RANGED, pattern ADD_NOCTO_1, pattern WEAK_ARROW, pattern LIGHT_ATTENUATOR, pattern FIREPROOF_CLOTH, pattern RING_OF_OPPORTUNITY_SNIPER, pattern ANY_ARROW, pattern STARTING_ARMOR, pattern STARTING_WEAPON, pattern GEM- , pattern CRAWL_HERO, pattern MERCENARY_HERO, pattern AQUATIC_ANIMAL, pattern AQUATIC_MONSTER, pattern EXPLOSIVE_MONSTER, pattern ROBOT, pattern MOBILE_ROBOT, pattern IMMOBILE_ROBOT, pattern CONSTRUCTION_ROBOT+ , pattern CRAWL_HERO, pattern EXTERMINATOR_HERO, pattern RAIDER_HERO, pattern MERCENARY_HERO, pattern AQUATIC_ANIMAL, pattern AQUATIC_MONSTER, pattern EXPLOSIVE_MONSTER, pattern ROBOT, pattern MOBILE_ROBOT, pattern IMMOBILE_ROBOT, pattern CONSTRUCTION_ROBOT, pattern MECHANICAL_CONTRAPTION, pattern GAUNTLET_ROBOT , pattern S_BULLTEPROOF_VEST, pattern S_PERFUME_POTION, pattern S_EMPTY_FLASK , pattern COOKED_FOOD, pattern MERCENARY_WEAPON, pattern MERCENARY_AMMO, pattern RAW_MEAT_CHUNK, pattern ROASTED_MEAT_CHUNK, pattern NEEDLE, pattern CAN_OF_STICKY_FOAM, pattern TRANQUILIZER_DART, pattern WASTE_CONTAINER, pattern CONSTRUCTION_HOOTER, pattern SPOTLIGHT, pattern BLOWTORCH, pattern POLE, pattern POLE_OR_HANDLE, pattern BREACHING_TOOL, pattern BONDING_TOOL, pattern SHARPENING_TOOL, pattern WIRECUTTING_TOOL , actorsGN, actorsGNSingleton@@ -22,7 +22,6 @@ import Game.LambdaHack.Core.Prelude -import Content.ItemKindOrgan import Game.LambdaHack.Content.ItemKind import Game.LambdaHack.Definition.Ability import Game.LambdaHack.Definition.Color@@ -30,6 +29,8 @@ import Game.LambdaHack.Definition.DefsInternal import Game.LambdaHack.Definition.Flavour +import Content.ItemKindOrgan+ -- * Group name patterns actorsGNSingleton :: [GroupName ItemKind]@@ -40,45 +41,50 @@ actorsGN :: [GroupName ItemKind] actorsGN =- [HERO, SCOUT_HERO, RANGER_HERO, ESCAPIST_HERO, AMBUSHER_HERO, BRAWLER_HERO, SOLDIER_HERO, CIVILIAN, MONSTER, MOBILE_MONSTER, SCOUT_MONSTER, ANIMAL, MOBILE_ANIMAL, IMMOBILE_ANIMAL]+ [HERO, SCOUT_HERO, RANGER_HERO, ESCAPIST_HERO, AMBUSHER_HERO, BRAWLER_HERO, SOLDIER_HERO, CIVILIAN, MONSTER, MOBILE_MONSTER, SCOUT_MONSTER, ANIMAL, MOBILE_ANIMAL, IMMOBILE_ANIMAL, INSECT] ++ [ADD_SIGHT, ARMOR_RANGED, ADD_NOCTO_1, WEAK_ARROW, LIGHT_ATTENUATOR, FIREPROOF_CLOTH, RING_OF_OPPORTUNITY_SNIPER, ANY_ARROW, STARTING_ARMOR, STARTING_WEAPON, GEM]- ++ [CRAWL_HERO, MERCENARY_HERO, AQUATIC_ANIMAL, AQUATIC_MONSTER, EXPLOSIVE_MONSTER, ROBOT, MOBILE_ROBOT, IMMOBILE_ROBOT, CONSTRUCTION_ROBOT]+ ++ [CRAWL_HERO, EXTERMINATOR_HERO, RAIDER_HERO, MERCENARY_HERO, AQUATIC_ANIMAL, AQUATIC_MONSTER, EXPLOSIVE_MONSTER, ROBOT, MOBILE_ROBOT, IMMOBILE_ROBOT, CONSTRUCTION_ROBOT, MECHANICAL_CONTRAPTION, GAUNTLET_ROBOT] ++ [COOKED_FOOD, MERCENARY_WEAPON, MERCENARY_AMMO, RAW_MEAT_CHUNK, ROASTED_MEAT_CHUNK, NEEDLE, CAN_OF_STICKY_FOAM, TRANQUILIZER_DART, WASTE_CONTAINER, CONSTRUCTION_HOOTER, SPOTLIGHT, BLOWTORCH, POLE, POLE_OR_HANDLE, BREACHING_TOOL, BONDING_TOOL, SHARPENING_TOOL, WIRECUTTING_TOOL] -pattern HERO, SCOUT_HERO, RANGER_HERO, ESCAPIST_HERO, AMBUSHER_HERO, BRAWLER_HERO, SOLDIER_HERO, CIVILIAN, MONSTER, MOBILE_MONSTER, SCOUT_MONSTER, ANIMAL, MOBILE_ANIMAL, IMMOBILE_ANIMAL :: GroupName ItemKind+pattern HERO, SCOUT_HERO, RANGER_HERO, ESCAPIST_HERO, AMBUSHER_HERO, BRAWLER_HERO, SOLDIER_HERO, CIVILIAN, MONSTER, MOBILE_MONSTER, SCOUT_MONSTER, ANIMAL, MOBILE_ANIMAL, IMMOBILE_ANIMAL, INSECT :: GroupName ItemKind pattern ADD_SIGHT, ARMOR_RANGED, ADD_NOCTO_1, WEAK_ARROW, LIGHT_ATTENUATOR, FIREPROOF_CLOTH, RING_OF_OPPORTUNITY_SNIPER, ANY_ARROW, STARTING_ARMOR, STARTING_WEAPON, GEM :: GroupName ItemKind -pattern CRAWL_HERO, MERCENARY_HERO, AQUATIC_ANIMAL, AQUATIC_MONSTER, EXPLOSIVE_MONSTER, ROBOT, MOBILE_ROBOT, IMMOBILE_ROBOT, CONSTRUCTION_ROBOT :: GroupName ItemKind+pattern CRAWL_HERO, EXTERMINATOR_HERO, RAIDER_HERO, MERCENARY_HERO, AQUATIC_ANIMAL, AQUATIC_MONSTER, EXPLOSIVE_MONSTER, ROBOT, MOBILE_ROBOT, IMMOBILE_ROBOT, CONSTRUCTION_ROBOT, MECHANICAL_CONTRAPTION, GAUNTLET_ROBOT :: GroupName ItemKind pattern COOKED_FOOD, MERCENARY_WEAPON, MERCENARY_AMMO, RAW_MEAT_CHUNK, ROASTED_MEAT_CHUNK, NEEDLE, CAN_OF_STICKY_FOAM, TRANQUILIZER_DART, WASTE_CONTAINER, CONSTRUCTION_HOOTER, SPOTLIGHT, BLOWTORCH, POLE, POLE_OR_HANDLE, BREACHING_TOOL, BONDING_TOOL, SHARPENING_TOOL, WIRECUTTING_TOOL :: GroupName ItemKind -- ** Common-pattern HERO = GroupName "hero"-pattern SCOUT_HERO = GroupName "scout hero"-pattern RANGER_HERO = GroupName "ranger hero"-pattern ESCAPIST_HERO = GroupName "escapist hero"-pattern AMBUSHER_HERO = GroupName "ambusher hero"-pattern BRAWLER_HERO = GroupName "brawler hero"-pattern SOLDIER_HERO = GroupName "fighter hero"+pattern HERO = GroupName "adventurer"+pattern SCOUT_HERO = GroupName "scout"+pattern RANGER_HERO = GroupName "ranger"+pattern ESCAPIST_HERO = GroupName "escapist"+pattern AMBUSHER_HERO = GroupName "ambusher"+pattern BRAWLER_HERO = GroupName "brawler"+pattern SOLDIER_HERO = GroupName "fighter" pattern CIVILIAN = GroupName "civilian"-pattern MONSTER = GroupName "monster"-pattern MOBILE_MONSTER = GroupName "mobile monster"-pattern SCOUT_MONSTER = GroupName "scout monster"+pattern MONSTER = GroupName "monstrosity"+pattern MOBILE_MONSTER = GroupName "mobile monstrosity"+pattern SCOUT_MONSTER = GroupName "scout monstrosity" pattern ANIMAL = GroupName "animal" pattern MOBILE_ANIMAL = GroupName "mobile animal" pattern IMMOBILE_ANIMAL = GroupName "immobile animal"+pattern INSECT = GroupName "insect" -- ** Allure-specific-pattern CRAWL_HERO = GroupName "crawl hero"-pattern MERCENARY_HERO = GroupName "mercenary hero"+pattern CRAWL_HERO = GroupName "crawl professional"+pattern EXTERMINATOR_HERO = GroupName "exterminator"+pattern RAIDER_HERO = GroupName "raider"+pattern MERCENARY_HERO = GroupName "mercenary" pattern AQUATIC_ANIMAL = GroupName "aquatic animal"-pattern AQUATIC_MONSTER = GroupName "aquatic monster"-pattern EXPLOSIVE_MONSTER = GroupName "explosive monster"+pattern AQUATIC_MONSTER = GroupName "aquatic monstrosity"+pattern EXPLOSIVE_MONSTER = GroupName "explosive monstrosity" pattern ROBOT = GroupName "robot" pattern MOBILE_ROBOT = GroupName "mobile robot" pattern IMMOBILE_ROBOT = GroupName "immobile robot" pattern CONSTRUCTION_ROBOT = GroupName "construction robot"+pattern MECHANICAL_CONTRAPTION = GroupName "mechanical contraption"+pattern GAUNTLET_ROBOT = GroupName "virus-infested robot" -- ** Common pattern S_WOODEN_TORCH = GroupName "wooden torch"@@ -124,9 +130,9 @@ actors :: [ItemKind] actors =- [warrior, warrior2, scout, ranger, escapist, ambusher, brawler, fighter, mercenary, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, elbowTank, intruder, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, hyena, komodoDragon, alligator, giantOctopus, lion, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, coolingFaucet, medbotFaucet, dustFaucet, fuelFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, weldedRobot, cleanerRobot]+ [warrior, warrior2, exterminator, raider, scout, ranger, escapist, ambusher, brawler, fighter, mercenary, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, elbowTank, intruder, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, hyena, komodoDragon, alligator, giantOctopus, lion, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, coolingFaucet, medbotFaucet, dustFaucet, fuelFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, wasteRobotNoEqp, lightRobot, heavyRobot, weldedRobot, cleanerRobot] -warrior, warrior2, scout, ranger, escapist, ambusher, brawler, fighter, mercenary, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, elbowTank, intruder, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, hyena, komodoDragon, alligator, giantOctopus, lion, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, coolingFaucet, medbotFaucet, dustFaucet, fuelFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, weldedRobot, cleanerRobot :: ItemKind+warrior, warrior2, exterminator, raider, scout, ranger, escapist, ambusher, brawler, fighter, mercenary, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, elbowTank, intruder, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, hyena, komodoDragon, alligator, giantOctopus, lion, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, coolingFaucet, medbotFaucet, dustFaucet, fuelFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, wasteRobotNoEqp, lightRobot, heavyRobot, weldedRobot, cleanerRobot :: ItemKind -- Note that the actors that appear in the crawl scenario should -- be generated with at most ordinary ammo. Otherwise, farming them@@ -136,9 +142,10 @@ -- * Hunams +-- TODO: bring back S_EAR_3 when character progression permits hearing boosts. humanOrgans :: [(GroupName ItemKind, CStore)] humanOrgans = [ (S_FIST, COrgan), (S_FOOT, COrgan)- , (S_EYE_6, COrgan), (S_EAR_3, COrgan)+ , (S_EYE_6, COrgan), (S_EAR_6, COrgan) , (S_SAPIENT_BRAIN, COrgan) , (S_ANIMAL_STOMACH, COrgan), (S_HUNGRY, COrgan) , (BACKSTORY, COrgan) ]@@ -169,20 +176,37 @@ , AddSkill SkOdor 1 , SetFlag Durable ] , ieffects = []- , idesc = "A human equipped for an adventure." , ikit = humanOrgans ++ [ (GENETIC_FLAW_10, COrgan)- , (S_EMPTY_FLASK, CStash), (COMMON_ITEM, CStash) ]+ , (S_EMPTY_FLASK, CStash)+ , (COMMON_ITEM, CStash) ]+ , idesc = "A human equipped for an adventure." } warrior2 = warrior { ifreq = [(CRAWL_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans ++ [ (GENETIC_FLAW_10, COrgan)- , (S_EMPTY_FLASK, CStash), (COOKED_FOOD, CStash) ]+ , (S_EMPTY_FLASK, CStash)+ , (COOKED_FOOD, CStash) ] }+exterminator = warrior+ { ifreq = [(EXTERMINATOR_HERO, 100), (MOBILE, 1)]+ , ikit = humanOrgans+ ++ [ (GENETIC_FLAW_10, COrgan)+ , (STARTING_WEAPON, CEqp)+ , (ARMOR_RANGED, CEqp) ]+ , idesc = "A human self-defending with makeshift equipment."+ }+raider = warrior+ { ifreq = [(RAIDER_HERO, 100), (MOBILE, 1)]+ , ikit = humanOrgans+ ++ [ (GENETIC_FLAW_10, COrgan)+ , (ARMOR_RANGED, CEqp)+ , (WEAK_ARROW, CStash) ]+ , idesc = "A human equipped for a raid."+ } scout = warrior- { iname = "scout"- , ifreq = [(SCOUT_HERO, 100), (MOBILE, 1)]+ { ifreq = [(SCOUT_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- no flaw ++ [ (ADD_SIGHT, CEqp) , (ARMOR_RANGED, CEqp)@@ -190,16 +214,14 @@ , idesc = "A human equipped for scouting." } ranger = warrior- { iname = "ranger"- , ifreq = [(RANGER_HERO, 100), (MOBILE, 1)]+ { ifreq = [(RANGER_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- no flaw ++ [ (ARMOR_RANGED, CEqp) , (WEAK_ARROW, CStash) ] , idesc = "A human equipped for ranged fight." } escapist = warrior- { iname = "escapist"- , ifreq = [(ESCAPIST_HERO, 100), (MOBILE, 1)]+ { ifreq = [(ESCAPIST_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- no flaw ++ [ (ADD_SIGHT, CEqp) , (STARTING_ARMOR, CEqp)@@ -210,8 +232,7 @@ , idesc = "A human equipped for an escape." } ambusher = warrior- { iname = "ambusher"- , ifreq = [(AMBUSHER_HERO, 100), (MOBILE, 1)]+ { ifreq = [(AMBUSHER_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- dark and numerous, so more kit without exploring ++ [ (RING_OF_OPPORTUNITY_SNIPER, CEqp) , (ANY_ARROW, CStash), (ANY_ARROW, CStash)@@ -222,21 +243,21 @@ , idesc = "A human equipped for an ambush." } brawler = warrior- { iname = "brawler"- , ifreq = [(BRAWLER_HERO, 100), (MOBILE, 1)]+ { ifreq = [(BRAWLER_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- no flaw- ++ [(STARTING_WEAPON, CEqp)]+ ++ [ (STARTING_WEAPON, CEqp)+ , (ANY_POTION, CStash) ] , idesc = "A human equipped for melee fight." } fighter = brawler- { iname = "fighter"- , ifreq = [(SOLDIER_HERO, 100), (MOBILE, 1)]+ { ifreq = [(SOLDIER_HERO, 100), (MOBILE, 1)] , ikit = ikit brawler- ++ [(STARTING_WEAPON, CEqp), (EXPLOSIVE, CStash)]+ ++ [ (STARTING_WEAPON, CEqp)+ , (EXPLOSIVE, CStash) ] , idesc = "A human equipped for intense combat." } mercenary = brawler- { iname = "mercenary"+ { iname = "mercenary" -- different name, because a very distinct faction , ifreq = [(MERCENARY_HERO, 100), (MOBILE, 1)] , ikit = humanOrgans -- no flaw ++ [ (MERCENARY_WEAPON, CEqp)@@ -280,7 +301,7 @@ , (MOBILE_MONSTER, 100), (SCOUT_MONSTER, 10) ] , iflavour = zipFancy [BrRed] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 10), (10, 8)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 10), (10, 8)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -303,7 +324,7 @@ , (MOBILE_MONSTER, 100), (SCOUT_MONSTER, 60) ] , iflavour = zipFancy [BrBlue] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 3), (10, 12)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 3), (10, 12)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -329,7 +350,7 @@ , (AQUATIC, 30), (AQUATIC_MONSTER, 30) ] -- likes liquids , iflavour = zipFancy [BrGreen] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 5), (10, 9)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 5), (10, 9)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -353,7 +374,7 @@ , (MOBILE_MONSTER, 100), (SCOUT_MONSTER, 30) ] , iflavour = zipFancy [BrMagenta] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 1), (10, 12)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 1), (10, 12)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -394,7 +415,7 @@ , (AQUATIC, 1) ] -- neutral to water, unlike other actors , iflavour = zipFancy [BrCyan] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 5), (10, 9)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 5), (10, 9)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -424,7 +445,7 @@ , ifreq = [(MONSTER, 100), (MOBILE, 1)] , iflavour = zipFancy [BrCyan] , icount = 1- , irarity = [(14 * 10/15, 0), (15 * 10/15, 1000)] -- unique+ , irarity = [(14 * 10/16, 0), (15 * 10/16, 1000)] -- unique , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -543,7 +564,7 @@ , iverbHit = "thud" , iweight = 54000 , idamage = 0- , iaspects = [ AddSkill SkMaxHP 30, AddSkill SkMaxCalm 30+ , iaspects = [ AddSkill SkMaxHP 25, AddSkill SkMaxCalm 30 , AddSkill SkSpeed 20, AddSkill SkNocto 2 , AddSkill SkHurtMelee (-70) -- quite harmless rolled in a ball , AddSkill SkAlter (-2) -- can't use hard stairs nor doors@@ -691,11 +712,13 @@ , (AQUATIC, 90), (AQUATIC_ANIMAL, 90) ] -- weak on land , iflavour = zipPlain [BrMagenta] -- very exotic, so bright color , icount = 1- , irarity = [(1, 3), (7, 3)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 5), (7, 3)]+ -- weak, but non-standard behaviour, so spoils initial mastery;+ -- later on not too common, because annoying , iverbHit = "thud" , iweight = 72000 , idamage = 0- , iaspects = [ AddSkill SkMaxHP 17, AddSkill SkMaxCalm 80+ , iaspects = [ AddSkill SkMaxHP 20, AddSkill SkMaxCalm 80 , AddSkill SkSwimming 100 -- swims better than walks , AddSkill SkSpeed 27, AddSkill SkNocto 3 -- good night vision , AddSkill SkAlter (-2) -- can't use hard stairs nor doors@@ -746,7 +769,7 @@ , ifreq = [(ANIMAL, 100), (MOBILE, 1)] , iflavour = zipPlain [Brown] , icount = 1- , irarity = [(7 * 10/15, 0), (8 * 10/15, 1000), (9 * 10/15, 0)] -- unique+ , irarity = [(7 * 10/16, 0), (8 * 10/16, 1000), (9 * 10/16, 0)] -- unique , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -774,7 +797,7 @@ beeSwarm = ItemKind { isymbol = toContentSymbol 'b' , iname = "bee swarm"- , ifreq = [(ANIMAL, 100), (MOBILE, 1)]+ , ifreq = [(ANIMAL, 100), (INSECT, 50), (MOBILE, 1)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1, 3), (10, 4)]@@ -796,7 +819,7 @@ hornetSwarm = ItemKind -- kind of tank with armor, but short-lived { isymbol = toContentSymbol 'h' , iname = "hornet swarm"- , ifreq = [(ANIMAL, 100), (MOBILE, 1), (MOBILE_ANIMAL, 100)]+ , ifreq = [(ANIMAL, 100), (INSECT, 100), (MOBILE, 1), (MOBILE_ANIMAL, 100)] , iflavour = zipPlain [Magenta] , icount = 1 , irarity = [(5, 1), (10, 4), (20, 10)]@@ -846,10 +869,10 @@ razorwireFence = ItemKind { isymbol = toContentSymbol 'f' , iname = "razorwire fence"- , ifreq = [(ROBOT, 15), (IMMOBILE_ROBOT, 10)]+ , ifreq = [(ROBOT, 15), (IMMOBILE_ROBOT, 10), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [Cyan] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 20), (10, 4)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 20), (10, 4)] , iverbHit = "scrape" , iweight = 80000 , idamage = 0@@ -865,10 +888,10 @@ electricFence = ItemKind { isymbol = toContentSymbol 'f' , iname = "electric fence"- , ifreq = [(ROBOT, 40), (IMMOBILE_ROBOT, 10)]+ , ifreq = [(ROBOT, 40), (IMMOBILE_ROBOT, 10), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [Blue] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 10), (10, 10), (20, 10)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 10), (10, 10), (20, 10)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -885,10 +908,10 @@ activeFence = ItemKind { isymbol = toContentSymbol 'f' , iname = "active fence"- , ifreq = [(ROBOT, 30), (IMMOBILE_ROBOT, 20)]+ , ifreq = [(ROBOT, 30), (IMMOBILE_ROBOT, 20), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [BrMagenta] , icount = 1- , irarity = [(5 * 10/15, 0), (10, 7), (20, 10)]+ , irarity = [(5 * 10/16, 0), (10, 7), (20, 10)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -909,7 +932,7 @@ steamFaucet = ItemKind { isymbol = toContentSymbol 'f' , iname = "steam faucet"- , ifreq = [(ROBOT, 8), (IMMOBILE_ROBOT, 15)]+ , ifreq = [(ROBOT, 8), (IMMOBILE_ROBOT, 15), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [BrGreen] , icount = 1 , irarity = [(1, 10), (10, 6)]@@ -927,7 +950,7 @@ coolingFaucet = ItemKind { isymbol = toContentSymbol 'f' , iname = "cooling faucet"- , ifreq = [(ROBOT, 8), (IMMOBILE_ROBOT, 15)]+ , ifreq = [(ROBOT, 8), (IMMOBILE_ROBOT, 15), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [BrBlue] , icount = 1 , irarity = [(1, 10), (10, 6)]@@ -945,7 +968,7 @@ medbotFaucet = ItemKind { isymbol = toContentSymbol 'f' , iname = "nano medbot faucet"- , ifreq = [(ROBOT, 10), (IMMOBILE_ROBOT, 100)]+ , ifreq = [(ROBOT, 10), (IMMOBILE_ROBOT, 100), (MECHANICAL_CONTRAPTION, 1)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(1, 10), (10, 6)]@@ -964,7 +987,8 @@ { isymbol = toContentSymbol 'f' , iname = "dust faucet" , ifreq = [ (ROBOT, 4) -- usually nothing to ignite- , (IMMOBILE_ROBOT, 30) ] -- except when other faucets around+ , (IMMOBILE_ROBOT, 30) -- except when other faucets around+ , (MECHANICAL_CONTRAPTION, 1) ] , iflavour = zipPlain [BrCyan] , icount = 1 , irarity = [(3, 20), (10, 6)]@@ -982,12 +1006,12 @@ fuelFaucet = ItemKind { isymbol = toContentSymbol 'f' , iname = "burning fuel faucet"- , ifreq = [(ROBOT, 30)]- -- common not in outermost level, but in the dungeon, because it's+ , ifreq = [(ROBOT, 30), (MECHANICAL_CONTRAPTION, 1)]+ -- common not in outermost level but in the dungeon, because it's -- self-contained, providing both fuel and ignition , iflavour = zipPlain [BrRed] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 6), (10, 12), (20, 10)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 6), (10, 12), (20, 10)] , iverbHit = "thud" , iweight = 80000 , idamage = 0@@ -1025,7 +1049,7 @@ { isymbol = toContentSymbol 'd' , iname = "oversight drone" , ifreq = [ (ROBOT, 100), (MOBILE, 100), (MOBILE_ROBOT, 100)- , (CONSTRUCTION_ROBOT, 100) ]+ , (CONSTRUCTION_ROBOT, 100), (GAUNTLET_ROBOT, 150) ] , iflavour = zipPlain [BrRed] , icount = 1 , irarity = [(1, 3), (10, 4)] -- gets summoned often, so low base rarity@@ -1073,7 +1097,8 @@ { isymbol = toContentSymbol 'r' , iname = "feral home robot" -- TODO: name another 'deranged', tertiary imperative: survival- , ifreq = [(ROBOT, 100), (MOBILE, 100), (MOBILE_ROBOT, 100)]+ , ifreq = [ (ROBOT, 100), (MOBILE, 100), (MOBILE_ROBOT, 100)+ , (GAUNTLET_ROBOT, 100) ] , iflavour = zipPlain [Magenta] , icount = 1 , irarity = [(1, 15), (10, 5)]@@ -1105,12 +1130,18 @@ , AddSkill SkSpeed 15, AddSkill SkNocto 2 , SetFlag Durable ] , ieffects = []- , idesc = "You are not in its database, hence you are waste. It can't see and you smell funny, so that must suffice."+ , idesc = "You are not in its database, hence you are waste. It can't see and you smell funny, so that's it." , ikit = [ (S_TENTACLE, COrgan), (S_SNOUT, COrgan) , (S_NOSTRIL, COrgan) -- only smell, for variety , (S_ROBOT_BRAIN, COrgan) , (WASTE_CONTAINER, CEqp) ] }+wasteRobotNoEqp = wasteRobot -- no drops, for gauntlet and to avoid junk+ { ifreq = [ (MOBILE, 100), (GAUNTLET_ROBOT, 250) ]+ , ikit = [ (S_TENTACLE, COrgan), (S_SNOUT, COrgan)+ , (S_NOSTRIL, COrgan) -- only smell, for variety+ , (S_ROBOT_BRAIN, COrgan) ]+ } lightRobot = ItemKind { isymbol = toContentSymbol 'r' , iname = "decoration robot"@@ -1118,7 +1149,7 @@ , (CONSTRUCTION_ROBOT, 100) ] , iflavour = zipPlain [BrYellow] , icount = 1- , irarity = [(3 * 10/15, 0), (4 * 10/15, 6), (10, 6)]+ , irarity = [(3 * 10/16, 0), (4 * 10/16, 6), (10, 6)] -- gets summoned often, so low rarity , iverbHit = "clank" , iweight = 80000@@ -1147,7 +1178,7 @@ , (CONSTRUCTION_ROBOT, 70) ] , iflavour = zipPlain [Cyan] , icount = 1- , irarity = [(7 * 10/15, 0), (8 * 10/15, 4), (10, 13), (30, 30)]+ , irarity = [(7 * 10/16, 0), (8 * 10/16, 4), (10, 13), (30, 30)] , iverbHit = "clank" , iweight = 800000 , idamage = 0@@ -1176,7 +1207,7 @@ , ifreq = [(ROBOT, 100), (IMMOBILE_ROBOT, 100)] , iflavour = zipPlain [BrCyan] , icount = 1- , irarity = [(1 * 10/15, 1000), (2 * 10/15, 0)] -- unique+ , irarity = [(1 * 10/16, 1000), (2 * 10/16, 0)] -- unique , iverbHit = "clank" , iweight = 80000 , idamage = 0@@ -1184,7 +1215,7 @@ , AddSkill SkMaxHP 200, AddSkill SkMaxCalm 100 , AddSkill SkSpeed 20, AddSkill SkNocto 2 , SetFlag Durable ]- , ieffects = [OnSmash $ VerbMsg "lament dying with disfigured and welded legs that nobody wanted to fix with the blowtorch" "."]+ , ieffects = [OnSmash $ VerbMsg "lament dying with disfigured and welded feet that nobody wanted to fix with the blowtorch" "."] , idesc = "A well-built humanoid luggage unloading robot with a smooth silvery satin skin. Its graceful moves are stunted by a thick irregular weld fastening both its shapely legs to the floor. A whiff of smoke escapes whenever it opens its mouth in a charming toothy smile while brandishing a blowtorch in its trembling hand. Blowtorch! That's the key to open the welded staircase." , ikit = [ (S_FIST, COrgan) , (S_EYE_6, COrgan), (S_EAR_3, COrgan)@@ -1202,7 +1233,7 @@ , ifreq = [(ROBOT, 100), (MOBILE, 1)] , iflavour = zipPlain [BrGreen] , icount = 1- , irarity = [(11 * 10/15, 0), (12 * 10/15, 1000), (13 * 10/15, 0)] -- unique+ , irarity = [(11 * 10/16, 0), (12 * 10/16, 1000), (13 * 10/16, 0)] -- unique , iverbHit = "clank" , iweight = 800000 , idamage = 0
GameDefinition/Content/ItemKindBlast.hs view
@@ -22,7 +22,6 @@ import Game.LambdaHack.Core.Prelude -import Content.ItemKindTemporary import Game.LambdaHack.Content.ItemKind import Game.LambdaHack.Core.Dice import Game.LambdaHack.Definition.Ability@@ -31,6 +30,8 @@ import Game.LambdaHack.Definition.DefsInternal import Game.LambdaHack.Definition.Flavour +import Content.ItemKindTemporary+ -- * Group name patterns blastsGNSingleton :: [GroupName ItemKind]@@ -580,7 +581,7 @@ , iname = "boiling water" , ifreq = [(S_BOILING_WATER, 1)] -- not enough water to create puddles , iflavour = zipPlain [White]- , icount = 18+ , icount = 17 -- 18 causes 3 particles to hit the same actor 3 tiles away , irarity = [(1, 1)] , iverbHit = "boil" , iweight = 1@@ -1028,7 +1029,7 @@ , iaspects = [ toVelocity 5 -- 1 step, 1 turn , SetFlag Fragile, SetFlag Blast ] , ieffects = [toOrganGood S_RESOLUTE (5 + 1 `d` 2), Discharge 1 50]- , idesc = "The fitful holographic clip shows a couple that laughs, watches in silence Saturn's rings through a huge window, throws treats to Billy the little rhino frolicking in reduced gravity, runs through corridors wearing alien masks in a mock chase. An exited female voice proclaims: \"...safety, security and comfort...for each of your senses...personalized life support zones...robot servants...guessing your every wish...\""+ , idesc = "The fitful holographic clip shows a couple that laughs, watches in silence Saturn's rings through a huge window, throws treats to Billy the little rhino frolicking in reduced gravity, runs through corridors wearing alien masks in a mock chase. An excited female voice proclaims: \"...safety, security and comfort...for each of your senses...personalized life support zones...robot servants...guessing your every wish...\"" , ikit = [] } outerAdHologram = cruiseAdHologram
GameDefinition/Content/ItemKindEmbed.hs view
@@ -20,10 +20,6 @@ import Game.LambdaHack.Core.Prelude -import Content.ItemKindActor-import Content.ItemKindBlast-import Content.ItemKindOrgan-import Content.ItemKindTemporary import Game.LambdaHack.Content.ItemKind import Game.LambdaHack.Core.Dice import Game.LambdaHack.Definition.Ability@@ -32,6 +28,11 @@ import Game.LambdaHack.Definition.DefsInternal import Game.LambdaHack.Definition.Flavour +import Content.ItemKindActor+import Content.ItemKindBlast+import Content.ItemKindOrgan+import Content.ItemKindTemporary+ -- * Group name patterns embedsGNSingleton :: [GroupName ItemKind]@@ -422,14 +423,14 @@ , idamage = 0 , iaspects = [ELabel "of steps", SetFlag Durable] , ieffects = [Ascend True]- , idesc = "Stairs that rise towards the spaceship core. It takes slightly more effort to climb than descend, but in lowered gravity it's almost instantaneous in either case."+ , idesc = "Emergency stairs that rise towards the spaceship core. It takes slightly more effort to climb than descend, but in lowered gravity it's almost instantaneous in either case." , ikit = [] } stairsDown = stairsUp { isymbol = toContentSymbol '>' , ifreq = [(STAIRS_DOWN, 1)] , ieffects = [Ascend False]- , idesc = "Stairs that descend towards the outer ring. Narrow enough that only one person can comfortably use them at a time, but short enough that the whole team may climb down in quick succession."+ , idesc = "Emergency stairs that descend towards the outer ring. Narrow enough that only one person can comfortably use them at a time, but short enough that the whole team may climb down in quick succession." } escape = stairsUp { isymbol = toContentSymbol '>'@@ -771,14 +772,14 @@ , iflavour = zipPlain [Blue] , ifreq = [(LIFT_UP, 1)] , iaspects = [SetFlag Durable]- , idesc = "" -- describe inner levels of the ship+ , idesc = "Surprisingly, this lift still functions, while others are wrecked." -- describe inner levels of the ship } liftDown = stairsDown { iname = "carriage" , iflavour = zipPlain [Blue] , ifreq = [(LIFT_DOWN, 1)] , iaspects = [SetFlag Durable]- , idesc = "" -- describe outer levels of the ship+ , idesc = "Surprisingly, this one shaft is still open, while others are ruined and blocked." -- describe outer levels of the ship } liftTrap = stairsTrapUp { iname = "elevator trap" -- hat tip to US heroes@@ -1081,6 +1082,7 @@ , ( [], [(1, S_STAFF), (1, STEEL_SCRAP)], [(1, S_SHORT_CLUB)] ) , ( [], [(1, POLE), (2, STEEL_SCRAP)], [(1, S_LONG_CLUB)] ) -- Perfect the perfection. Comes after the productive rules.+ -- Only include the most augmented items with random stats to re-roll. , ( [(1, BONDING_TOOL)], [(1, S_LONG_SHARP_HAMMER)] , [(1, S_LONG_SHARP_HAMMER)] ) , ( [(1, BONDING_TOOL)], [(1, S_POLL_AXE)], [(1, S_POLL_AXE)] )
GameDefinition/Content/ItemKindOrgan.hs view
@@ -20,9 +20,6 @@ import Game.LambdaHack.Core.Prelude -import Content.ItemKindBlast-import Content.ItemKindTemporary-import Content.RuleKind import Game.LambdaHack.Content.ItemKind import Game.LambdaHack.Content.RuleKind import Game.LambdaHack.Core.Dice@@ -32,6 +29,10 @@ import Game.LambdaHack.Definition.DefsInternal import Game.LambdaHack.Definition.Flavour +import Content.ItemKindBlast+import Content.ItemKindTemporary+import Content.RuleKind+ -- * Group name patterns organsGNSingleton :: [GroupName ItemKind]@@ -531,7 +532,8 @@ , ifreq = [(S_INSECT_MORTALITY, 1)] , iverbHit = "age" , iaspects = [ AddSkill SkAggression 2 -- try to attack before you die- , Timeout $ 30 + (1 `d` 3) * 10 -- die very slowly+ , Timeout $ 50 + (1 `d` 3) * 10 -- die even more slowly+ -- due to large levels , SetFlag Periodic, SetFlag Durable ] , ieffects = [RefillHP (-1), Yell] , idesc = ""@@ -633,7 +635,7 @@ bonusHP = armoredSkin { isymbol = toContentSymbol 'H' -- '+' reserved for conditions- , iname = "bonus HP"+ , iname = "extra HP" , ifreq = [(S_BONUS_HP, 1)] , iflavour = zipPlain [BrBlue] , iverbHit = "intimidate"@@ -868,16 +870,28 @@ , ifreq = [(S_MOUTH_VENT, 1)] , iflavour = zipPlain [BrMagenta] , iverbHit = "surprise"- , iaspects = [ Timeout 7+ , iaspects = [ Timeout 10 , SetFlag Periodic, SetFlag Durable ]- , ieffects = [OneOf $- map (AndEffect (Explode S_SMOKE) . uncurry VerbMsg)- [ ("say: Sir, your luggage has already been collected", ".")- , ("ask: Would you kindly help me?", "")- , ("complain: I can't reach you with this tool", "." ) ]- ++ map Explode- [ S_PHEROMONE, S_RHINO_HOLOGRAM, S_CURRENT_DISCHARGE- , blastNoStatOf S_IMMOBILE, S_SPARK ]]+ , ieffects =+ [ OneOf $+ map (uncurry VerbMsg)+ [ ("say: Sir, your luggage has already been delivered", ".")+ , ("say: Sir, please find your luggage on the bench by your airlock", ".")+ , ("say: To resume my service I need help with this implement", ".")+ , ("announce: There's been a locomotive malfunction in component 'foot'. Help is requested", ".")+ , ("announce: Deck blue, level four has been temporarily sealed for a routine inspection", ".")+ , ("announce: Lifts are temporarily nonoperational. Please use emergency staircases", ".")+ , ("ask: Would you kindly help me?", "")+ , ("ask: Could you please come closer?", "")+ , ("ask: Have you found your luggage, sir?", "")+ , ("ask: Have you found the lift to your destination?", "")+ , ("complain: I can't reach you with this essential tool", "." )+ , ("complain: I can't hand you this item from here", "." )+ , ("complain: I'm afraid, I can't do that", "." ) ]+ ++ [NopEffect, NopEffect, NopEffect, NopEffect]+ , OneOf $ map Explode+ [ S_PHEROMONE, S_RHINO_HOLOGRAM, S_CURRENT_DISCHARGE+ , blastNoStatOf S_IMMOBILE, S_SPARK, S_SMOKE ] ] , idesc = "" } dustVent = armoredSkin
GameDefinition/Content/ItemKindTemporary.hs view
@@ -153,12 +153,14 @@ [AddSkill SkArmorRanged 25] tmpDefenseless = tmpAspects S_DEFENSELESS [ AddSkill SkArmorMelee (-50) , AddSkill SkArmorRanged (-25) ]-tmpResolute = tmpAspects S_RESOLUTE [AddSkill SkMaxCalm 60]+tmpResolute = tmpAspects S_RESOLUTE [ AddSkill SkMaxCalm 60+ , AddSkill SkHearing 10 ] tmpFast20 = tmpAspects S_HASTED [AddSkill SkSpeed 20] tmpSlow10 = tmpAspects S_SLOWED [AddSkill SkSpeed (-10)] tmpFarSighted = tmpAspects S_FAR_SIGHTED [AddSkill SkSight 5] tmpBlind = tmpAspects S_BLIND [ AddSkill SkSight (-99)- , AddSkill SkArmorMelee (-30) ]+ , AddSkill SkArmorMelee (-30)+ , AddSkill SkHearing 10 ] tmpKeenSmelling = tmpAspects S_KEEN_SMELLING [AddSkill SkSmell 2] tmpFoulSmelling = tmpAspects S_FOUL_SMELLING [AddSkill SkOdor 2] tmpRoseSmelling = tmpAspects S_ROSE_SMELLING [AddSkill SkOdor (-4)]
GameDefinition/Content/ModeKind.hs view
@@ -4,15 +4,15 @@ -- 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.+-- | Definitions of game mode kinds. module Content.ModeKind- ( -- * Group names+ ( -- * Group name patterns groupNamesSingleton, groupNames , -- * Content content #ifdef EXPOSE_INTERNAL -- * Group name patterns- , pattern RAID, pattern BRAWL, pattern LONG, pattern CRAWL, pattern FOGGY, pattern SHOOTOUT, pattern PERILOUS, pattern HUNT, pattern NIGHT, pattern ESCAPE, pattern BURNING, pattern ZOO, pattern RANGED, pattern AMBUSH, pattern SAFARI, pattern DIG, pattern SEE, pattern SHORT, pattern CRAWL_EMPTY, pattern CRAWL_SURVIVAL, pattern SAFARI_SURVIVAL, pattern BATTLE, pattern BATTLE_DEFENSE, pattern BATTLE_SURVIVAL, pattern DEFENSE, pattern DEFENSE_EMPTY+ , pattern GAUNTLET, pattern RAID, pattern BRAWL, pattern LONG, pattern CRAWL, pattern FOGGY, pattern SHOOTOUT, pattern PERILOUS, pattern HUNT, pattern NIGHT, pattern FLIGHT, pattern BURNING, pattern ZOO, pattern RANGED, pattern AMBUSH, pattern SAFARI, pattern DIG, pattern SEE, pattern SHORT, pattern FUN, pattern CRAWL_EMPTY, pattern CRAWL_SURVIVAL, pattern SAFARI_SURVIVAL, pattern BATTLE, pattern BATTLE_DEFENSE, pattern BATTLE_SURVIVAL, pattern DEFENSE, pattern DEFENSE_EMPTY #endif ) where @@ -22,26 +22,29 @@ import qualified Data.Text as T -import Content.CaveKind hiding (content, groupNames, groupNamesSingleton)-import Content.ItemKindActor-import Content.ModeKindPlayer import Game.LambdaHack.Content.CaveKind (CaveKind, pattern DEFAULT_RANDOM)+import Game.LambdaHack.Content.FactionKind (Outcome (..)) import Game.LambdaHack.Content.ModeKind import Game.LambdaHack.Core.Dice import Game.LambdaHack.Definition.Defs import Game.LambdaHack.Definition.DefsInternal +import Content.CaveKind hiding (content, groupNames, groupNamesSingleton)+import Content.FactionKind hiding (content, groupNames, groupNamesSingleton)+import Content.ItemKindActor+ -- * Group name patterns groupNamesSingleton :: [GroupName ModeKind] groupNamesSingleton =- [RAID, BRAWL, LONG, CRAWL, FOGGY, SHOOTOUT, PERILOUS, HUNT, NIGHT, ESCAPE, BURNING, ZOO, RANGED, AMBUSH, SAFARI, DIG, SEE, SHORT, CRAWL_EMPTY, CRAWL_SURVIVAL, SAFARI_SURVIVAL, BATTLE, BATTLE_DEFENSE, BATTLE_SURVIVAL, DEFENSE, DEFENSE_EMPTY]+ [GAUNTLET, RAID, BRAWL, LONG, CRAWL, FOGGY, SHOOTOUT, PERILOUS, HUNT, NIGHT, FLIGHT, BURNING, ZOO, RANGED, AMBUSH, SAFARI, DIG, SEE, SHORT, FUN, CRAWL_EMPTY, CRAWL_SURVIVAL, SAFARI_SURVIVAL, BATTLE, BATTLE_DEFENSE, BATTLE_SURVIVAL, DEFENSE, DEFENSE_EMPTY] -pattern RAID, BRAWL, LONG, CRAWL, FOGGY, SHOOTOUT, PERILOUS, HUNT, NIGHT, ESCAPE, BURNING, ZOO, RANGED, AMBUSH, SAFARI, DIG, SEE, SHORT, CRAWL_EMPTY, CRAWL_SURVIVAL, SAFARI_SURVIVAL, BATTLE, BATTLE_DEFENSE, BATTLE_SURVIVAL, DEFENSE, DEFENSE_EMPTY :: GroupName ModeKind+pattern GAUNTLET, RAID, BRAWL, LONG, CRAWL, FOGGY, SHOOTOUT, PERILOUS, HUNT, NIGHT, FLIGHT, BURNING, ZOO, RANGED, AMBUSH, SAFARI, DIG, SEE, SHORT, FUN, CRAWL_EMPTY, CRAWL_SURVIVAL, SAFARI_SURVIVAL, BATTLE, BATTLE_DEFENSE, BATTLE_SURVIVAL, DEFENSE, DEFENSE_EMPTY :: GroupName ModeKind groupNames :: [GroupName ModeKind]-groupNames = [NO_CONFIRMS]+groupNames = [] +pattern GAUNTLET = GroupName "gauntlet" pattern RAID = GroupName "raid" pattern BRAWL = GroupName "brawl" pattern LONG = GroupName "long crawl"@@ -50,8 +53,8 @@ pattern SHOOTOUT = GroupName "shootout" pattern PERILOUS = GroupName "perilous hunt" pattern HUNT = GroupName "hunt"-pattern NIGHT = GroupName "night escape"-pattern ESCAPE = GroupName "escape"+pattern NIGHT = GroupName "night flight"+pattern FLIGHT = GroupName "flight" pattern BURNING = GroupName "burning zoo" pattern ZOO = GroupName "zoo" pattern RANGED = GroupName "ranged ambush"@@ -60,6 +63,7 @@ pattern DIG = GroupName "dig" pattern SEE = GroupName "see" pattern SHORT = GroupName "short"+pattern FUN = GroupName "fun" pattern CRAWL_EMPTY = GroupName "crawlEmpty" -- only the first word matters pattern CRAWL_SURVIVAL = GroupName "crawlSurvival" pattern SAFARI_SURVIVAL = GroupName "safariSurvival"@@ -73,9 +77,9 @@ content :: [ModeKind] content =- [raid, brawl, crawl, shootout, hunt, escape, zoo, ambush, safari, dig, see, short, crawlEmpty, crawlSurvival, safariSurvival, battle, battleDefense, battleSurvival, defense, defenseEmpty, screensaverRaid, screensaverBrawl, screensaverCrawl, screensaverShootout, screensaverHunt, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverSafari]+ [gauntlet, raid, brawl, crawl, shootout, hunt, flight, zoo, ambush, safari, dig, see, short, fun, crawlEmpty, crawlSurvival, safariSurvival, battle, battleDefense, battleSurvival, defense, defenseEmpty, screensaverGauntlet, screensaverRaid, screensaverBrawl, screensaverCrawl, screensaverShootout, screensaverHunt, screensaverFlight, screensaverZoo, screensaverAmbush, screensaverSafari] -raid, brawl, crawl, shootout, hunt, escape, zoo, ambush, safari, dig, see, short, crawlEmpty, crawlSurvival, safariSurvival, battle, battleDefense, battleSurvival, defense, defenseEmpty, screensaverRaid, screensaverBrawl, screensaverCrawl, screensaverShootout, screensaverHunt, screensaverEscape, screensaverZoo, screensaverAmbush, screensaverSafari :: ModeKind+gauntlet, raid, brawl, crawl, shootout, hunt, flight, zoo, ambush, safari, dig, see, short, fun, crawlEmpty, crawlSurvival, safariSurvival, battle, battleDefense, battleSurvival, defense, defenseEmpty, screensaverGauntlet, screensaverRaid, screensaverBrawl, screensaverCrawl, screensaverShootout, screensaverHunt, screensaverFlight, screensaverZoo, screensaverAmbush, 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@@ -90,32 +94,55 @@ -- crowd ranged: no, fish in a barrel, less predictable and more fun inside -- crawl, even without reaction fire +gauntlet = ModeKind+ { mname = "gauntlet (tutorial, 1)"+ , mfreq = [(GAUNTLET, 1), (CAMPAIGN_SCENARIO, 1)]+ , mtutorial = True+ , mattract = False+ , mroster = rosterGauntlet+ , mcaves = cavesGauntlet+ , mendMsg = [ (Killed, "That was unfortunate. Perhaps the growing wave of rogue robots indeed could not be stemmed. The bill for the nano medbot treatment will reach the stars once the checkout clock alerts authorities and a full drone city sweep (another bill) recovers your remains.\nBut was it really impossible to run a few dozen meters into the tunnel, side-stepping or displacing (Shift-direction) enemies, and trigger the red alarm console? Perhaps one person could distract the replicants, while another searched for a passage around them? Or was the challenge just too difficult and could the difficulty have been lowered otherwise?") -- hint, hint+ , (Conquer, "Not alerting the authorities was a choice that paid off handsomely. You can now collect the semiconductors parts from the infected robots all for yourself. Nobody needs to know. Replicant scrap gives a hefty premium on the darknet, even counting in anonymizing intermediaries. This will make for an enormous PTSD-shedding party.")+ , (Escape, "The moment you press the red button, robots get distracted and disperse towards the walls, scanning. You disengage and watch fascinated, but you don't get to see what happens next. The security force contacts you and hauls you up the chute, where you are sternly reprimanded and, unexpectedly, released scot-free after being sworn to silence. Oh well, saving own life is definitely worth more than whatever makes the officer that shooed you off so excited.") ]+ , mrules = T.intercalate "\n"+ [ "* One level only"+ , "* Two heroes vs. Spawned enemies"+ , "* Incapacitate all enemies faster than they can spawn"+ , "* Or find and activate the red alarm console ASAP"+ ]+ , mdesc = T.intercalate "\n"+ [ "Taking this shortcut may not have been the best idea. The tunnel's entry chute was much deeper than the net search suggested and the landing turned out on a pile of robot scrap that dampened the shock, but promptly started moving on its own, shooting rays of light down the corridor and drowning the area in clanking and echoes."+ , "Gasping huddled behind a hardware stack you appraise your misery. That must be the Internet of Things gone wrong, the notorious Robot Replicants, viruses that take over robots or their components, modify, repair, rebuild, clone, merge and divide, spawn and multiply. You've heard about them but you weren't one of the lucky few that experienced the thrill of seeing them. And survived." ]+ , mreason = "This is a simple introductory tutorial adventure. It teaches (avoiding) combat, escape, particularly via displacing, aggression, audacity, speed and multiple good endings and dying."+ , mhint = "Speaking plainly, the two good endings are evacuation thanks to the alarm console and killing off all the replicants. The former requires a long and nerve-wrecking jog with lots of displacing (Shift-direction), while being harassed by robots, to the far end of the tunnel. The latter is hard, because the infected machines initially spawn faster than they can be killed and they keep spawning for as long as a single survivor hides under a crate somewhere. Killing off all robots results in higher score, unless it required much more time.\nWhen meleeing, it's best to keep all characters together, but when running past enemies, a sole sprinter will have a higher speed, though breaking through an unexpected wall of enemies may prove impossible for a single brave. If any of the endings seem unattainable, it may be wise to lower game difficulty level from main menu and/or return after trying out subsequent game modes, battle-hardened and full of mastery."+ }+ raid = ModeKind- { msymbol = 'r'- , mname = "raid (tutorial, 1)"+ { mname = "raid (tutorial, 2)" , mfreq = [(RAID, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = True+ , mattract = False , mroster = rosterRaid , mcaves = cavesRaid- , mendMsg = [ (Killed, "That was unfortunate. The bill for the rescue team and for the subsequent nano medbot treatment will reach the stars. Perhaps more stealth was needed? Perhaps the items lying around the area could aid survival instead of ending up ignored or passively hoarded? Or perhaps a wise course of action would be to choose a Neptune Economic Area Administration challenge with a lower difficulty?")+ , mendMsg = [ (Killed, "The search&rescue and nano-medical revival fees are going to kill you (anew). Perhaps more stealth was needed? Perhaps the items lying around the area could aid survival instead of ending up ignored or passively hoarded? Or perhaps a wise course of action would be to choose a Neptune Economic Area Administration challenge with a lower difficulty?") , (Defeated, "Sadly, you got worked up in the tunnels while another team snatched the prize. Remember, you are at the Outer Frontier to gain wealth and independence through industriousness and commerce. This pits you in a fight against competing agents, not just against the feral nature.") , (Escape, "You are the first to clear a route through the sewer system. Triton City authorities will now be able to establish a perimeter and mop up the side tunnels. You collect your reward of 100 gold grains and start looking for a way to invest it profitably on this Solar System's commercial frontier, abounding in more or less (usually less) regulated opportunities.\nAfter some thought you decide to start by splurging on genetic enhancement for your team. The effects won't be visible at once, but you have to plan ahead, having just made fresh enemies.") ] , mrules = T.intercalate "\n" [ "* One level only"- , "* Two heroes vs. Spawned enemies"+ , "* Two heroes vs. Competition and Spawned enemies" , "* Gather gold"- , "* Find exit and escape ASAP"+ , "* Find a way out and escape ASAP" ] , mdesc = "Neptune Economic Area Administration confirms isolated spottings of oversize vermin in non-residential zones of the Neptune's Triton moon's largest city. To put it plainly: Triton City sewers need purging. The first person to break through to the other exit will be paid 100 gold grains. The Administration \"strongly urges participants not to resort to violence against each other.\" However, no punitive consequences are specified, not even disqualification from the contest."- , mreason = "In addition to initiating the game plot, this adventure provides an introductory tutorial. Relax, explore, gather loot, find the exit and escape. With some luck, you won't even need to fight anything."- , mhint = "You can't use gathered items in your next encounters, so trigger any consumables at will, in particular the electronic chips as common as pebbles on the muddy sewer floors.\nFeel free to scout with only one of the heroes and keep the other one immobile, e.g., standing guard over the squad's shared inventory stash. If in grave danger, retreat with the scout to join forces with the guard. The more gold collected and the faster the victory, the higher your score in this encounter."+ , mreason = "In addition to initiating the game plot, this adventure teaches treasure gathering and item use, looking after the shared inventory stash and dealing with many enemy factions at once. Combat, however, is not a focus, so relax, explore, gather loot, find the way out and escape. With some luck, you won't even need to fight anything."+ , mhint = "You can't use gathered items in your next encounters, so trigger any consumables at will, in particular the throwaway electronic chips as common as pebbles on the muddy sewer floors.\nFeel free to scout with only one of the heroes and keep the other one immobile, e.g., standing guard over the squad's shared inventory stash. If in grave danger, retreat with the scout to join forces with the guard. The more gold collected and the faster the victory, the higher your score in this encounter." } brawl = ModeKind -- sparse melee in daylight, with shade for melee ambush- { msymbol = 'k'- , mname = "brawl (tutorial, 2)"+ { mname = "brawl (tutorial, 3)" , mfreq = [(BRAWL, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = True+ , mattract = False , mroster = rosterBrawl , mcaves = cavesBrawl , mendMsg = [ (Killed, "That treacherous villain didn't honour his word and brought his friends to the fight. It would still not turn so bad if we remembered to use terrain to protect us from missiles or even completely hide our presence and if we honourably kept together to the end, at the same time preventing the overwhelming enemy forces from brutishly ganging up on our modest-sized, though valiant, squad.\nHaving to repurchase the genetic therapy is the most painful result. If repeated, that's going to send you broke and in shame to Earth, to start collecting your Basic Income.")@@ -132,10 +159,10 @@ } crawl = ModeKind- { msymbol = 'c'- , mname = "long crawl (main)"+ { mname = "long crawl (main)" , mfreq = [(LONG, 1), (CRAWL, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawl , mcaves = cavesCrawl , mendMsg = [ (Killed, "It was not supposed to end this way. Perhaps more stealth was in order? Perhaps foes that didn't carry any key resources for your survival nor escape could have been eluded and ignored? Perhaps the gathered items should be used for survival instead of hoarded? Or perhaps the challenge, chosen freely but without awareness of the grisly difficulty, was insurmountable and lost from the very start?")@@ -144,7 +171,7 @@ [ "* Many levels, some requiring tools to access" , "* Three heroes vs. Spawned enemies" , "* Gather gold, gems and stimpacks"- , "* Find exit and escape ASAP"+ , "* Find a way out and escape ASAP" ] , mdesc = "You are busy looting, with utmost satisfaction, the blasted bridge of an old and extravagantly luxurious cruise liner.\nSuddenly, the inert spaceship, supposedly long deserted and barely able to sustain life support, tremors and dials her fusion engines up to red overdrive. The space map flickering among the irreversibly damaged consoles shows the ship manoeuvre deftly off Triton orbit and purposefully climb the Neptune's gravity well. There's no way to control the ship and static floods all communication channels.\nYou decide to scour the nearby dilapidated decks for missing squad members, this time sending them in pairs and mapping the area properly, and then get back to the spaceport the way you came, in your shuttle. However, you are determined not to leave the ship without taking at least a portion of the wealth that is rightfully yours." , mreason = "This is the main, longest and most replayable scenario of the game. The fundamental goal is the survival of your crew. Sub-goals will present themselves as you take in newly visited spaceship decks and figure out ways to reach those that are presently cut off."@@ -161,10 +188,10 @@ -- the other team members are more spotters and guardians than snipers -- and that's their only role, so a small party makes sense. shootout = ModeKind -- sparse ranged in daylight- { msymbol = 's'- , mname = "foggy shootout (3)"+ { mname = "foggy shootout (4)" , mfreq = [(FOGGY, 1), (SHOOTOUT, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False+ , mattract = False , mroster = rosterShootout , mcaves = cavesShootout , mendMsg = [ (Killed, "This is a disgrace. How is a thuggish robbery in broad daylight even possible in a moon city that styles itself as the capital of Outer System technological innovation and commercial opportunity? Where are the municipal surveillance drones, normally so eager to eavesdrop and needlessly complicate an honest tax-free business, when one's health and wealth for once depend on their nosy presence?\nSpeaking of drones, we could use one in this skirmish, or even just a human lookout placed in a covered but unobstructed spot. Then the rest of the squad could snipe from concealment or from a safe distance.\nBarring that, we would end up in a better shape even if we all hid and fired blindly. We'd listen to impact sounds and wait vigilantly for incoming enemy missiles in order to register their trajectories and derive hints of enemy location. Apparently, ranged combat requires a change of pace and better planning than our previous illustrious successes accustomed us to.")@@ -181,10 +208,10 @@ } hunt = ModeKind -- melee vs ranged with reaction fire in daylight- { msymbol = 'h'- , mname = "perilous hunt (4)"+ { mname = "perilous hunt (5)" , mfreq = [(PERILOUS, 1), (HUNT, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False+ , mattract = False , mroster = rosterHunt , mcaves = cavesHunt , mendMsg = [ (Killed, "Next time let's try to remember we are not on a sightseeing expedition. Also, leaving concealment is risky, leaving cover is foolhardy and wandering off is deadly. Also, what was that taking pictures by the mangrove tree all about? Were you trying to immortalize your handsome faces in case our shared pool of money was not enough to revive your sorry carcasses after the defeat?\nGood call, because after paying the techno-medical bills we are broke, while the gang foot soldiers that chase us seem to have military grade communication and reaction fire implants. And we were so close to complete victory and unfathomable wealth, if only we strove to lower the difficulty of this mission instead of raising it.")@@ -195,21 +222,21 @@ [ "* One level only" , "* Seven heroes vs. Seven human enemies capable of concurrent attacks" , "* Minimize losses"- , "* Incapacitate all enemies ASAP"+ , "* Incapacitate all human enemies ASAP" ] , mdesc = "Who is the hunter and who is the prey? The only criterion is last man standing when the chase ends." , mreason = "This is yet another reminiscence of the events that led to the long crawl adventure. This encounter is quite a tactical challenge, because enemies are allowed to fling their ammo simultaneously at your team, which has no such ability." , mhint = "Try not to outshoot the enemy, but to instead focus more on melee tactics. A useful concept here is communication overhead. Any team member that is not waiting and spotting for everybody, but acts, e.g., melees or moves or manages items, slows down all other team members by roughly 10%, because they need to keep track of his actions. Therefore, if other heroes melee, consider carefully if it makes sense to come to their aid, slowing them while you move, or if it's better to stay put and monitor the perimeter. This is true for all factions and all actors on each level separately, except the pointman of each faction, if it has one." -- this also eliminates lag in big battles and helps the player to focus on combat and not get distracted by distant team members frantically trying to reach the battleground in time } -escape = ModeKind -- asymmetric ranged and stealth race at night- { msymbol = 'e'- , mname = "night escape (5)"- , mfreq = [(NIGHT, 1), (ESCAPE, 1), (CAMPAIGN_SCENARIO, 1)]+flight = ModeKind -- asymmetric ranged and stealth race at night+ { mname = "night flight (6)"+ , mfreq = [(NIGHT, 1), (FLIGHT, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False- , mroster = rosterEscape- , mcaves = cavesEscape- , mendMsg = [ (Killed, "Somebody must have tipped the gang guards off. However, us walking along a lit trail, yelling, could have been a contributing factor. Also, it's worth noting that the torches prepared for this assault are best used as thrown makeshift flares.\nOn the other hand, equipping a lit torch makes one visible in the dark, regrettably but not quite unexpectedly. Lastly, the goal of this foray was to find the exit back to the city, marked by a yellow '>' sign, and to gather some treasure along the way. Not to harass every local evildoer, as much as they do deserve it.")+ , mattract = False+ , mroster = rosterFlight+ , mcaves = cavesFlight+ , mendMsg = [ (Killed, "Somebody must have tipped the gang guards off. However, us walking along a lit trail, yelling, could have been a contributing factor. Also, it's worth noting that the torches prepared for this assault are best used as thrown makeshift flares.\nOn the other hand, equipping a lit torch makes one visible in the dark, regrettably but not quite unexpectedly. Lastly, the goal of this foray was to find the way back to the city, marked by a yellow '>' sign, and to gather some treasure along the way. Not to harass every local evildoer, as much as they do deserve it.") , (Conquer, "It was enough to reach the escape area, namely the exit tunnel from the park marked by yellow '>' symbol. Spilling that much blood was risky. unnecessary and alerted the authorities. Having said that --- impressive indeed.") , (Escape, "Congratulations, you took your revenge and it's heavy in your pockets.") ] , mrules = T.intercalate "\n"@@ -217,18 +244,18 @@ , "* Three heroes vs. Seven human enemies capable of concurrent attacks" , "* Minimize losses" , "* Gather gems"- , "* Find exit and escape ASAP"+ , "* Find a way out and escape ASAP" ]- , mdesc = "Bloodied spaceship deed in hand notwithstanding, you can reach the derelict spaceliner only via a shuttle from the Central Triton Spaceport across the city. After hours of being chased in the opposite direction towards the border wall, you sneak back and make a desperate dash through the very den of the pursuing gang. Any valuables you come upon in this public park turned miscreant lair will be fair compensation for your losses, but you need to find the exit before the foes find you. Rein in your wrath and don't attack your tormentors. Foiling their plans by eluding them will be revenge enough."+ , mdesc = "Bloodied spaceship deed in hand notwithstanding, you can reach the derelict spaceliner only via a shuttle from the Central Triton Spaceport across the city. After hours of being chased in the opposite direction towards the border wall, you sneak back and make a desperate dash through the very den of the pursuing gang. Any valuables you come upon in this public park turned miscreant lair will be fair compensation for your losses, but you need to find the way out before the foes find you. Rein in your wrath and don't attack your tormentors. Foiling their plans by eluding them will be revenge enough." , mreason = "The focus of this installment is on stealthy exploration under the threat of numerically superior enemy." , mhint = "" } zoo = ModeKind -- asymmetric crowd melee at night- { msymbol = 'b'- , mname = "burning zoo (6)"+ { mname = "burning zoo (7)" , mfreq = [(BURNING, 1), (ZOO, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False+ , mattract = False , mroster = rosterZoo , mcaves = cavesZoo , mendMsg = [ (Killed, "Against such an onslaught, only clever positioning, use of terrain and patient vigilance gives any chance of survival.")@@ -253,10 +280,10 @@ -- without reaction fire don't make sense, because then usually only one hero -- shoots (and often also scouts) and others just gather ammo. ambush = ModeKind -- dense ranged with reaction fire vs melee at night- { msymbol = 'm'- , mname = "ranged ambush (7)"+ { mname = "ranged ambush (8)" , mfreq = [(RANGED, 1), (AMBUSH, 1), (CAMPAIGN_SCENARIO, 1)] , mtutorial = False+ , mattract = False , mroster = rosterAmbush , mcaves = cavesAmbush , mendMsg = [ (Killed, "You turned out to be the prey, this time, not the hunter. In fact, you are not even in the hunters' league. When fighting against such odds, passively waiting for enemy to spring a trap is to no avail, because a professional team can sneak in darkness and ambush the ambushers.\nGranted, good positioning is crucial, so that each squad member can overwatch the battlefield and fire opportunistically, using the recently recovered mil-grade communication equipment. However, there is no hope without active scouting, throwing lit objects and probing suspect areas with missiles while paying attention to sounds. And that may still not be enough.")@@ -273,10 +300,10 @@ } safari = ModeKind -- Easter egg available only via screensaver- { msymbol = 'f'- , mname = "safari"+ { mname = "safari" , mfreq = [(SAFARI, 1)] , mtutorial = False+ , mattract = False , mroster = rosterSafari , mcaves = cavesSafari , mendMsg = []@@ -284,7 +311,7 @@ [ "* Three levels" , "* Many teammates capable of concurrent action vs. Many enemies" , "* Minimize losses"- , "* Find exit and escape ASAP"+ , "* Find a way out and escape ASAP" ] , mdesc = "\"In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent. Exit at the topmost level.\" This is a VR recording recovered from an alien nest debris." , mreason = "This is an Easter egg. The default squad doctrine is that all team members follow the pointman, but it can be changed from the settings submenu of the main menu."@@ -294,10 +321,10 @@ -- * Testing modes dig = ModeKind- { msymbol = 'd'- , mname = "dig"+ { mname = "dig" , mfreq = [(DIG, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawlEmpty , mcaves = cavesDig , mendMsg = []@@ -308,10 +335,10 @@ } see = ModeKind- { msymbol = 'a'- , mname = "see"+ { mname = "see" , mfreq = [(SEE, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawlEmpty , mcaves = cavesSee , mendMsg = []@@ -322,10 +349,10 @@ } short = ModeKind- { msymbol = 's'- , mname = "short"+ { mname = "short" , mfreq = [(SHORT, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawlEmpty , mcaves = cavesShort , mendMsg = []@@ -335,11 +362,25 @@ , mhint = "" } +fun = ModeKind+ { mname = "fun"+ , mfreq = [(FUN, 1)]+ , mtutorial = False+ , mattract = False+ , mroster = rosterCrawlEmpty+ , mcaves = cavesFun+ , mendMsg = []+ , mrules = ""+ , mdesc = "See all fun maps!"+ , mreason = ""+ , mhint = ""+ }+ crawlEmpty = ModeKind- { msymbol = 'c'- , mname = "crawl empty"+ { mname = "crawl empty" , mfreq = [(CRAWL_EMPTY, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawlEmpty , mcaves = cavesCrawlEmpty , mendMsg = []@@ -350,10 +391,10 @@ } crawlSurvival = ModeKind- { msymbol = 'd'- , mname = "crawl survival"+ { mname = "crawl survival" , mfreq = [(CRAWL_SURVIVAL, 1)] , mtutorial = False+ , mattract = False , mroster = rosterCrawlSurvival , mcaves = cavesCrawl , mendMsg = []@@ -364,10 +405,10 @@ } safariSurvival = ModeKind- { msymbol = 'u'- , mname = "safari survival"+ { mname = "safari survival" , mfreq = [(SAFARI_SURVIVAL, 1)] , mtutorial = False+ , mattract = False , mroster = rosterSafariSurvival , mcaves = cavesSafari , mendMsg = []@@ -378,10 +419,10 @@ } battle = ModeKind- { msymbol = 'b'- , mname = "battle"+ { mname = "battle" , mfreq = [(BATTLE, 1)] , mtutorial = False+ , mattract = False , mroster = rosterBattle , mcaves = cavesBattle , mendMsg = []@@ -392,10 +433,10 @@ } battleDefense = ModeKind- { msymbol = 'f'- , mname = "battle defense"+ { mname = "battle defense" , mfreq = [(BATTLE_DEFENSE, 1)] , mtutorial = False+ , mattract = False , mroster = rosterBattleDefense , mcaves = cavesBattle , mendMsg = []@@ -406,10 +447,10 @@ } battleSurvival = ModeKind- { msymbol = 'i'- , mname = "battle survival"+ { mname = "battle survival" , mfreq = [(BATTLE_SURVIVAL, 1)] , mtutorial = False+ , mattract = False , mroster = rosterBattleSurvival , mcaves = cavesBattle , mendMsg = []@@ -420,10 +461,10 @@ } defense = ModeKind -- perhaps a real scenario in the future- { msymbol = 'e'- , mname = "defense"+ { mname = "defense" , mfreq = [(DEFENSE, 1)] , mtutorial = False+ , mattract = False , mroster = rosterDefense , mcaves = cavesCrawl , mendMsg = []@@ -434,10 +475,10 @@ } defenseEmpty = ModeKind- { msymbol = 'e'- , mname = "defense empty"+ { mname = "defense empty" , mfreq = [(DEFENSE_EMPTY, 1)] , mtutorial = False+ , mattract = False , mroster = rosterDefenseEmpty , mcaves = cavesCrawlEmpty , mendMsg = []@@ -449,358 +490,242 @@ -- * Screensaver modes -screensaverRaid = screensave (AutoLeader False False) $ raid- { mname = "auto-raid (1)"- , mfreq = [(INSERT_COIN, 2), (NO_CONFIRMS, 1)]+screensaverGauntlet = gauntlet+ { mname = "auto-gauntlet (1)"+ , mfreq = []+ , mattract = True } -screensaverBrawl = screensave (AutoLeader False False) $ brawl- { mname = "auto-brawl (2)"- , mfreq = [(NO_CONFIRMS, 1)]+screensaverRaid = raid+ { mname = "auto-raid (2)"+ , mfreq = [(INSERT_COIN, 2)]+ , mattract = True } -screensaverCrawl = screensave (AutoLeader False False) $ crawl+screensaverBrawl = brawl+ { mname = "auto-brawl (3)"+ , mfreq = []+ , mattract = True+ }++screensaverCrawl = crawl { mname = "auto-crawl (long)"- , mfreq = [(NO_CONFIRMS, 1)]+ , mfreq = []+ , mattract = True } -screensaverShootout = screensave (AutoLeader False False) $ shootout- { mname = "auto-shootout (3)"- , mfreq = [(INSERT_COIN, 2), (NO_CONFIRMS, 1)]+screensaverShootout = shootout+ { mname = "auto-shootout (4)"+ , mfreq = [(INSERT_COIN, 2)]+ , mattract = True } -screensaverHunt = screensave (AutoLeader False False) $ hunt- { mname = "auto-hunt (4)"- , mfreq = [(INSERT_COIN, 2), (NO_CONFIRMS, 1)]+screensaverHunt = hunt+ { mname = "auto-hunt (5)"+ , mfreq = [(INSERT_COIN, 2)]+ , mattract = True } -screensaverEscape = screensave (AutoLeader False False) $ escape- { mname = "auto-escape (5)"- , mfreq = [(INSERT_COIN, 2), (NO_CONFIRMS, 1)]+screensaverFlight = flight+ { mname = "auto-flight (6)"+ , mfreq = [(INSERT_COIN, 2)]+ , mattract = True } -screensaverZoo = screensave (AutoLeader False False) $ zoo- { mname = "auto-zoo (6)"- , mfreq = [(NO_CONFIRMS, 1)]+screensaverZoo = zoo+ { mname = "auto-zoo (7)"+ , mfreq = []+ , mattract = True } -screensaverAmbush = screensave (AutoLeader False False) $ ambush- { mname = "auto-ambush (7)"- , mfreq = [(NO_CONFIRMS, 1)]+screensaverAmbush = ambush+ { mname = "auto-ambush (8)"+ , mfreq = []+ , mattract = True } --- changing leader by client needed, because of TFollow-screensaverSafari = screensave (AutoLeader False True) $ safari+screensaverSafari = safari { mname = "auto-safari"- , mfreq = [(INSERT_COIN, 1), (NO_CONFIRMS, 1)]+ , mfreq = [(INSERT_COIN, 1)]+ , mattract = True } -teamCompetitor, teamCivilian, teamMercenary :: TeamContinuity-teamCompetitor = TeamContinuity 2-teamCivilian = TeamContinuity 3-teamMercenary = TeamContinuity 4+rosterGauntlet, rosterRaid, rosterBrawl, rosterCrawl, rosterShootout, rosterHunt, rosterFlight, rosterZoo, rosterAmbush, rosterSafari, rosterCrawlEmpty, rosterCrawlSurvival, rosterSafariSurvival, rosterBattle, rosterBattleDefense, rosterBattleSurvival, rosterDefense, rosterDefenseEmpty :: Roster -rosterRaid, rosterBrawl, rosterCrawl, rosterShootout, rosterHunt, rosterEscape, rosterZoo, rosterAmbush, rosterSafari, rosterCrawlEmpty, rosterCrawlSurvival, rosterSafariSurvival, rosterBattle, rosterBattleDefense, rosterBattleSurvival, rosterDefense, rosterDefenseEmpty :: Roster+rosterGauntlet =+ [ ( EXPLORER_EXTERMINATOR+ , [(1, 2, EXTERMINATOR_HERO)] )+ , ( ROBOT_GAUNTLET+ , [] ) -- avoid a robot that sleeps far away and keeps the faction spawning+ , (HORROR_REPRESENTATIVE, []) ] -rosterRaid = Roster- { rosterList = [ ( playerAnimal -- starting over escape- , Nothing- , [(2, 2, ANIMAL)] )- , ( playerHero {fhiCondPoly = hiHeroShort}- , Just teamExplorer- , [(2, 2, HERO)] )- , ( playerAntiHero { fname = "Red Collar Bro"- , fhiCondPoly = hiHeroShort }- , Just teamCompetitor- , [(2, 1, RANGER_HERO)] )- , ( playerRobot- , Nothing- , [(2, 1, ROBOT)] )- , (playerHorror, Nothing, []) ] -- for summoned monsters- , rosterEnemy = [ ("Spacefarer", "Animal Kingdom")- , ("Spacefarer", "Robot Anarchy")- , ("Spacefarer", "Horror Den")- , ("Spacefarer", "Red Collar Bro")- , ("Red Collar Bro", "Animal Kingdom")- , ("Red Collar Bro", "Robot Anarchy")- , ("Red Collar Bro", "Horror Den") ]- , rosterAlly = [("Robot Anarchy", "Animal Kingdom")] }+rosterRaid =+ [ ( ANIMAL_REPRESENTATIVE -- starting over escape+ , [(2, 2, ANIMAL)] )+ , ( EXPLORER_SHORT+ , [(2, 2, HERO)] )+ , ( COMPETITOR_SHORT+ , [(2, 1, RAIDER_HERO)] )+ , ( ROBOT_REPRESENTATIVE+ , [(2, 1, ROBOT)] )+ , (HORROR_REPRESENTATIVE, []) ] -- for summoned monsters -rosterBrawl = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamExplorer- , [(3, 3, BRAWLER_HERO)] )- -- start heroes on stairs, since they go first- , ( playerAntiHero { fname = "Red Collar Bro"- , fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamCompetitor- , [ (3, 3, BRAWLER_HERO)- , (2, 3, BRAWLER_HERO) ] )- , (playerHorror, Nothing, []) ]- , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")- , ("Spacefarer", "Horror Den")- , ("Red Collar Bro", "Horror Den") ]- , rosterAlly = [] }+rosterBrawl =+ [ ( EXPLORER_NO_ESCAPE+ , [(3, 3, BRAWLER_HERO)] )+ -- start heroes on stairs, since they go first+ , ( COMPETITOR_NO_ESCAPE+ , [ (3, 3, BRAWLER_HERO)+ , (2, 3, BRAWLER_HERO) ] )+ , (HORROR_REPRESENTATIVE, []) ] -rosterCrawl = Roster- { rosterList = [ ( playerHero -- start on stairs so that stash is handy- , Just teamExplorer- , [(3, 3, CRAWL_HERO)] )- , ( playerMonster- , Nothing- , [] )- , ( playerAnimal- , Nothing- , [ (2, 5, ANIMAL)- , (3, 4, ANIMAL)- , -- Optional huge battle at the end:- (15, 100, MOBILE_ANIMAL) ] )- , ( playerRobot- , Nothing- , [(2, 4, ROBOT)] ) ]- , rosterEnemy = [ ("Spacefarer", "Alien Hierarchy")- , ("Spacefarer", "Animal Kingdom")- , ("Spacefarer", "Robot Anarchy") ]- , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")- , ("Alien Hierarchy", "Robot Anarchy")- , ("Robot Anarchy", "Animal Kingdom") ] }+rosterCrawl =+ [ ( EXPLORER_REPRESENTATIVE -- start on stairs so that stash is handy+ , [(3, 3, CRAWL_HERO)] )+ , ( MONSTER_REPRESENTATIVE+ , [] )+ , ( ANIMAL_REPRESENTATIVE+ , [ (2, 5, ANIMAL)+ , (3, 4, ANIMAL)+ , -- Optional huge battle at the end:+ (16, 100, MOBILE_ANIMAL) ] )+ , ( ROBOT_REPRESENTATIVE+ , [(2, 4, ROBOT)] )+ , ( ROBOT_VIRUS+ , [] ) ] -- Exactly one scout gets a sight boost, to help the aggressor, because he uses -- the scout for initial attack, while camper (on big enough maps) -- can't guess where the attack would come and so can't position his single -- scout to counter the stealthy advance.-rosterShootout = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamExplorer- , [(5, 2, RANGER_HERO), (5, 1, SCOUT_HERO)] )- , ( playerAntiHero { fname = "Red Collar Bro"- , fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamCompetitor- , [(5, 2, RANGER_HERO), (5, 1, SCOUT_HERO)] )- , (playerHorror, Nothing, []) ]- , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")- , ("Spacefarer", "Horror Den")- , ("Red Collar Bro", "Horror Den") ]- , rosterAlly = [] }+rosterShootout =+ [ ( EXPLORER_NO_ESCAPE+ , [(5, 2, RANGER_HERO), (5, 1, SCOUT_HERO)] )+ , ( COMPETITOR_NO_ESCAPE+ , [(5, 2, RANGER_HERO), (5, 1, SCOUT_HERO)] )+ , (HORROR_REPRESENTATIVE, []) ] -rosterHunt = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamExplorer- , [(6, 7, SOLDIER_HERO)] )- , ( playerAntiHero { fname = "Red Collar Bro"- , fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamCompetitor- , [(6, 6, AMBUSHER_HERO), (6, 1, SCOUT_HERO)] )- , (playerHorror, Nothing, []) ]- , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")- , ("Spacefarer", "Horror Den")- , ("Red Collar Bro", "Horror Den") ]- , rosterAlly = [] }+rosterHunt =+ [ ( EXPLORER_NO_ESCAPE+ , [(6, 7, SOLDIER_HERO)] )+ , ( COMPETITOR_NO_ESCAPE+ , [(6, 6, AMBUSHER_HERO), (6, 1, SCOUT_HERO)] )+ , (HORROR_REPRESENTATIVE, []) ] -rosterEscape = Roster- { rosterList = [ ( playerAntiHero { fname = "Red Collar Bro"- , fcanEscape = False -- start on escape- , fhiCondPoly = hiHeroMedium }- , Just teamCompetitor- , [(7, 6, AMBUSHER_HERO), (7, 1, SCOUT_HERO)] )- , ( playerHero {fhiCondPoly = hiHeroMedium}- , Just teamExplorer- , [(7, 2, ESCAPIST_HERO), (7, 1, SCOUT_HERO)] )- -- second on the list to let bros occupy the exit- , (playerHorror, Nothing, []) ]- , rosterEnemy = [ ("Spacefarer", "Red Collar Bro")- , ("Spacefarer", "Horror Den")- , ("Red Collar Bro", "Horror Den") ]- , rosterAlly = [] }+rosterFlight =+ [ ( COMPETITOR_NO_ESCAPE -- start on escape+ , [(7, 6, AMBUSHER_HERO), (7, 1, SCOUT_HERO)] )+ , ( EXPLORER_MEDIUM+ , [(7, 2, ESCAPIST_HERO), (7, 1, SCOUT_HERO)] )+ -- second on the list to let the bros occupy the escape+ , (HORROR_REPRESENTATIVE, []) ] -rosterZoo = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroLong }- , Just teamExplorer- , [(8, 5, SOLDIER_HERO)] )- , ( playerAnimal {fneverEmpty = True}- , Nothing- , [(8, 100, MOBILE_ANIMAL)] )- , (playerHorror, Nothing, []) ] -- for summoned monsters- , rosterEnemy = [ ("Spacefarer", "Animal Kingdom")- , ("Spacefarer", "Horror Den") ]- , rosterAlly = [] }+rosterZoo =+ [ ( EXPLORER_TRAPPED+ , [(8, 5, SOLDIER_HERO)] )+ , ( ANIMAL_CAPTIVE+ , [(8, 100, MOBILE_ANIMAL)] )+ , (HORROR_REPRESENTATIVE, []) ] -- for summoned monsters -rosterAmbush = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamExplorer- , [(9, 5, AMBUSHER_HERO), (9, 1, SCOUT_HERO)] )- , ( playerAntiHero { fname = "Gray Off-World Mercenary"- , fcanEscape = False- , fhiCondPoly = hiHeroMedium }- , Just teamMercenary- , [(9, 12, MERCENARY_HERO)] )- , (playerHorror, Nothing, []) ]- , rosterEnemy = [ ("Spacefarer", "Gray Off-World Mercenary")- , ("Spacefarer", "Horror Den")- , ("Gray Off-World Mercenary", "Horror Den") ]- , rosterAlly = [] }+rosterAmbush =+ [ ( EXPLORER_NO_ESCAPE+ , [(9, 5, AMBUSHER_HERO), (9, 1, SCOUT_HERO)] )+ , ( OFF_WORLD_REPRESENTATIVE+ , [(9, 12, MERCENARY_HERO)] )+ , (HORROR_REPRESENTATIVE, []) ] -- No horrors faction needed, because spawned heroes land in civilian faction.-rosterSafari = Roster- { rosterList = [ ( playerMonsterTourist- , Nothing- , [(5, 15, MONSTER)] )- , ( playerHunamConvict- , Just teamCivilian- , [(5, 2, CIVILIAN)] )- , ( playerAnimalMagnificent- , Nothing- , [(10, 15, MOBILE_ANIMAL)] )- , ( playerAnimalExquisite -- start on escape- , Nothing- , [(15, 20, MOBILE_ANIMAL)] )- , (playerHorror, Nothing, []) ]- -- construction hooter; neutral- , rosterEnemy = [ ("Alien Tourist Office", "Hunam Convict")- , ( "Alien Tourist Office"- , "Animal Magnificent Specimen Variety" )- , ( "Alien Tourist Office"- , "Animal Exquisite Herds and Packs Galore" )- , ( "Animal Magnificent Specimen Variety"- , "Hunam Convict" )- , ( "Hunam Convict"- , "Animal Exquisite Herds and Packs Galore" ) ]- , rosterAlly = [ ( "Animal Magnificent Specimen Variety"- , "Animal Exquisite Herds and Packs Galore" ) ] }+rosterSafari =+ [ ( MONSTER_TOURIST+ , [(5, 15, MONSTER)] )+ , ( CONVICT_REPRESENTATIVE+ , [(5, 2, CIVILIAN)] )+ , ( ANIMAL_MAGNIFICENT+ , [(10, 15, MOBILE_ANIMAL)] )+ , ( ANIMAL_EXQUISITE -- start on escape+ , [(16, 20, MOBILE_ANIMAL)] )+ , (HORROR_REPRESENTATIVE, []) ]+ -- construction hooter; neutral -rosterCrawlEmpty = Roster- { rosterList = [ ( playerHero- , Just teamExplorer- , [(1, 1, CRAWL_HERO)] )- , (playerHorror, Nothing, []) ]- -- for spawned and summoned monsters- , rosterEnemy = []- , rosterAlly = [] }+rosterCrawlEmpty =+ [ ( EXPLORER_PACIFIST+ , [(1, 1, CRAWL_HERO)] )+ , (HORROR_PACIFIST, []) ]+ -- for spawned and summoned monsters -rosterCrawlSurvival = rosterCrawl- { rosterList = [ ( playerAntiHero- , Just teamExplorer- , [(3, 3, CRAWL_HERO)] )- , ( playerMonster- , Nothing- , [(5, 1, MONSTER)] )- , ( playerAnimal {fhasUI = True}- , Nothing- , [(5, 10, ANIMAL)] ) -- explore unopposed for some time- , ( playerRobot- , Nothing- , [(3, 3, ROBOT)] ) ] }+rosterCrawlSurvival =+ [ ( EXPLORER_AUTOMATED+ , [(3, 3, CRAWL_HERO)] )+ , ( MONSTER_REPRESENTATIVE+ , [(5, 1, MONSTER)] )+ , ( ANIMAL_OR_ROBOT_NARRATING+ , [(5, 10, ANIMAL)] ) -- explore unopposed for some time+ , (HORROR_REPRESENTATIVE, []) ] -rosterSafariSurvival = rosterSafari- { rosterList = [ ( playerMonsterTourist- { fleaderMode = Just $ AutoLeader True True- , fhasUI = False- , funderAI = True }- , Nothing- , [(5, 15, MONSTER)] )- , ( playerHunamConvict- , Just teamCivilian- , [(5, 3, CIVILIAN)] )- , ( playerAnimalMagnificent- { fleaderMode = Just $ AutoLeader True False- , fhasUI = True- , funderAI = False }- , Nothing- , [(10, 20, MOBILE_ANIMAL)] )- , ( playerAnimalExquisite- , Nothing- , [(15, 30, MOBILE_ANIMAL)] )- , (playerHorror, Nothing, []) ] }+rosterSafariSurvival =+ [ ( MONSTER_TOURIST_PASSIVE+ , [(5, 15, MONSTER)] )+ , ( CONVICT_REPRESENTATIVE+ , [(5, 3, CIVILIAN)] )+ , ( ANIMAL_MAGNIFICENT_NARRATING+ , [(10, 20, MOBILE_ANIMAL)] )+ , ( ANIMAL_EXQUISITE+ , [(16, 30, MOBILE_ANIMAL)] )+ , (HORROR_REPRESENTATIVE, []) ] -rosterBattle = Roster- { rosterList = [ ( playerHero { fcanEscape = False- , fhiCondPoly = hiHeroLong }- , Just teamExplorer- , [(10, 5, SOLDIER_HERO)] )- , ( playerMonster {fneverEmpty = True}- , Nothing- , [(10, 35, MOBILE_MONSTER)] )- , ( playerAnimal {fneverEmpty = True}- , Nothing- , [(10, 20, MOBILE_ANIMAL)] )- , ( playerRobot {fneverEmpty = True}- , Nothing- , [(10, 15, MOBILE_ROBOT)] ) ]- , rosterEnemy = [ ("Spacefarer", "Alien Hierarchy")- , ("Spacefarer", "Animal Kingdom")- , ("Spacefarer", "Robot Anarchy") ]- , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom")- , ("Alien Hierarchy", "Robot Anarchy")- , ("Robot Anarchy", "Animal Kingdom") ] }+rosterBattle =+ [ ( EXPLORER_TRAPPED+ , [(10, 5, SOLDIER_HERO)] )+ , ( MONSTER_CAPTIVE+ , [(10, 35, MOBILE_MONSTER)] )+ , ( ANIMAL_CAPTIVE+ , [(10, 20, MOBILE_ANIMAL)] )+ , ( ROBOT_CAPTIVE+ , [(10, 15, MOBILE_ROBOT)] ) ] -rosterBattleDefense = rosterBattle- { rosterList = [ ( playerAntiHero { fcanEscape = False- , fhiCondPoly = hiHeroLong }- , Just teamExplorer- , [(10, 5, SOLDIER_HERO)] )- , ( playerMonster { fneverEmpty = True- , fhasUI = True }- , Nothing- , [(10, 35, MOBILE_MONSTER)] )- , ( playerAnimal {fneverEmpty = True}- , Nothing- , [(10, 20, MOBILE_ANIMAL)] )- , ( playerRobot {fneverEmpty = True}- , Nothing- , [(10, 15, MOBILE_ROBOT)] ) ] }+rosterBattleDefense =+ [ ( EXPLORER_AUTOMATED_TRAPPED+ , [(10, 5, SOLDIER_HERO)] )+ , ( MONSTER_CAPTIVE_NARRATING+ , [(10, 35, MOBILE_MONSTER)] )+ , ( ANIMAL_CAPTIVE+ , [(10, 20, MOBILE_ANIMAL)] )+ , ( ROBOT_CAPTIVE+ , [(10, 15, MOBILE_ROBOT)] ) ] -rosterBattleSurvival = rosterBattle- { rosterList = [ ( playerAntiHero { fcanEscape = False- , fhiCondPoly = hiHeroLong }- , Just teamExplorer- , [(10, 5, SOLDIER_HERO)] )- , ( playerMonster {fneverEmpty = True}- , Nothing- , [(10, 35, MOBILE_MONSTER)] )- , ( playerAnimal { fneverEmpty = True- , fhasUI = True }- , Nothing- , [(10, 20, MOBILE_ANIMAL)] )- , ( playerRobot {fneverEmpty = True}- , Nothing- , [(10, 15, MOBILE_ROBOT)] ) ] }+rosterBattleSurvival =+ [ ( EXPLORER_AUTOMATED_TRAPPED+ , [(10, 5, SOLDIER_HERO)] )+ , ( MONSTER_CAPTIVE+ , [(10, 35, MOBILE_MONSTER)] )+ , ( ANIMAL_CAPTIVE_NARRATING+ , [(10, 20, MOBILE_ANIMAL)] )+ , ( ROBOT_CAPTIVE+ , [(10, 15, MOBILE_ROBOT)] ) ] -rosterDefense = rosterCrawl- { rosterList = [ ( playerAntiHero- , Just teamExplorer- , [(3, 3, CRAWL_HERO)] )- , ( playerAntiMonster- , Nothing- , [] )- , ( playerAnimal- , Nothing- , -- Fun from the start to avoid empty initial level:- [ (3, 5 + 1 `d` 2, ANIMAL) -- many, because no spawning- -- Optional huge battle at the end:- , (15, 100, MOBILE_ANIMAL) ] )- , ( playerRobot- , Nothing- , [] ) ] }+rosterDefense =+ [ ( EXPLORER_AUTOMATED+ , [(3, 3, CRAWL_HERO)] )+ , ( MONSTER_ANTI+ , [] )+ , ( ANIMAL_REPRESENTATIVE+ , -- Fun from the start to avoid empty initial level:+ [ (3, 5 + 1 `d` 2, ANIMAL) -- many, because no spawning+ -- Optional huge battle at the end:+ , (16, 100, MOBILE_ANIMAL) ] )+ , ( ROBOT_REPRESENTATIVE+ , [] ) ] -rosterDefenseEmpty = rosterCrawl- { rosterList = [ ( playerAntiMonster {fneverEmpty = True}- , Nothing- , [(4, 1, SCOUT_MONSTER)] )- , (playerHorror, Nothing, []) ]- -- for spawned and summoned animals- , rosterEnemy = []- , rosterAlly = [] }+rosterDefenseEmpty =+ [ ( MONSTER_ANTI_PACIFIST+ , [(4, 1, SCOUT_MONSTER)] )+ , (HORROR_PACIFIST, []) ]+ -- for spawned and summoned animals -cavesRaid, cavesBrawl, cavesCrawl, cavesShootout, cavesHunt, cavesEscape, cavesZoo, cavesAmbush, cavesSafari, cavesDig, cavesSee, cavesShort, cavesCrawlEmpty, cavesBattle :: Caves+cavesGauntlet, cavesRaid, cavesBrawl, cavesCrawl, cavesShootout, cavesHunt, cavesFlight, cavesZoo, cavesAmbush, cavesSafari, cavesDig, cavesSee, cavesShort, cavesFun, cavesCrawlEmpty, cavesBattle :: Caves +cavesGauntlet = [([1], [CAVE_GAUNTLET])]+ cavesRaid = [([2], [CAVE_RAID])] cavesBrawl = reverse [([2], [CAVE_BRAWL_ALT]), ([3], [CAVE_BRAWL])]@@ -811,13 +736,13 @@ , ([2], [CAVE_SHALLOW_ROGUE]) , ([3], [CAVE_BRIDGE]) , ([4], [CAVE_NOISE])- , ([7, 6, 5], [CAVE_ROGUE, CAVE_ARENA, CAVE_RESIDENTIAL])+ , ([8, 7, 6, 5], [CAVE_VIRUS, CAVE_ROGUE, CAVE_ARENA, CAVE_RESIDENTIAL]) -- reversed order, to match @reverse@ later on- , ([8], [CAVE_LABORATORY])- , ([11, 10, 9], [DEFAULT_RANDOM, DEFAULT_RANDOM, CAVE_MUSEUM])- , ([12], [CAVE_EXIT])- , ([14, 13], [DEFAULT_RANDOM, CAVE_CASINO])- , ([15], [CAVE_POWER]) ]+ , ([9], [CAVE_LABORATORY])+ , ([12, 11, 10], [DEFAULT_RANDOM, DEFAULT_RANDOM, CAVE_MUSEUM])+ , ([13], [CAVE_EGRESS])+ , ([15, 14], [DEFAULT_RANDOM, CAVE_CASINO])+ , ([16], [CAVE_POWER]) ] cavesCrawl = reverse listCrawl @@ -825,7 +750,7 @@ cavesHunt = [([6], [CAVE_HUNT])] -cavesEscape = [([7], [CAVE_ESCAPE])]+cavesFlight = [([7], [CAVE_FLIGHT])] cavesZoo = [([8], [CAVE_ZOO])] @@ -833,15 +758,15 @@ cavesSafari = reverse [ ([5], [CAVE_SAFARI_1]) , ([10], [CAVE_SAFARI_2])- , ([15], [CAVE_SAFARI_3]) ]+ , ([16], [CAVE_SAFARI_3]) ] cavesDig = reverse $ concat $ zipWith (map . renumberCaves)- [0, 15 ..]+ [0, 16 ..] (replicate 100 listCrawl) -- [0, 2 ..]--- (replicate 100 [([1], [CAVE_OUTERMOST]),([2], [CAVE_EXIT])])+-- (replicate 100 [([1], [CAVE_OUTERMOST]),([2], [CAVE_EGRESS])]) renumberCaves :: Int -> ([Int], [GroupName CaveKind]) -> ([Int], [GroupName CaveKind])@@ -853,15 +778,22 @@ cavesShort = let numberCaves n c = ([n], [c]) in reverse $ zipWith numberCaves [1..]- $ concatMap (replicate 100) $ take 7 allCaves+ $ concatMap (replicate 100) $ take 8 allCaves +cavesFun = let numberCaves n c = ([n], [c])+ funModes = drop 4 (take 8 allCaves)+ funLevels = [ CAVE_OUTERMOST, CAVE_RESIDENTIAL, CAVE_ROGUE+ , CAVE_AMBUSH ]+ in reverse $ zipWith numberCaves [1..]+ $ concatMap (replicate 33) $ funModes ++ funLevels+ allCaves :: [GroupName CaveKind] allCaves =- [ CAVE_RAID, CAVE_BRAWL, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_ESCAPE, CAVE_ZOO- , CAVE_AMBUSH+ [ CAVE_GAUNTLET, CAVE_RAID, CAVE_BRAWL, CAVE_SHOOTOUT, CAVE_HUNT, CAVE_FLIGHT+ , CAVE_ZOO, CAVE_AMBUSH , CAVE_OUTERMOST, CAVE_SHALLOW_ROGUE, CAVE_BRIDGE, CAVE_NOISE, CAVE_ROGUE- , CAVE_ARENA, CAVE_RESIDENTIAL, CAVE_LABORATORY, CAVE_MUSEUM, CAVE_EXIT- , CAVE_CASINO, CAVE_POWER ]+ , CAVE_ARENA, CAVE_RESIDENTIAL, CAVE_VIRUS, CAVE_LABORATORY, CAVE_MUSEUM+ , CAVE_EGRESS, CAVE_CASINO, CAVE_POWER ] cavesCrawlEmpty = reverse $ map (\(ns, grps) ->
− GameDefinition/Content/ModeKindPlayer.hs
@@ -1,211 +0,0 @@--- Copyright (c) 2008--2011 Andres Loeh--- Copyright (c) 2010--2021 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.------ | Basic players definitions.-module Content.ModeKindPlayer- ( playerHero, playerAntiHero, playerCivilian- , playerMonster, playerAntiMonster, playerAnimal- , playerHorror, playerMonsterTourist, playerHunamConvict- , playerAnimalMagnificent, playerAnimalExquisite- , hiHeroShort, hiHeroMedium, hiHeroLong, hiDweller- , playerRobot- ) where--import Prelude ()--import Game.LambdaHack.Core.Prelude--import Content.ItemKindActor-import Content.ItemKindOrgan-import qualified Game.LambdaHack.Content.ItemKind as IK-import Game.LambdaHack.Content.ModeKind-import Game.LambdaHack.Definition.Ability--playerHero, playerAntiHero, playerCivilian, playerMonster, playerAntiMonster, playerAnimal, playerHorror, playerMonsterTourist, playerHunamConvict, playerAnimalMagnificent, playerAnimalExquisite :: Player-playerRobot :: Player--playerHero = Player- { fname = "Spacefarer"- , fgroups = [HERO]- , fskillsOther = meleeAdjacent- , fcanEscape = True- , fneverEmpty = True- , fhiCondPoly = hiHeroLong- , fhasGender = True- , fdoctrine = TExplore- , fleaderMode = Just $ AutoLeader False False- , fhasUI = True- , funderAI = False- }--playerAntiHero = playerHero- { fleaderMode = Just $ AutoLeader True False- , fhasUI = False- , funderAI = True- }--playerCivilian = Player- { fname = "Civilian"- , fgroups = [HERO, CIVILIAN]- , fskillsOther = zeroSkills -- not coordinated by any leadership- , fcanEscape = False- , fneverEmpty = True- , fhiCondPoly = hiHeroMedium- , fhasGender = True- , fdoctrine = TPatrol- , fleaderMode = Nothing -- unorganized- , fhasUI = False- , funderAI = True- }--playerMonster = Player- { fname = "Alien Hierarchy"- , fgroups = [MONSTER, MOBILE_MONSTER, AQUATIC_MONSTER]- , fskillsOther = zeroSkills- , fcanEscape = False- , fneverEmpty = False- , fhiCondPoly = hiDweller- , fhasGender = False- , fdoctrine = TExplore- , fleaderMode =- -- No point changing leader on level, since all move and they- -- don't follow the leader.- Just $ AutoLeader True True- , fhasUI = False- , funderAI = True- }--playerAntiMonster = playerMonster- { fleaderMode = Just $ AutoLeader True True- , fhasUI = True- , funderAI = False- }--playerAnimal = Player- { fname = "Animal Kingdom"- , fgroups = [ ANIMAL, MOBILE_ANIMAL, IMMOBILE_ANIMAL, AQUATIC_ANIMAL- , SCAVENGER ]- , fskillsOther = zeroSkills- , fcanEscape = False- , fneverEmpty = False- , fhiCondPoly = hiDweller- , fhasGender = False- , fdoctrine = TRoam -- can't pick up, so no point exploring- , fleaderMode = Nothing- , fhasUI = False- , funderAI = True- }---- | A special player, for summoned actors that don't belong to any--- of the main players of a given game. E.g., animals summoned during--- a brawl game between two hero factions land in the horror faction.--- In every game, either all factions for which summoning items exist--- should be present or a horror player should be added to host them.-playerHorror = Player- { fname = "Horror Den"- , fgroups = [IK.HORROR]- , fskillsOther = zeroSkills- , fcanEscape = False- , fneverEmpty = False- , fhiCondPoly = []- , fhasGender = False- , fdoctrine = TPatrol -- disoriented- , fleaderMode = Nothing- , fhasUI = False- , funderAI = True- }--playerMonsterTourist =- playerAntiMonster { fname = "Alien Tourist Office"- , fcanEscape = True- , fneverEmpty = True -- no spawning- , fhiCondPoly = hiHeroMedium- , fdoctrine = TFollow -- follow-the-guide, as tourists do- , fleaderMode = Just $ AutoLeader False False- , funderAI = False }--playerHunamConvict =- playerCivilian { fname = "Hunam Convict"- , fleaderMode = Just $ AutoLeader True False- , funderAI = True }--playerAnimalMagnificent =- playerAnimal { fname = "Animal Magnificent Specimen Variety"- , fneverEmpty = True }--playerAnimalExquisite =- playerAnimal { fname = "Animal Exquisite Herds and Packs Galore"- , fneverEmpty = True }--hiHeroLong, hiHeroMedium, hiHeroShort, hiDweller :: HiCondPoly--hiHeroShort =- [ ( [(HiLoot, 100)]- , [minBound..maxBound] )- , ( [(HiConst, 100)]- , victoryOutcomes )- , ( [(HiSprint, -500)] -- speed matters, but only if fast enough- , victoryOutcomes )- , ( [(HiSurvival, 10)] -- few points for surviving long- , deafeatOutcomes )- ]--hiHeroMedium =- [ ( [(HiLoot, 200)] -- usually no loot, but if so, no harm- , [minBound..maxBound] )- , ( [(HiConst, 200), (HiLoss, -10)]- , victoryOutcomes )- , ( [(HiSprint, -500)] -- speed matters, but only if fast enough- , victoryOutcomes )- , ( [(HiBlitz, -100)] -- speed matters always- , victoryOutcomes )- , ( [(HiSurvival, 10)] -- few points for surviving long- , deafeatOutcomes )- ]---- Heroes in long crawls rejoice in loot.-hiHeroLong =- [ ( [(HiLoot, 10000)] -- multiplied by fraction of collected- , [minBound..maxBound] )- , ( [(HiSprint, -20000)] -- speedrun bonus, if below this number of turns- , victoryOutcomes )- , ( [(HiBlitz, -100)] -- speed matters always- , victoryOutcomes )- , ( [(HiSurvival, 10)] -- few points for surviving long- , deafeatOutcomes )- ]---- Spawners get no points from loot, but try to kill--- all opponents fast or at least hold up for long.-hiDweller = [ ( [(HiConst, 1000)] -- no loot, so big win reward- , victoryOutcomes )- , ( [(HiConst, 1000), (HiLoss, -10)]- , victoryOutcomes )- , ( [(HiSprint, -1000)] -- speedrun bonus, if below- , victoryOutcomes )- , ( [(HiBlitz, -100)] -- speed matters- , victoryOutcomes )- , ( [(HiSurvival, 100)]- , deafeatOutcomes )- ]---- Allure-specific--playerRobot = Player- { fname = "Robot Anarchy"- , fgroups = [ ROBOT, MOBILE_ROBOT, IMMOBILE_ROBOT --, "aquatic robot"- , CONSTRUCTION_ROBOT ]- , fskillsOther = zeroSkills- , fcanEscape = False- , fneverEmpty = False- , fhiCondPoly = hiDweller- , fhasGender = False- , fdoctrine = TRoam- -- TODO:TFollow -- coordinated via net, follow alien leader- , fleaderMode = Nothing- , fhasUI = False- , funderAI = True- }
GameDefinition/Content/PlaceKind.hs view
@@ -8,10 +8,10 @@ -- place kind. module Content.PlaceKind ( -- * Group name patterns- pattern ROGUE, pattern LABORATORY, pattern ZOO, pattern BRAWL, pattern SHOOTOUT, pattern ARENA, pattern ESCAPE, pattern AMBUSH, pattern BATTLE, pattern NOISE, pattern EMPTY+ pattern ROGUE, pattern LABORATORY, pattern ZOO, pattern BRAWL, pattern SHOOTOUT, pattern ARENA, pattern FLIGHT, pattern AMBUSH, pattern BATTLE, pattern NOISE, pattern EMPTY , pattern INDOOR_ESCAPE_DOWN, pattern INDOOR_ESCAPE_UP, pattern OUTDOOR_ESCAPE_DOWN, pattern TINY_STAIRCASE, pattern OPEN_STAIRCASE, pattern CLOSED_STAIRCASE, pattern WALLED_STAIRCASE, pattern GATED_TINY_STAIRCASE, pattern GATED_OPEN_STAIRCASE, pattern GATED_CLOSED_STAIRCASE, pattern OUTDOOR_TINY_STAIRCASE, pattern OUTDOOR_CLOSED_STAIRCASE, pattern OUTDOOR_WALLED_STAIRCASE- , pattern RESIDENTIAL, pattern MUSEUM, pattern EXIT, pattern RAID- , pattern TINY_LIFT, pattern OPEN_LIFT, pattern WALLED_LIFT, pattern CLOSED_LIFT, pattern ESCAPE_FROM_SPACESHIP_DOWN, pattern DECON_TINY_STAIRCASE, pattern DECON_OPEN_STAIRCASE, pattern DECON_WALLED_STAIRCASE, pattern DECON_TINY_LIFT, pattern DECON_OPEN_LIFT, pattern DECON_WALLED_LIFT, pattern GATED_TINY_LIFT, pattern GATED_OPEN_LIFT, pattern GATED_CLOSED_LIFT, pattern WELDED_TINY_LIFT, pattern WELDED_OPEN_LIFT, pattern WELDED_WALLED_LIFT, pattern WELDED_TINY_STAIRCASE, pattern WELDED_OPEN_STAIRCASE, pattern WELDED_WALLED_STAIRCASE+ , pattern RESIDENTIAL, pattern MUSEUM, pattern EGRESS, pattern VIRUS, pattern GAUNTLET, pattern RAID+ , pattern TINY_LIFT, pattern OPEN_LIFT, pattern WALLED_LIFT, pattern CLOSED_LIFT, pattern SPACESHIP_ESCAPE_DOWN, pattern ALARM_ESCAPE_UP, pattern DECON_TINY_STAIRCASE, pattern DECON_OPEN_STAIRCASE, pattern DECON_WALLED_STAIRCASE, pattern DECON_TINY_LIFT, pattern DECON_OPEN_LIFT, pattern DECON_WALLED_LIFT, pattern GATED_TINY_LIFT, pattern GATED_OPEN_LIFT, pattern GATED_CLOSED_LIFT, pattern WELDED_TINY_LIFT, pattern WELDED_OPEN_LIFT, pattern WELDED_WALLED_LIFT, pattern WELDED_TINY_STAIRCASE, pattern WELDED_OPEN_STAIRCASE, pattern WELDED_WALLED_STAIRCASE , groupNamesSingleton, groupNames , -- * Content content@@ -24,12 +24,13 @@ import qualified Data.EnumMap.Strict as EM import qualified Data.Text as T -import Content.TileKind hiding (content, groupNames, groupNamesSingleton) import Game.LambdaHack.Content.PlaceKind import Game.LambdaHack.Content.TileKind (TileKind) import Game.LambdaHack.Definition.Defs import Game.LambdaHack.Definition.DefsInternal +import Content.TileKind hiding (content, groupNames, groupNamesSingleton)+ -- * Group name patterns groupNamesSingleton :: [GroupName PlaceKind]@@ -39,19 +40,19 @@ -- group names, let's also add the generated group names to @groupNames@. groupNames :: [GroupName PlaceKind] groupNames =- [ROGUE, LABORATORY, ZOO, BRAWL, SHOOTOUT, ARENA, ESCAPE, AMBUSH, BATTLE, NOISE, EMPTY]+ [ROGUE, LABORATORY, ZOO, BRAWL, SHOOTOUT, ARENA, FLIGHT, AMBUSH, BATTLE, NOISE, EMPTY] ++ [INDOOR_ESCAPE_DOWN, INDOOR_ESCAPE_UP, OUTDOOR_ESCAPE_DOWN, TINY_STAIRCASE, OPEN_STAIRCASE, CLOSED_STAIRCASE, WALLED_STAIRCASE]- ++ [RESIDENTIAL, MUSEUM, EXIT, RAID]- ++ [TINY_LIFT, OPEN_LIFT, WALLED_LIFT, CLOSED_LIFT, ESCAPE_FROM_SPACESHIP_DOWN]+ ++ [RESIDENTIAL, MUSEUM, EGRESS, VIRUS, GAUNTLET, RAID]+ ++ [TINY_LIFT, OPEN_LIFT, WALLED_LIFT, CLOSED_LIFT, SPACESHIP_ESCAPE_DOWN, ALARM_ESCAPE_UP] ++ fst generatedStairs -pattern ROGUE, LABORATORY, ZOO, BRAWL, SHOOTOUT, ARENA, ESCAPE, AMBUSH, BATTLE, NOISE, EMPTY :: GroupName PlaceKind+pattern ROGUE, LABORATORY, ZOO, BRAWL, SHOOTOUT, ARENA, FLIGHT, AMBUSH, BATTLE, NOISE, EMPTY :: GroupName PlaceKind pattern INDOOR_ESCAPE_DOWN, INDOOR_ESCAPE_UP, OUTDOOR_ESCAPE_DOWN, TINY_STAIRCASE, OPEN_STAIRCASE, CLOSED_STAIRCASE, WALLED_STAIRCASE, GATED_TINY_STAIRCASE, GATED_OPEN_STAIRCASE, GATED_CLOSED_STAIRCASE, OUTDOOR_TINY_STAIRCASE, OUTDOOR_CLOSED_STAIRCASE, OUTDOOR_WALLED_STAIRCASE :: GroupName PlaceKind -pattern RESIDENTIAL, MUSEUM, EXIT, RAID :: GroupName PlaceKind+pattern RESIDENTIAL, MUSEUM, EGRESS, VIRUS, GAUNTLET, RAID :: GroupName PlaceKind -pattern TINY_LIFT, OPEN_LIFT, WALLED_LIFT, CLOSED_LIFT, ESCAPE_FROM_SPACESHIP_DOWN, DECON_TINY_STAIRCASE, DECON_OPEN_STAIRCASE, DECON_WALLED_STAIRCASE, DECON_TINY_LIFT, DECON_OPEN_LIFT, DECON_WALLED_LIFT, GATED_TINY_LIFT, GATED_OPEN_LIFT, GATED_CLOSED_LIFT, WELDED_TINY_LIFT, WELDED_OPEN_LIFT, WELDED_WALLED_LIFT, WELDED_TINY_STAIRCASE, WELDED_OPEN_STAIRCASE, WELDED_WALLED_STAIRCASE :: GroupName PlaceKind+pattern TINY_LIFT, OPEN_LIFT, WALLED_LIFT, CLOSED_LIFT, SPACESHIP_ESCAPE_DOWN, ALARM_ESCAPE_UP, DECON_TINY_STAIRCASE, DECON_OPEN_STAIRCASE, DECON_WALLED_STAIRCASE, DECON_TINY_LIFT, DECON_OPEN_LIFT, DECON_WALLED_LIFT, GATED_TINY_LIFT, GATED_OPEN_LIFT, GATED_CLOSED_LIFT, WELDED_TINY_LIFT, WELDED_OPEN_LIFT, WELDED_WALLED_LIFT, WELDED_TINY_STAIRCASE, WELDED_OPEN_STAIRCASE, WELDED_WALLED_STAIRCASE :: GroupName PlaceKind pattern ROGUE = GroupName "rogue" pattern LABORATORY = GroupName "laboratory"@@ -59,15 +60,15 @@ pattern BRAWL = GroupName "brawl" pattern SHOOTOUT = GroupName "shootout" pattern ARENA = GroupName "arena"-pattern ESCAPE = GroupName "escape"+pattern FLIGHT = GroupName "flight" pattern AMBUSH = GroupName "ambush" pattern BATTLE = GroupName "battle" pattern NOISE = GroupName "noise" pattern EMPTY = GroupName "empty" -pattern INDOOR_ESCAPE_DOWN = GroupName "escape down"-pattern INDOOR_ESCAPE_UP = GroupName "escape up"-pattern OUTDOOR_ESCAPE_DOWN = GroupName "outdoor escape route"+pattern INDOOR_ESCAPE_DOWN = GroupName "indoor escape down"+pattern INDOOR_ESCAPE_UP = GroupName "indoor escape up"+pattern OUTDOOR_ESCAPE_DOWN = GroupName "outdoor escape down" pattern TINY_STAIRCASE = GroupName "tiny staircase" pattern OPEN_STAIRCASE = GroupName "open staircase" pattern CLOSED_STAIRCASE = GroupName "closed staircase"@@ -85,14 +86,17 @@ -- ** Allure-specific pattern RESIDENTIAL = GroupName "residential" pattern MUSEUM = GroupName "museum"-pattern EXIT = GroupName "exit"+pattern EGRESS = GroupName "egress"+pattern VIRUS = GroupName "virus"+pattern GAUNTLET = GroupName "gauntlet" pattern RAID = GroupName "raid" pattern TINY_LIFT = GroupName "tiny lift" pattern OPEN_LIFT = GroupName "open lift" pattern WALLED_LIFT = GroupName "walled lift" pattern CLOSED_LIFT = GroupName "closed lift"-pattern ESCAPE_FROM_SPACESHIP_DOWN = GroupName "escape from spaceship"+pattern SPACESHIP_ESCAPE_DOWN = GroupName "spaceship escape down"+pattern ALARM_ESCAPE_UP = GroupName "alarm escape up" -- This is a rotten compromise, because these are synthesized below, -- so typos can happen.@@ -138,13 +142,13 @@ generatedStairs :: ([GroupName PlaceKind], [PlaceKind]) generatedStairs = let (stairs, lifts) = partition ((/= "a lift") . pname) staircaseBasic- gatedStairs = map switchStaircaseToGated stairs+ gatedStairs = map switchStairToGated stairs gatedLifts = map switchLiftToGated lifts- deconStairs = map switchStaircaseToDecon stairs+ deconStairs = map switchStairToDecon stairs deconLifts = map switchLiftToDecon lifts- weldedStairs = map switchStaircaseToWelded stairs+ weldedStairs = map switchStairToWelded stairs weldedLifts = map switchLiftToWelded lifts- outdoorStairs = map switchStaircaseToOutdoor stairs+ outdoorStairs = map switchStairToOutdoor stairs stairsAll = stairs ++ gatedStairs ++ deconStairs ++ weldedStairs ++ outdoorStairs liftsAll = lifts ++ gatedLifts ++ deconLifts ++ weldedLifts@@ -153,10 +157,10 @@ ++ deconStairs ++ deconLifts ++ weldedStairs ++ weldedLifts ++ outdoorStairs- ++ map (switchExitToUp "stair terminal") stairsAll- ++ map (switchExitToUp "lift terminal") liftsAll- ++ map (switchExitToDown "stair terminal") stairsAll- ++ map (switchExitToDown "lift terminal") liftsAll+ ++ map (switchStairToUp "stair terminal") stairsAll+ ++ map (switchStairToUp "lift terminal") liftsAll+ ++ map (switchStairToDown "stair terminal") stairsAll+ ++ map (switchStairToDown "lift terminal") liftsAll in ( nub $ sort $ concatMap (map fst . pfreq) genStairs , genStairs ) @@ -170,7 +174,8 @@ let upEscapes = map switchEscapeToUp escapeDownBasic outdoorEscapes = map switchEscapeToOutdoorDown escapeDownBasic spaceshipEscapes = map switchEscapeToSpaceshipDown escapeDownBasic- in upEscapes ++ outdoorEscapes ++ spaceshipEscapes+ upAlarms = map switchEscapeToAlarmUp escapeDownBasic+ in upEscapes ++ outdoorEscapes ++ spaceshipEscapes ++ upAlarms -- The dots below are @'\x00B7'@, as defined in 'TileKind.floorSymbol'. defaultLegendLit :: EM.EnumMap Char (GroupName TileKind)@@ -179,8 +184,8 @@ , ('0', S_PILLAR) , ('&', S_RUBBLE_PILE) , ('+', S_CLOSED_DOOR)- , ('<', ESCAPE_UP)- , ('>', ESCAPE_DOWN)+ , ('<', TILE_INDOOR_ESCAPE_UP)+ , ('>', TILE_INDOOR_ESCAPE_DOWN) , ('%', TRANSPARENT_WALL) , ('^', ICE_BUILDUP) , ('\'', S_OPEN_DOOR)@@ -195,8 +200,8 @@ , ('0', S_PILLAR) , ('&', S_RUBBLE_PILE) , ('+', S_CLOSED_DOOR)- , ('<', ESCAPE_UP)- , ('>', ESCAPE_DOWN)+ , ('<', TILE_INDOOR_ESCAPE_UP)+ , ('>', TILE_INDOOR_ESCAPE_DOWN) , ('%', TRANSPARENT_WALL) , ('^', ICE_BUILDUP) , ('\'', S_OPEN_DOOR)@@ -206,8 +211,7 @@ , ('I', SIGNBOARD) ] deadEnd = PlaceKind -- needs to have index 0- { psymbol = 'd'- , pname = "a dead end"+ { pname = "a dead end" , pfreq = [] , prarity = [] , pcover = CStretch@@ -217,8 +221,7 @@ , plegendLit = defaultLegendLit } rect = PlaceKind -- Valid for any nonempty area, hence low frequency.- { psymbol = 'r'- , pname = "a room"+ { pname = "a room" , pfreq = [(ROGUE, 100), (LABORATORY, 10), (RAID, 100)] , prarity = [(1, 10), (10, 6)] , pcover = CStretch@@ -232,9 +235,8 @@ , pfreq = [(SHOOTOUT, 1), (ZOO, 10)] } rectWindows = overridePlaceKind [('%', RECT_WINDOWS)] $ PlaceKind- { psymbol = 'w'- , pname = "a shed"- , pfreq = [(ESCAPE, 20)]+ { pname = "a shed"+ , pfreq = [(FLIGHT, 20)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch , pfence = FNone@@ -245,8 +247,7 @@ , plegendLit = defaultLegendLit } glasshouse = PlaceKind- { psymbol = 'g'- , pname = "a glasshouse"+ { pname = "a glasshouse" , pfreq = [(SHOOTOUT, 10)] , prarity = [(1, 10), (10, 7)] , pcover = CStretch@@ -272,8 +273,7 @@ } pulpit = overridePlaceKind [('0', S_PULPIT)] $ PlaceKind -- except for floor, all will be lit, regardless of night/dark; OK- { psymbol = 'p'- , pname = "a stand podium"+ { pname = "a stand podium" , pfreq = [(ARENA, 15), (MUSEUM, 15), (ZOO, 100)] , prarity = [(1, 1)] , pcover = CMirror@@ -287,8 +287,7 @@ } ruin = override2PlaceKind [('·', DAMP_FLOOR_DARK)] [('·', DAMP_FLOOR_LIT)] $ PlaceKind- { psymbol = 'R'- , pname = "ruins"+ { pname = "ruins" , pfreq = [(BATTLE, 660), (AMBUSH, 70)] , prarity = [(1, 1)] , pcover = CStretch@@ -299,14 +298,15 @@ } ruin2 = ruin { pname = "a scaffolding"- , pfreq = [(NOISE, 2000), (EXIT, 5), (MUSEUM, 1)]+ , pfreq = [(NOISE, 2000), (EGRESS, 5), (MUSEUM, 1)] } collapsed = overridePlaceKind [('#', DOORLESS_MACHINERY)] $ PlaceKind- { psymbol = 'c'- , pname = "a hardware stack"- , pfreq = [(NOISE, 1)]+ { pname = "a hardware stack"+ , pfreq = [(NOISE, 1), (VIRUS, 10), (GAUNTLET, 2)] -- no point taking up space if very little space taken,- -- but if no other place can be generated, a failsafe is useful+ -- but if no other place can be generated, a failsafe is useful;+ -- this is also useful for tiny levels, such as GAUNTLET,+ -- where without cfenceApart, the other shapes could be cut off , prarity = [(1, 1)] , pcover = CStretch , pfence = FNone@@ -316,7 +316,7 @@ , plegendLit = defaultLegendLit } collapsed2 = collapsed- { pfreq = [(NOISE, 1000), (BATTLE, 200)]+ { pfreq = [(NOISE, 1000), (VIRUS, 50), (BATTLE, 200)] , ptopLeft = [ "X#" , "##" ]@@ -355,8 +355,7 @@ ] } pillar = PlaceKind- { psymbol = 'p'- , pname = "a court"+ { pname = "a court" , pfreq = [ (ROGUE, 250), (ARENA, 15), (MUSEUM, 10) , (LABORATORY, 200), (RAID, 50) ] , prarity = [(1, 1)]@@ -407,7 +406,7 @@ -- no STUCK_DOOR, because FWall, so would break global pathfinding { pname = "a bank outlet" , pfreq = [ (ROGUE, 1200), (ARENA, 6000)- , (EMPTY, 600), (EXIT, 600) ]+ , (EMPTY, 600), (EGRESS, 600) ] , ptopLeft = [ "&i%·" , "ii#·" , "%#p·"@@ -429,10 +428,9 @@ ] } colonnade = PlaceKind- { psymbol = 'c'- , pname = "a colonnade"- , pfreq = [ (ROGUE, 12), (NOISE, 1000), (ESCAPE, 200)- , (EXIT, 30), (RAID, 12) ]+ { pname = "a colonnade"+ , pfreq = [ (ROGUE, 12), (NOISE, 1000), (FLIGHT, 200)+ , (EGRESS, 30), (RAID, 12) ] , prarity = [(1, 12), (10, 12)] , pcover = CAlternate , pfence = FFloor@@ -508,9 +506,8 @@ } lampPost = overridePlaceKind [ ('0', S_LAMP_POST) , ('·', S_FLOOR_ACTOR_LIT) ] $ PlaceKind- { psymbol = 'l'- , pname = "a lamp-lit area"- , pfreq = [ (ESCAPE, 200), (ZOO, 100), (AMBUSH, 1000)+ { pname = "a lamp-lit area"+ , pfreq = [ (FLIGHT, 200), (ZOO, 100), (AMBUSH, 1000) , (BATTLE, 100) ] , prarity = [(1, 1)] , pcover = CVerbatim@@ -529,7 +526,7 @@ ] } lampPost3 = lampPost- { pfreq = [(ESCAPE, 3000), (ZOO, 500), (BATTLE, 1100)]+ { pfreq = [(FLIGHT, 3000), (ZOO, 500), (BATTLE, 1100)] , ptopLeft = [ "XX·XX" , "X···X" , "··0··"@@ -538,7 +535,7 @@ ] } lampPost4 = lampPost- { pfreq = [(ESCAPE, 3000), (ZOO, 500), (BATTLE, 600)]+ { pfreq = [(FLIGHT, 3000), (ZOO, 500), (BATTLE, 600)] , ptopLeft = [ "X···X" , "·····" , "··0··"@@ -551,8 +548,7 @@ [ ('0', S_TREE_LIT) , ('s', TREE_SHADE_WALKABLE_LIT) ] $ overridePlaceKind [('·', S_SHADED_GROUND)] $ PlaceKind- { psymbol = 't'- , pname = "a tree shade"+ { pname = "a tree shade" , pfreq = [(BRAWL, 500)] , prarity = [(1, 1)] , pcover = CMirror@@ -567,9 +563,8 @@ fogClump = override2PlaceKind [('f', FOG_CLUMP_DARK)] [('f', FOG_CLUMP_LIT)] $ overridePlaceKind [(';', S_FOG_LIT)] $ PlaceKind- { psymbol = 'f'- , pname = "a foggy patch"- , pfreq = [(EMPTY, 400), (SHOOTOUT, 70), (ESCAPE, 60), (RAID, 50)]+ { pname = "a foggy patch"+ , pfreq = [(EMPTY, 500), (SHOOTOUT, 70), (FLIGHT, 60), (RAID, 20)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FNone@@ -581,7 +576,7 @@ , plegendLit = defaultLegendLit } fogClump2 = fogClump- { pfreq = [(EMPTY, 2200), (SHOOTOUT, 400), (ESCAPE, 100), (RAID, 250)]+ { pfreq = [(EMPTY, 2500), (SHOOTOUT, 400), (FLIGHT, 100), (RAID, 50)] , ptopLeft = [ "X;f" , "f;f" , ";;f"@@ -593,9 +588,8 @@ [ ('f', SMOKE_CLUMP_LIT) , ('·', S_FLOOR_ACTOR_LIT) ] $ overridePlaceKind [(';', S_SMOKE_LIT)] $ PlaceKind- { psymbol = 's'- , pname = "a smoky patch"- , pfreq = [(EXIT, 20), (ZOO, 40), (AMBUSH, 50)]+ { pname = "a smoky patch"+ , pfreq = [(EGRESS, 20), (ZOO, 40), (AMBUSH, 50), (VIRUS, 1)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FNone@@ -607,7 +601,7 @@ , plegendLit = defaultLegendLit } smokeClump2 = smokeClump- { pfreq = [(EXIT, 100), (ZOO, 200), (AMBUSH, 150)]+ { pfreq = [(EGRESS, 100), (ZOO, 200), (AMBUSH, 150), (VIRUS, 2)] , ptopLeft = [ "X;f" , "f;f" , ";;f"@@ -631,9 +625,8 @@ bushClump = override2PlaceKind [('f', BUSH_CLUMP_DARK)] [('f', BUSH_CLUMP_LIT)] $ overridePlaceKind [(';', S_BUSH_LIT)] $ PlaceKind- { psymbol = 'b'- , pname = "a bushy patch"- , pfreq = [(SHOOTOUT, 120), (EMPTY, 60), (BRAWL, 30)]+ { pname = "a bushy patch"+ , pfreq = [(SHOOTOUT, 120), (EMPTY, 160), (BRAWL, 30)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FNone@@ -652,8 +645,7 @@ , ('0', S_LAMP_POST) , ('b', BARREL) , ('a', S_FLOOR_ACTOR_LIT) ] $ PlaceKind- { psymbol = '>'- , pname = "an escape down"+ { pname = "an escape down" , pfreq = [(INDOOR_ESCAPE_DOWN, 1)] , prarity = [(1, 1)] , pcover = CVerbatim@@ -740,8 +732,7 @@ staircase = overridePlaceKind [ ('<', STAIRCASE_UP) , ('>', STAIRCASE_DOWN) , ('S', FILLER_WALL) ] $ PlaceKind- { psymbol = '/'- , pname = "a staircase"+ { pname = "a staircase" , pfreq = [(TINY_STAIRCASE, 1)] -- no cover when arriving; low freq , prarity = [(1, 100), (10, 100)] , pcover = CVerbatim@@ -767,8 +758,7 @@ [ ('<', STAIRCASE_LIFT_UP), ('>', STAIRCASE_LIFT_DOWN) , ('S', S_LIFT_SHAFT) ] staircaseLift = overridePlaceKind overrideLift $ PlaceKind- { psymbol = '|'- , pname = "a lift"+ { pname = "a lift" , pfreq = [(TINY_LIFT, 1)] , prarity = [(1, 100), (10, 100)] , pcover = CVerbatim@@ -1183,8 +1173,7 @@ , ('f', PUMPS_LIT) , (';', UNDERBRUSH_CLUMP_LIT) ] $ overridePlaceKind [('d', DOORLESS_MACHINERY)] $ PlaceKind- { psymbol = 'w'- , pname = "water pumps"+ { pname = "water pumps" , pfreq = [ (ROGUE, 200), (LABORATORY, 100), (EMPTY, 2000) , (SHOOTOUT, 50), (RAID, 300) ] , prarity = [(1, 1)]@@ -1209,10 +1198,9 @@ , ('b', BARREL) , ('a', SAFE_TRAIL_LIT) , ('T', S_TREE_LIT) ] $ PlaceKind- { psymbol = 'o'- , pname = "a dome"+ { pname = "a dome" , pfreq = [ (ROGUE, 20000), (ARENA, 30000), (MUSEUM, 30000)- , (LABORATORY, 50000), (EMPTY, 3000), (EXIT, 5000)+ , (LABORATORY, 50000), (EMPTY, 3000), (EGRESS, 5000) , (AMBUSH, 20000), (RAID, 20000) ] , prarity = [(1, 1)] , pcover = CStretch@@ -1228,7 +1216,7 @@ } ovalFloor = oval { pfreq = [ (ROGUE, 150000), (ARENA, 60000), (MUSEUM, 60000)- , (LABORATORY, 100000), (EMPTY, 20000), (EXIT, 5000)+ , (LABORATORY, 100000), (EMPTY, 20000), (EGRESS, 5000) , (AMBUSH, 100000), (RAID, 150000) ] , pfence = FGround , ptopLeft = [ "aXXX##"@@ -1241,7 +1229,7 @@ } ovalSquare = oval { pfreq = [ (ROGUE, 20000), (ARENA, 30000), (MUSEUM, 30000)- , (LABORATORY, 50000), (EMPTY, 8000), (EXIT, 5000)+ , (LABORATORY, 50000), (EMPTY, 8000), (EGRESS, 5000) , (AMBUSH, 20000), (RAID, 20000) ] , pfence = FGround , ptopLeft = [ "X###+"@@ -1301,8 +1289,7 @@ ] } floodedRoom = PlaceKind -- Valid for any nonempty area, hence low frequency.- { psymbol = 'f'- , pname = "a flooded room"+ { pname = "a flooded room" , pfreq = [(ROGUE, 10), (LABORATORY, 12), (ZOO, 50), (RAID, 7)] , prarity = [(1, 1)] , pcover = CStretch@@ -1312,8 +1299,7 @@ , plegendLit = defaultLegendLit } floodedRoom2 = overridePlaceKind [('f', PUMPS_LIT)] $ PlaceKind- { psymbol = 'p'- , pname = "a pond"+ { pname = "a pond" , pfreq = [(BRAWL, 100)] , prarity = [(1, 1)] , pcover = CMirror@@ -1334,10 +1320,9 @@ , ('p', TRAPPED_DOOR) , ('i', FLOOR_ACTOR_ITEM) -- lit or not, randomly , ('$', TRAPPABLE_WALL) ] $ PlaceKind- { psymbol = 'm'- , pname = "an intricate maze"+ { pname = "an intricate maze" , pfreq = [ (ROGUE, 60), (LABORATORY, 1500), (ARENA, 3)- , (MUSEUM, 3), (EXIT, 100), (RAID, 60) ]+ , (MUSEUM, 3), (EGRESS, 100), (RAID, 60) ] , prarity = [(1, 1)] , pcover = CStretch , pfence = FWall@@ -1350,7 +1335,7 @@ } maze2 = maze { pfreq = [ (ROGUE, 120), (LABORATORY, 12000), (ARENA, 4)- , (MUSEUM, 4), (EXIT, 100), (RAID, 120) ]+ , (MUSEUM, 4), (EGRESS, 100), (RAID, 120) ] , ptopLeft = [ "#·%%·" , "·%··#" , "···#·"@@ -1358,7 +1343,7 @@ } maze3 = maze { pfreq = [ (ROGUE, 120), (LABORATORY, 1000), (ARENA, 8)- , (MUSEUM, 4), (EMPTY, 300), (EXIT, 50), (RAID, 120) ]+ , (MUSEUM, 4), (EMPTY, 300), (EGRESS, 50), (RAID, 120) ] , ptopLeft = [ "#·ff·" , "·f··#" , "···#;"@@ -1366,7 +1351,7 @@ } maze4 = maze { pfreq = [ (ROGUE, 300), (LABORATORY, 15000), (ARENA, 9)- , (EXIT, 200), (RAID, 300) ]+ , (EGRESS, 200), (RAID, 300) ] , ptopLeft = [ "##·##·" , "#·#··#" , "~·f···"@@ -1374,7 +1359,7 @@ } mazeBig = maze { pfreq = [ (ROGUE, 1500), (LABORATORY, 8000), (ARENA, 10000)- , (EXIT, 1000), (RAID, 300) ]+ , (EGRESS, 1000), (RAID, 300) ] , pfence = FNone , ptopLeft = [ "X$$$$$" , "$··##·"@@ -1401,10 +1386,9 @@ , (';', UNDERBRUSH_CLUMP_LIT) ] $ overridePlaceKind [ ('d', DOORLESS_MACHINERY) , ('w', S_REINFORCED_WALL) ] $ PlaceKind- { psymbol = '#'- , pname = "air filters"+ { pname = "air filters" , pfreq = [ (ROGUE, 40), (LABORATORY, 48), (MUSEUM, 10)- , (EXIT, 150), (NOISE, 480)+ , (EGRESS, 150), (NOISE, 480) , (ZOO, 700), (AMBUSH, 80), (RAID, 40) ] , prarity = [(1, 1)] , pcover = CReflect@@ -1441,7 +1425,7 @@ cells5 = cells -- this one is distinct enough from others, so needs a boost { pname = "broken robot holds" , pfreq = [ (ROGUE, 20), (LABORATORY, 15)- , (EMPTY, 80), (EXIT, 70), (NOISE, 150) ]+ , (EMPTY, 80), (EGRESS, 70), (NOISE, 150) ] , ptopLeft = [ "··w" , "·:w" , "wwo"@@ -1457,7 +1441,7 @@ cells7 = cells { pname = "a defunct control room" , pfreq = [ (ROGUE, 10), (LABORATORY, 20)- , (EXIT, 30), (NOISE, 200), (AMBUSH, 50) ]+ , (EGRESS, 30), (NOISE, 200), (AMBUSH, 50) ] , pfence = FFloor , ptopLeft = [ "d·o" , "·#o"@@ -1466,9 +1450,8 @@ tank = overridePlaceKind [ ('#', DOORLESS_WALL) , ('r', S_REINFORCED_WALL) , ('b', BARREL) ] $ PlaceKind- { psymbol = 'c'- , pname = "a tank"- , pfreq = [(EMPTY, 1)]+ { pname = "a tank"+ , pfreq = [(EMPTY, 2)] -- no point taking up space if very little space taken, -- but if no other place can be generated, a failsafe is useful , prarity = [(1, 1)]@@ -1481,26 +1464,27 @@ } tank2 = tank { pname = "a barrel stack"- , pfreq = [(EMPTY, 30), (EXIT, 2), (NOISE, 1), (BATTLE, 1)]+ , pfreq = [(EMPTY, 60), (EGRESS, 2), (NOISE, 1), (VIRUS, 10), (BATTLE, 1)] , ptopLeft = [ "b" ] } tank3 = tank- { pfreq = [(EMPTY, 150), (EXIT, 15), (NOISE, 50), (BATTLE, 25)]+ { pfreq = [ (EMPTY, 300), (EGRESS, 15), (NOISE, 50), (GAUNTLET, 1)+ , (BATTLE, 25) ] , ptopLeft = [ "0#" , "##" ] } tank4 = tank { pname = "a barrel stack"- , pfreq = [(EMPTY, 150), (EXIT, 8), (NOISE, 50), (BATTLE, 25)]+ , pfreq = [(EMPTY, 300), (EGRESS, 8), (NOISE, 50), (VIRUS, 40), (BATTLE, 25)] , ptopLeft = [ "Xb" , "bb" ] } tank5 = tank { pname = "a barrel yard"- , pfreq = [(EMPTY, 1800), (EXIT, 700), (NOISE, 700), (BATTLE, 300)]+ , pfreq = [(EMPTY, 4000), (EGRESS, 800), (NOISE, 800), (BATTLE, 350)] , pcover = CAlternate , ptopLeft = [ "bbX" , "bbX"@@ -1509,7 +1493,7 @@ } tank6 = tank { pname = "a barrel yard"- , pfreq = [(EMPTY, 15000), (EXIT, 5000), (NOISE, 5000), (BATTLE, 2500)]+ , pfreq = [(EMPTY, 30000), (EGRESS, 5000), (NOISE, 5000), (BATTLE, 2500)] , pcover = CAlternate , ptopLeft = [ "bbbX" , "bbbX"@@ -1518,14 +1502,15 @@ ] } tank7 = tank- { pfreq = [(EMPTY, 300), (EXIT, 5), (NOISE, 100), (BATTLE, 50)]+ { pfreq = [ (EMPTY, 600), (EGRESS, 5), (NOISE, 100), (BATTLE, 50)+ , (GAUNTLET, 1) ] , ptopLeft = [ "rr#" , "r##" , "###" ] } tank8 = tank- { pfreq = [(EMPTY, 500), (EXIT, 15), (NOISE, 150), (BATTLE, 70)]+ { pfreq = [(EMPTY, 1000), (EGRESS, 15), (NOISE, 150), (BATTLE, 70)] , ptopLeft = [ "XX0#" , "Xrr#" , "0r##"@@ -1534,7 +1519,7 @@ } tank9 = tank { pname = "a barrel yard"- , pfreq = [(EMPTY, 500), (EXIT, 150), (NOISE, 150), (BATTLE, 70)]+ , pfreq = [(EMPTY, 3000), (EGRESS, 150), (NOISE, 150), (BATTLE, 70)] , pcover = CReflect , ptopLeft = [ "XbbX" , "bbbX"@@ -1544,7 +1529,7 @@ } tank10 = tank { pname = "a cistern"- , pfreq = [(EMPTY, 500), (EXIT, 15), (NOISE, 150), (BATTLE, 70)]+ , pfreq = [(EMPTY, 1000), (EGRESS, 15), (NOISE, 150), (BATTLE, 70)] , ptopLeft = [ "XXr#" , "Xr##" , "r###"@@ -1553,7 +1538,7 @@ } tank11 = tank { pname = "a barrel yard"- , pfreq = [(EMPTY, 700), (EXIT, 250), (NOISE, 250), (BATTLE, 125)]+ , pfreq = [(EMPTY, 4000), (EGRESS, 250), (NOISE, 250), (BATTLE, 125)] , pcover = CReflect , ptopLeft = [ "bbbXX" , "bbbbX"@@ -1563,7 +1548,7 @@ } tank12 = tank { pname = "a barrel yard"- , pfreq = [(EMPTY, 1000), (EXIT, 500), (NOISE, 500), (BATTLE, 250)]+ , pfreq = [(EMPTY, 6000), (EGRESS, 500), (NOISE, 500), (BATTLE, 250)] , pcover = CReflect , ptopLeft = [ "XbbXX" , "bbbbX"@@ -1581,9 +1566,8 @@ , ('u', STUCK_DOOR) , ('h', S_HARDWARE_RACK) , ('w', S_REINFORCED_WALL) ] $ PlaceKind- { psymbol = 's'- , pname = "a shuttle husk"- , pfreq = [(EMPTY, 1000), (EXIT, 15000), (AMBUSH, 15000)]+ { pname = "a shuttle husk"+ , pfreq = [(EMPTY, 2000), (EGRESS, 15000), (AMBUSH, 15000)] , prarity = [(1, 1)] , pcover = CMirror , pfence = FGround@@ -1601,12 +1585,12 @@ , plegendLit = defaultLegendLit } shuttleHusk2 = shuttleHusk- { pfreq = [(EMPTY, 1000), (EXIT, 15000), (AMBUSH, 15000)]+ { pfreq = [(EMPTY, 4000), (EGRESS, 30000), (AMBUSH, 30000)] , ptopLeft = map (T.cons 'X' . flip T.snoc 'X') $ ptopLeft shuttleHusk -- 9 x 9 } shuttleHusk3 = shuttleHusk- { pfreq = [(EMPTY, 300), (EXIT, 5000), (AMBUSH, 5000)]+ { pfreq = [(EMPTY, 600), (EGRESS, 5000), (AMBUSH, 5000)] , ptopLeft = [ ":··##··X" -- 8 x 8 , "X#%ww%#X" , "#w····w#"@@ -1618,12 +1602,12 @@ ] } shuttleHusk4 = shuttleHusk3- { pfreq = [(EMPTY, 300), (EXIT, 5000), (AMBUSH, 5000)]+ { pfreq = [(EMPTY, 600), (EGRESS, 5000), (AMBUSH, 5000)] , ptopLeft = map (T.cons 'X' . flip T.snoc 'X') $ ptopLeft shuttleHusk3 -- 10 x 8 } shuttleHusk5 = shuttleHusk- { pfreq = [(EXIT, 80000), (AMBUSH, 80000)]+ { pfreq = [(EGRESS, 80000), (AMBUSH, 80000)] -- can't have EMPTY or AI can't reach and kill the boss and get the key , ptopLeft = [ "···##···" -- 8 x 10 , "w#%ww%#w"@@ -1638,7 +1622,7 @@ ] } shuttleHusk6 = shuttleHusk- { pfreq = [(EMPTY, 2000), (EXIT, 120000), (AMBUSH, 120000)]+ { pfreq = [(EMPTY, 4000), (EGRESS, 120000), (AMBUSH, 120000)] , ptopLeft = [ "X··###··X" -- 9 x 10 , "X#%#w#%#X" , "##·h·h·##"@@ -1654,9 +1638,8 @@ dormitory = overridePlaceKind [ ('d', FLOOR_ACTOR_ITEM_LIT) , ('f', PUMPS_LIT) , ('$', TRAPPABLE_WALL) ] $ PlaceKind- { psymbol = 'd'- , pname = "dormitory"- , pfreq = [(RESIDENTIAL, 10000)]+ { pname = "dormitory"+ , pfreq = [(RESIDENTIAL, 30000)] , prarity = [(1, 1)] , pcover = CAlternate , pfence = FWall@@ -1724,21 +1707,19 @@ -- * Helper functions -switchExitToUp :: Text -> PlaceKind -> PlaceKind-switchExitToUp terminal s = override2PlaceKind+switchStairToUp :: Text -> PlaceKind -> PlaceKind+switchStairToUp terminal s = override2PlaceKind [('>', GroupName $ terminal <+> "Dark")] [('>', GroupName $ terminal <+> "Lit")] $ s- { psymbol = '<'- , pname = pname s <+> "up"+ { pname = pname s <+> "up" , pfreq = renameFreqs (<+> "up") $ pfreq s } -switchExitToDown :: Text -> PlaceKind -> PlaceKind-switchExitToDown terminal s = override2PlaceKind+switchStairToDown :: Text -> PlaceKind -> PlaceKind+switchStairToDown terminal s = override2PlaceKind [('<', GroupName $ terminal <+> "Dark")] [('<', GroupName $ terminal <+> "Lit")] $ s- { psymbol = '>'- , pname = pname s <+> "down"+ { pname = pname s <+> "down" , pfreq = renameFreqs (<+> "down") $ pfreq s } @@ -1748,10 +1729,9 @@ [ ('<', GATED_STAIRCASE_UP), ('>', GATED_STAIRCASE_DOWN) , ('S', FILLER_WALL) ] -switchStaircaseToGated :: PlaceKind -> PlaceKind-switchStaircaseToGated s = overridePlaceKind overrideGatedStaircase $ s- { psymbol = 'g'- , pname = T.unwords $ "a gated" : tail (T.words (pname s))+switchStairToGated :: PlaceKind -> PlaceKind+switchStairToGated s = overridePlaceKind overrideGatedStaircase $ s+ { pname = T.unwords $ "a gated" : tail (T.words (pname s)) , pfreq = renameFreqs ("gated" <+>) $ pfreq s } @@ -1762,8 +1742,7 @@ switchLiftToGated :: PlaceKind -> PlaceKind switchLiftToGated s = overridePlaceKind overrideGatedLift $ s- { psymbol = 'g'- , pname = T.unwords $ "a gated" : tail (T.words (pname s))+ { pname = T.unwords $ "a gated" : tail (T.words (pname s)) , pfreq = renameFreqs ("gated" <+>) $ pfreq s } @@ -1774,10 +1753,9 @@ , ('>', S_STAIRCASE_TRAP_DOWN_OIL) -- talter high enough , ('S', FILLER_WALL) ] -switchStaircaseToDecon :: PlaceKind -> PlaceKind-switchStaircaseToDecon s = overridePlaceKind overrideDeconStaircase $ s- { psymbol = 'd'- , pfreq = renameFreqs ("decon" <+>) $ pfreq s+switchStairToDecon :: PlaceKind -> PlaceKind+switchStairToDecon s = overridePlaceKind overrideDeconStaircase $ s+ { pfreq = renameFreqs ("decon" <+>) $ pfreq s } overrideDeconLift :: [(Char, GroupName TileKind)]@@ -1788,8 +1766,7 @@ switchLiftToDecon :: PlaceKind -> PlaceKind switchLiftToDecon s = overridePlaceKind overrideDeconLift $ s- { psymbol = 'd'- , pfreq = renameFreqs ("decon" <+>) $ pfreq s+ { pfreq = renameFreqs ("decon" <+>) $ pfreq s } @@ -1798,10 +1775,9 @@ [ ('<', WELDED_STAIRCASE_UP), ('>', ORDINARY_STAIRCASE_DOWN) , ('S', FILLER_WALL) ] -switchStaircaseToWelded :: PlaceKind -> PlaceKind-switchStaircaseToWelded s = overridePlaceKind overrideWeldedStaircase $ s- { psymbol = 'w'- , pfreq = renameFreqs ("welded" <+>) $ pfreq s+switchStairToWelded :: PlaceKind -> PlaceKind+switchStairToWelded s = overridePlaceKind overrideWeldedStaircase $ s+ { pfreq = renameFreqs ("welded" <+>) $ pfreq s } overrideWeldedLift :: [(Char, GroupName TileKind)]@@ -1811,8 +1787,7 @@ switchLiftToWelded :: PlaceKind -> PlaceKind switchLiftToWelded s = overridePlaceKind overrideWeldedLift $ s- { psymbol = 'w'- , pfreq = renameFreqs ("welded" <+>) $ pfreq s+ { pfreq = renameFreqs ("welded" <+>) $ pfreq s } @@ -1821,29 +1796,35 @@ [ ('<', STAIRCASE_OUTDOOR_UP), ('>', STAIRCASE_OUTDOOR_DOWN) , ('S', FILLER_WALL) ] -switchStaircaseToOutdoor :: PlaceKind -> PlaceKind-switchStaircaseToOutdoor s = overridePlaceKind overrideOutdoor $ s- { psymbol = 'o'- , pname = "an outdoor area exit"+switchStairToOutdoor :: PlaceKind -> PlaceKind+switchStairToOutdoor s = overridePlaceKind overrideOutdoor $ s+ { pname = "an outdoor area exit" , pfreq = renameFreqs ("outdoor" <+>) $ pfreq s } switchEscapeToUp :: PlaceKind -> PlaceKind-switchEscapeToUp s = overridePlaceKind [('>', ESCAPE_UP)] $ s- { psymbol = '<'- , pname = "an escape up"+switchEscapeToUp s = overridePlaceKind [('>', TILE_INDOOR_ESCAPE_UP)] $ s+ { pname = "an escape up" , pfreq = map (\(_, n) -> (INDOOR_ESCAPE_UP, n)) $ pfreq s } switchEscapeToOutdoorDown :: PlaceKind -> PlaceKind-switchEscapeToOutdoorDown s = overridePlaceKind [('>', ESCAPE_OUTDOOR_DOWN)] $ s+switchEscapeToOutdoorDown s = overridePlaceKind+ [('>', TILE_OUTDOOR_ESCAPE_DOWN)] $ s { pname = "outdoor escape route" , pfreq = map (\(_, n) -> (OUTDOOR_ESCAPE_DOWN, n)) $ pfreq s } switchEscapeToSpaceshipDown :: PlaceKind -> PlaceKind switchEscapeToSpaceshipDown s = overridePlaceKind- [('>', ESCAPE_SPACESHIP_DOWN)] $ s+ [('>', TILE_SPACESHIP_ESCAPE_DOWN)] $ s { pname = "escape from spaceship"- , pfreq = map (\(_, n) -> (ESCAPE_FROM_SPACESHIP_DOWN, n)) $ pfreq s+ , pfreq = map (\(_, n) -> (SPACESHIP_ESCAPE_DOWN, n)) $ pfreq s+ }++switchEscapeToAlarmUp :: PlaceKind -> PlaceKind+switchEscapeToAlarmUp s = overridePlaceKind+ [('>', TILE_ALARM_ESCAPE_UP)] $ s+ { pname = "alarm console"+ , pfreq = map (\(_, n) -> (ALARM_ESCAPE_UP, n)) $ pfreq s }
GameDefinition/Content/RuleKind.hs view
@@ -40,17 +40,17 @@ , rcfgUIDefault = $(do let path = "GameDefinition" </> "config.ui" <.> "default" qAddDependentFile path- s <- qRunIO $ do+ !s <- qRunIO $ do inputHandle <- openFile path ReadMode hSetEncoding inputHandle utf8 hGetContents inputHandle- let cfgUIDefault =+ let !cfgUIDefault = either (error . ("Ini.parse of default config" `showFailure`)) id $ Ini.parse s lift (s, cfgUIDefault)) , rwriteSaveClips = 1000 , rleadLevelClips = 50- , rscoresFile = "Allure.scores"+ , rscoresFileName = "Allure.scores" , rnearby = 30 , rstairWordCarried = ["staircase", "lift"] , ritemSymbols = ItemSymbolsUsedInEngine
GameDefinition/Content/TileKind.hs view
@@ -11,12 +11,12 @@ -- ** Used in CaveKind and perhaps elsewhere. pattern FILLER_WALL, pattern FLOOR_CORRIDOR_LIT, pattern FLOOR_CORRIDOR_DARK, pattern TRAIL_LIT, pattern SAFE_TRAIL_LIT, pattern LAB_TRAIL_LIT, pattern DAMP_FLOOR_LIT, pattern DAMP_FLOOR_DARK, pattern DIRT_LIT, pattern DIRT_DARK, pattern FLOOR_ARENA_LIT, pattern FLOOR_ARENA_DARK , pattern HABITAT_CONTAINMENT_WALL, pattern TRANSPORT_ROUTE, pattern ORIELS_FENCE, pattern AIRLOCK_FENCE, pattern EMPTY_AIRLOCK_FENCE, pattern OPENABLE_WALL, pattern TRAPPABLE_WALL, pattern OILY_FLOOR_LIT, pattern OILY_FLOOR_DARK- , pattern EMPTY_SET_LIT, pattern EMPTY_SET_DARK, pattern NOISE_SET_LIT, pattern POWER_SET_LIT, pattern POWER_SET_DARK, pattern BATTLE_SET_LIT, pattern BATTLE_SET_DARK, pattern BRAWL_SET_LIT, pattern SHOOTOUT_SET_LIT, pattern ZOO_SET_LIT, pattern ZOO_SET_DARK, pattern ESCAPE_SET_LIT, pattern ESCAPE_SET_DARK, pattern AMBUSH_SET_LIT, pattern AMBUSH_SET_DARK, pattern ARENA_SET_LIT, pattern ARENA_SET_DARK- , pattern ROGUE_SET, pattern MUSEUM_SET_LIT, pattern MUSEUM_SET_DARK, pattern HUNT_SET_LIT, pattern EXIT_SET_LIT+ , pattern EMPTY_SET_LIT, pattern EMPTY_SET_DARK, pattern NOISE_SET_LIT, pattern POWER_SET_LIT, pattern POWER_SET_DARK, pattern BATTLE_SET_LIT, pattern BATTLE_SET_DARK, pattern BRAWL_SET_LIT, pattern SHOOTOUT_SET_LIT, pattern ZOO_SET_LIT, pattern ZOO_SET_DARK, pattern FLIGHT_SET_LIT, pattern FLIGHT_SET_DARK, pattern AMBUSH_SET_LIT, pattern AMBUSH_SET_DARK, pattern ARENA_SET_LIT, pattern ARENA_SET_DARK+ , pattern ROGUE_SET, pattern MUSEUM_SET_LIT, pattern MUSEUM_SET_DARK, pattern HUNT_SET_LIT, pattern EGRESS_SET_LIT, pattern VIRUS_SET_LIT, pattern VIRUS_SET_DARK -- ** Used in PlaceKind, but not in CaveKind.- , pattern TREE_SHADE_WALKABLE_LIT, pattern TREE_SHADE_WALKABLE_DARK, pattern SMOKE_CLUMP_LIT, pattern SMOKE_CLUMP_DARK, pattern BUSH_CLUMP_LIT, pattern BUSH_CLUMP_DARK, pattern FOG_CLUMP_LIT, pattern FOG_CLUMP_DARK, pattern STAIR_TERMINAL_LIT, pattern STAIR_TERMINAL_DARK, pattern SIGNBOARD, pattern STAIRCASE_UP, pattern ORDINARY_STAIRCASE_UP, pattern STAIRCASE_OUTDOOR_UP, pattern GATED_STAIRCASE_UP, pattern STAIRCASE_DOWN, pattern ORDINARY_STAIRCASE_DOWN, pattern STAIRCASE_OUTDOOR_DOWN, pattern GATED_STAIRCASE_DOWN, pattern ESCAPE_UP, pattern ESCAPE_DOWN, pattern ESCAPE_OUTDOOR_DOWN, pattern TRANSPARENT_WALL, pattern ICE_BUILDUP, pattern WORKSHOP, pattern FLOOR_ACTOR_ITEM, pattern FLOOR_ACTOR_ITEM_LIT, pattern FLOOR_ACTOR_ITEM_DARK+ , pattern TREE_SHADE_WALKABLE_LIT, pattern TREE_SHADE_WALKABLE_DARK, pattern SMOKE_CLUMP_LIT, pattern SMOKE_CLUMP_DARK, pattern BUSH_CLUMP_LIT, pattern BUSH_CLUMP_DARK, pattern FOG_CLUMP_LIT, pattern FOG_CLUMP_DARK, pattern STAIR_TERMINAL_LIT, pattern STAIR_TERMINAL_DARK, pattern SIGNBOARD, pattern STAIRCASE_UP, pattern ORDINARY_STAIRCASE_UP, pattern STAIRCASE_OUTDOOR_UP, pattern GATED_STAIRCASE_UP, pattern STAIRCASE_DOWN, pattern ORDINARY_STAIRCASE_DOWN, pattern STAIRCASE_OUTDOOR_DOWN, pattern GATED_STAIRCASE_DOWN, pattern TILE_INDOOR_ESCAPE_UP, pattern TILE_INDOOR_ESCAPE_DOWN, pattern TILE_OUTDOOR_ESCAPE_DOWN, pattern TRANSPARENT_WALL, pattern ICE_BUILDUP, pattern WORKSHOP, pattern FLOOR_ACTOR_ITEM, pattern FLOOR_ACTOR_ITEM_LIT, pattern FLOOR_ACTOR_ITEM_DARK , pattern S_PILLAR, pattern S_RUBBLE_PILE, pattern S_LAMP_POST, pattern S_TREE_LIT, pattern S_TREE_DARK, pattern S_PULPIT, pattern S_BUSH_LIT, pattern S_FOG_LIT, pattern S_SMOKE_LIT, pattern S_FLOOR_ACTOR_LIT, pattern S_FLOOR_ACTOR_DARK, pattern S_FLOOR_ASHES_LIT, pattern S_FLOOR_ASHES_DARK, pattern S_SHADED_GROUND, pattern S_SHALLOW_WATER_LIT, pattern S_SHALLOW_WATER_DARK- , pattern BUSH_GROVE_LIT, pattern BUSH_GROVE_DARK, pattern UNDERBRUSH_CLUMP_LIT, pattern UNDERBRUSH_CLUMP_DARK, pattern ASHES_SMOKE_LIT, pattern ASHES_SMOKE_DARK, pattern RECT_WINDOWS, pattern DOORLESS_MACHINERY, pattern PUMPS_LIT, pattern PUMPS_DARK, pattern DOORLESS_WALL, pattern OIL_RESIDUE_LIT, pattern OIL_RESIDUE_DARK, pattern LIFT_TERMINAL_LIT, pattern LIFT_TERMINAL_DARK, pattern STAIRCASE_LIFT_UP, pattern STAIRCASE_LIFT_DOWN, pattern GATED_LIFT_UP, pattern GATED_LIFT_DOWN, pattern DECON_STAIRCASE_UP, pattern DECON_STAIRCASE_DOWN, pattern DECON_LIFT_UP, pattern DECON_LIFT_DOWN, pattern WELDED_STAIRCASE_UP, pattern WELDED_LIFT_UP, pattern ESCAPE_SPACESHIP_DOWN, pattern ORDINARY_LIFT_UP, pattern ORDINARY_LIFT_DOWN, pattern RUBBLE_OR_WASTE_LIT, pattern RUBBLE_OR_WASTE_DARK, pattern CACHE_DEPOSIT, pattern CACHE_JEWELRY, pattern CACHE_MAZE, pattern CACHE_SHUTTLE, pattern TRAPPED_DOOR, pattern STUCK_DOOR, pattern BARREL+ , pattern BUSH_GROVE_LIT, pattern BUSH_GROVE_DARK, pattern UNDERBRUSH_CLUMP_LIT, pattern UNDERBRUSH_CLUMP_DARK, pattern ASHES_SMOKE_LIT, pattern ASHES_SMOKE_DARK, pattern RECT_WINDOWS, pattern DOORLESS_MACHINERY, pattern PUMPS_LIT, pattern PUMPS_DARK, pattern DOORLESS_WALL, pattern OIL_RESIDUE_LIT, pattern OIL_RESIDUE_DARK, pattern LIFT_TERMINAL_LIT, pattern LIFT_TERMINAL_DARK, pattern STAIRCASE_LIFT_UP, pattern STAIRCASE_LIFT_DOWN, pattern GATED_LIFT_UP, pattern GATED_LIFT_DOWN, pattern DECON_STAIRCASE_UP, pattern DECON_STAIRCASE_DOWN, pattern DECON_LIFT_UP, pattern DECON_LIFT_DOWN, pattern WELDED_STAIRCASE_UP, pattern WELDED_LIFT_UP, pattern TILE_ALARM_ESCAPE_UP, pattern TILE_SPACESHIP_ESCAPE_DOWN, pattern ORDINARY_LIFT_UP, pattern ORDINARY_LIFT_DOWN, pattern RUBBLE_OR_WASTE_LIT, pattern RUBBLE_OR_WASTE_DARK, pattern CACHE_DEPOSIT, pattern CACHE_JEWELRY, pattern CACHE_MAZE, pattern CACHE_SHUTTLE, pattern TRAPPED_DOOR, pattern STUCK_DOOR, pattern BARREL , pattern S_POOL_LIT, pattern S_POOL_DARK, pattern S_CLOSED_DOOR, pattern S_OPEN_DOOR, pattern S_OIL_SPILL, pattern S_FROZEN_PATH, pattern S_LIFT_SHAFT, pattern S_REINFORCED_WALL, pattern S_SHUTTLE_HULL, pattern S_HARDWARE_RACK, pattern S_STAIRCASE_TRAP_DOWN_OIL, pattern S_UNDERBRUSH_LIT, pattern S_UNDERBRUSH_DARK , groupNamesSingleton, groupNames -- * Content@@ -29,15 +29,16 @@ import qualified Data.Text as T -import Content.ItemKindActor-import Content.ItemKindBlast-import Content.ItemKindEmbed-import Content.ItemKindOrgan import Game.LambdaHack.Content.TileKind import Game.LambdaHack.Definition.Color import Game.LambdaHack.Definition.Defs import Game.LambdaHack.Definition.DefsInternal +import Content.ItemKindActor+import Content.ItemKindBlast+import Content.ItemKindEmbed+import Content.ItemKindOrgan+ -- * Group name patterns -- Warning, many of these are also sythesized, so typos can happen.@@ -72,29 +73,29 @@ [AQUATIC] ++ [FILLER_WALL, FLOOR_CORRIDOR_LIT, FLOOR_CORRIDOR_DARK, TRAIL_LIT, SAFE_TRAIL_LIT, LAB_TRAIL_LIT, DAMP_FLOOR_LIT, DAMP_FLOOR_DARK, DIRT_LIT, DIRT_DARK, FLOOR_ARENA_LIT, FLOOR_ARENA_DARK] ++ [HABITAT_CONTAINMENT_WALL, TRANSPORT_ROUTE, ORIELS_FENCE, AIRLOCK_FENCE, EMPTY_AIRLOCK_FENCE, OPENABLE_WALL, TRAPPABLE_WALL, OILY_FLOOR_LIT, OILY_FLOOR_DARK]- ++ [EMPTY_SET_LIT, EMPTY_SET_DARK, NOISE_SET_LIT, POWER_SET_LIT, POWER_SET_DARK, BATTLE_SET_LIT, BATTLE_SET_DARK, BRAWL_SET_LIT, SHOOTOUT_SET_LIT, ZOO_SET_LIT, ZOO_SET_DARK, ESCAPE_SET_LIT, ESCAPE_SET_DARK, AMBUSH_SET_LIT, AMBUSH_SET_DARK, ARENA_SET_LIT, ARENA_SET_DARK]- ++ [ROGUE_SET, MUSEUM_SET_LIT, MUSEUM_SET_DARK, HUNT_SET_LIT, EXIT_SET_LIT]- ++ [TREE_SHADE_WALKABLE_LIT, TREE_SHADE_WALKABLE_DARK, SMOKE_CLUMP_LIT, SMOKE_CLUMP_DARK, BUSH_CLUMP_LIT, BUSH_CLUMP_DARK, FOG_CLUMP_LIT, FOG_CLUMP_DARK, STAIR_TERMINAL_LIT, STAIR_TERMINAL_DARK, SIGNBOARD, STAIRCASE_UP, ORDINARY_STAIRCASE_UP, STAIRCASE_OUTDOOR_UP, GATED_STAIRCASE_UP, STAIRCASE_DOWN, ORDINARY_STAIRCASE_DOWN, STAIRCASE_OUTDOOR_DOWN, GATED_STAIRCASE_DOWN, ESCAPE_UP, ESCAPE_DOWN, ESCAPE_OUTDOOR_DOWN, TRANSPARENT_WALL, ICE_BUILDUP, WORKSHOP, FLOOR_ACTOR_ITEM, FLOOR_ACTOR_ITEM_LIT, FLOOR_ACTOR_ITEM_DARK]- ++ [BUSH_GROVE_LIT, BUSH_GROVE_DARK, UNDERBRUSH_CLUMP_LIT, UNDERBRUSH_CLUMP_DARK, ASHES_SMOKE_LIT, ASHES_SMOKE_DARK, RECT_WINDOWS, DOORLESS_MACHINERY, PUMPS_LIT, PUMPS_DARK, DOORLESS_WALL, OIL_RESIDUE_LIT, OIL_RESIDUE_DARK, LIFT_TERMINAL_LIT, LIFT_TERMINAL_DARK, STAIRCASE_LIFT_UP, STAIRCASE_LIFT_DOWN, GATED_LIFT_UP, GATED_LIFT_DOWN, DECON_STAIRCASE_UP, DECON_STAIRCASE_DOWN, DECON_LIFT_UP, DECON_LIFT_DOWN, WELDED_STAIRCASE_UP, WELDED_LIFT_UP, ESCAPE_SPACESHIP_DOWN, ORDINARY_LIFT_UP, ORDINARY_LIFT_DOWN, RUBBLE_OR_WASTE_LIT, RUBBLE_OR_WASTE_DARK, CACHE_DEPOSIT, CACHE_JEWELRY, CACHE_MAZE, CACHE_SHUTTLE, TRAPPED_DOOR, STUCK_DOOR, BARREL]+ ++ [EMPTY_SET_LIT, EMPTY_SET_DARK, NOISE_SET_LIT, POWER_SET_LIT, POWER_SET_DARK, BATTLE_SET_LIT, BATTLE_SET_DARK, BRAWL_SET_LIT, SHOOTOUT_SET_LIT, ZOO_SET_LIT, ZOO_SET_DARK, FLIGHT_SET_LIT, FLIGHT_SET_DARK, AMBUSH_SET_LIT, AMBUSH_SET_DARK, ARENA_SET_LIT, ARENA_SET_DARK]+ ++ [ROGUE_SET, MUSEUM_SET_LIT, MUSEUM_SET_DARK, HUNT_SET_LIT, EGRESS_SET_LIT, VIRUS_SET_LIT, VIRUS_SET_DARK]+ ++ [TREE_SHADE_WALKABLE_LIT, TREE_SHADE_WALKABLE_DARK, SMOKE_CLUMP_LIT, SMOKE_CLUMP_DARK, BUSH_CLUMP_LIT, BUSH_CLUMP_DARK, FOG_CLUMP_LIT, FOG_CLUMP_DARK, STAIR_TERMINAL_LIT, STAIR_TERMINAL_DARK, SIGNBOARD, STAIRCASE_UP, ORDINARY_STAIRCASE_UP, STAIRCASE_OUTDOOR_UP, GATED_STAIRCASE_UP, STAIRCASE_DOWN, ORDINARY_STAIRCASE_DOWN, STAIRCASE_OUTDOOR_DOWN, GATED_STAIRCASE_DOWN, TILE_INDOOR_ESCAPE_UP, TILE_INDOOR_ESCAPE_DOWN, TILE_OUTDOOR_ESCAPE_DOWN, TRANSPARENT_WALL, ICE_BUILDUP, WORKSHOP, FLOOR_ACTOR_ITEM, FLOOR_ACTOR_ITEM_LIT, FLOOR_ACTOR_ITEM_DARK]+ ++ [BUSH_GROVE_LIT, BUSH_GROVE_DARK, UNDERBRUSH_CLUMP_LIT, UNDERBRUSH_CLUMP_DARK, ASHES_SMOKE_LIT, ASHES_SMOKE_DARK, RECT_WINDOWS, DOORLESS_MACHINERY, PUMPS_LIT, PUMPS_DARK, DOORLESS_WALL, OIL_RESIDUE_LIT, OIL_RESIDUE_DARK, LIFT_TERMINAL_LIT, LIFT_TERMINAL_DARK, STAIRCASE_LIFT_UP, STAIRCASE_LIFT_DOWN, GATED_LIFT_UP, GATED_LIFT_DOWN, DECON_STAIRCASE_UP, DECON_STAIRCASE_DOWN, DECON_LIFT_UP, DECON_LIFT_DOWN, WELDED_STAIRCASE_UP, WELDED_LIFT_UP, TILE_ALARM_ESCAPE_UP, TILE_SPACESHIP_ESCAPE_DOWN, ORDINARY_LIFT_UP, ORDINARY_LIFT_DOWN, RUBBLE_OR_WASTE_LIT, RUBBLE_OR_WASTE_DARK, CACHE_DEPOSIT, CACHE_JEWELRY, CACHE_MAZE, CACHE_SHUTTLE, TRAPPED_DOOR, STUCK_DOOR, BARREL] ++ [TREE_BURNING_OR_NOT, BUSH_BURNING_OR_NOT] ++ [OBSCURED_WALL, CACHE_DEPOSIT_OR_NOT, CACHE_DEPOSIT_BREACHED, CACHE_JEWELRY_OR_NOT, CACHE_JEWELRY_TRAPPED_OR_NOT, CACHE_ABANDONED_OR_NOT, RUBBLE_BURNING_OR_NOT]- ++ [BRAWL_SET_DARK, NOISE_SET_DARK, SHOOTOUT_SET_DARK, EXIT_SET_DARK, HUNT_SET_DARK]+ ++ [BRAWL_SET_DARK, NOISE_SET_DARK, SHOOTOUT_SET_DARK, EGRESS_SET_DARK, HUNT_SET_DARK] pattern FILLER_WALL, FLOOR_CORRIDOR_LIT, FLOOR_CORRIDOR_DARK, TRAIL_LIT, SAFE_TRAIL_LIT, LAB_TRAIL_LIT, DAMP_FLOOR_LIT, DAMP_FLOOR_DARK, DIRT_LIT, DIRT_DARK, FLOOR_ARENA_LIT, FLOOR_ARENA_DARK :: GroupName TileKind -- ** Allure-specific pattern HABITAT_CONTAINMENT_WALL, TRANSPORT_ROUTE, ORIELS_FENCE, AIRLOCK_FENCE, EMPTY_AIRLOCK_FENCE, OPENABLE_WALL, TRAPPABLE_WALL, OILY_FLOOR_LIT, OILY_FLOOR_DARK :: GroupName TileKind -pattern EMPTY_SET_LIT, EMPTY_SET_DARK, NOISE_SET_LIT, POWER_SET_LIT, POWER_SET_DARK, BATTLE_SET_LIT, BATTLE_SET_DARK, BRAWL_SET_LIT, SHOOTOUT_SET_LIT, ZOO_SET_LIT, ZOO_SET_DARK, ESCAPE_SET_LIT, ESCAPE_SET_DARK, AMBUSH_SET_LIT, AMBUSH_SET_DARK, ARENA_SET_LIT, ARENA_SET_DARK :: GroupName TileKind+pattern EMPTY_SET_LIT, EMPTY_SET_DARK, NOISE_SET_LIT, POWER_SET_LIT, POWER_SET_DARK, BATTLE_SET_LIT, BATTLE_SET_DARK, BRAWL_SET_LIT, SHOOTOUT_SET_LIT, ZOO_SET_LIT, ZOO_SET_DARK, FLIGHT_SET_LIT, FLIGHT_SET_DARK, AMBUSH_SET_LIT, AMBUSH_SET_DARK, ARENA_SET_LIT, ARENA_SET_DARK :: GroupName TileKind -- ** Allure-specific-pattern ROGUE_SET, MUSEUM_SET_LIT, MUSEUM_SET_DARK, HUNT_SET_LIT, EXIT_SET_LIT :: GroupName TileKind+pattern ROGUE_SET, MUSEUM_SET_LIT, MUSEUM_SET_DARK, HUNT_SET_LIT, EGRESS_SET_LIT, VIRUS_SET_LIT, VIRUS_SET_DARK :: GroupName TileKind -- ** Used in PlaceKind, but not in CaveKind.-pattern TREE_SHADE_WALKABLE_LIT, TREE_SHADE_WALKABLE_DARK, SMOKE_CLUMP_LIT, SMOKE_CLUMP_DARK, BUSH_CLUMP_LIT, BUSH_CLUMP_DARK, FOG_CLUMP_LIT, FOG_CLUMP_DARK, STAIR_TERMINAL_LIT, STAIR_TERMINAL_DARK, SIGNBOARD, STAIRCASE_UP, ORDINARY_STAIRCASE_UP, STAIRCASE_OUTDOOR_UP, GATED_STAIRCASE_UP, STAIRCASE_DOWN, ORDINARY_STAIRCASE_DOWN, STAIRCASE_OUTDOOR_DOWN, GATED_STAIRCASE_DOWN, ESCAPE_UP, ESCAPE_DOWN, ESCAPE_OUTDOOR_DOWN, TRANSPARENT_WALL, ICE_BUILDUP, WORKSHOP, FLOOR_ACTOR_ITEM, FLOOR_ACTOR_ITEM_LIT, FLOOR_ACTOR_ITEM_DARK :: GroupName TileKind+pattern TREE_SHADE_WALKABLE_LIT, TREE_SHADE_WALKABLE_DARK, SMOKE_CLUMP_LIT, SMOKE_CLUMP_DARK, BUSH_CLUMP_LIT, BUSH_CLUMP_DARK, FOG_CLUMP_LIT, FOG_CLUMP_DARK, STAIR_TERMINAL_LIT, STAIR_TERMINAL_DARK, SIGNBOARD, STAIRCASE_UP, ORDINARY_STAIRCASE_UP, STAIRCASE_OUTDOOR_UP, GATED_STAIRCASE_UP, STAIRCASE_DOWN, ORDINARY_STAIRCASE_DOWN, STAIRCASE_OUTDOOR_DOWN, GATED_STAIRCASE_DOWN, TILE_INDOOR_ESCAPE_UP, TILE_INDOOR_ESCAPE_DOWN, TILE_OUTDOOR_ESCAPE_DOWN, TRANSPARENT_WALL, ICE_BUILDUP, WORKSHOP, FLOOR_ACTOR_ITEM, FLOOR_ACTOR_ITEM_LIT, FLOOR_ACTOR_ITEM_DARK :: GroupName TileKind -- ** Allure-specific-pattern BUSH_GROVE_LIT, BUSH_GROVE_DARK, UNDERBRUSH_CLUMP_LIT, UNDERBRUSH_CLUMP_DARK, ASHES_SMOKE_LIT, ASHES_SMOKE_DARK, RECT_WINDOWS, DOORLESS_MACHINERY, PUMPS_LIT, PUMPS_DARK, DOORLESS_WALL, OIL_RESIDUE_LIT, OIL_RESIDUE_DARK, LIFT_TERMINAL_LIT, LIFT_TERMINAL_DARK, STAIRCASE_LIFT_UP, STAIRCASE_LIFT_DOWN, GATED_LIFT_UP, GATED_LIFT_DOWN, DECON_STAIRCASE_UP, DECON_STAIRCASE_DOWN, DECON_LIFT_UP, DECON_LIFT_DOWN, WELDED_STAIRCASE_UP, WELDED_LIFT_UP, ESCAPE_SPACESHIP_DOWN, ORDINARY_LIFT_UP, ORDINARY_LIFT_DOWN, RUBBLE_OR_WASTE_LIT, RUBBLE_OR_WASTE_DARK, CACHE_DEPOSIT, CACHE_JEWELRY, CACHE_MAZE, CACHE_SHUTTLE, TRAPPED_DOOR, STUCK_DOOR, BARREL :: GroupName TileKind+pattern BUSH_GROVE_LIT, BUSH_GROVE_DARK, UNDERBRUSH_CLUMP_LIT, UNDERBRUSH_CLUMP_DARK, ASHES_SMOKE_LIT, ASHES_SMOKE_DARK, RECT_WINDOWS, DOORLESS_MACHINERY, PUMPS_LIT, PUMPS_DARK, DOORLESS_WALL, OIL_RESIDUE_LIT, OIL_RESIDUE_DARK, LIFT_TERMINAL_LIT, LIFT_TERMINAL_DARK, STAIRCASE_LIFT_UP, STAIRCASE_LIFT_DOWN, GATED_LIFT_UP, GATED_LIFT_DOWN, DECON_STAIRCASE_UP, DECON_STAIRCASE_DOWN, DECON_LIFT_UP, DECON_LIFT_DOWN, WELDED_STAIRCASE_UP, WELDED_LIFT_UP, TILE_ALARM_ESCAPE_UP, TILE_SPACESHIP_ESCAPE_DOWN, ORDINARY_LIFT_UP, ORDINARY_LIFT_DOWN, RUBBLE_OR_WASTE_LIT, RUBBLE_OR_WASTE_DARK, CACHE_DEPOSIT, CACHE_JEWELRY, CACHE_MAZE, CACHE_SHUTTLE, TRAPPED_DOOR, STUCK_DOOR, BARREL :: GroupName TileKind -- ** Used only internally in other TileKind definitions or never used. pattern TREE_BURNING_OR_NOT, BUSH_BURNING_OR_NOT :: GroupName TileKind@@ -103,7 +104,7 @@ pattern OBSCURED_WALL, CACHE_DEPOSIT_OR_NOT, CACHE_DEPOSIT_BREACHED, CACHE_JEWELRY_OR_NOT, CACHE_JEWELRY_TRAPPED_OR_NOT, CACHE_ABANDONED_OR_NOT, RUBBLE_BURNING_OR_NOT :: GroupName TileKind -- * Not used, but needed, because auto-generated. Not singletons.-pattern BRAWL_SET_DARK, NOISE_SET_DARK, SHOOTOUT_SET_DARK, EXIT_SET_DARK, HUNT_SET_DARK :: GroupName TileKind+pattern BRAWL_SET_DARK, NOISE_SET_DARK, SHOOTOUT_SET_DARK, EGRESS_SET_DARK, HUNT_SET_DARK :: GroupName TileKind -- ** Used in CaveKind and perhaps elsewhere (or a dark/lit version thereof). pattern FILLER_WALL = GroupName "fillerWall"@@ -145,8 +146,8 @@ pattern SHOOTOUT_SET_LIT = GroupName "shootoutSetLit" pattern ZOO_SET_LIT = GroupName "zooSetLit" pattern ZOO_SET_DARK = GroupName "zooSetDark"-pattern ESCAPE_SET_LIT = GroupName "escapeSetLit"-pattern ESCAPE_SET_DARK = GroupName "escapeSetDark"+pattern FLIGHT_SET_LIT = GroupName "flightSetLit"+pattern FLIGHT_SET_DARK = GroupName "flightSetDark" pattern AMBUSH_SET_LIT = GroupName "ambushSetLit" pattern AMBUSH_SET_DARK = GroupName "ambushSetDark" pattern ARENA_SET_LIT = GroupName "arenaSetLit"@@ -157,7 +158,9 @@ pattern MUSEUM_SET_LIT = GroupName "museumSetLit" pattern MUSEUM_SET_DARK = GroupName "museumSetDark" pattern HUNT_SET_LIT = GroupName "huntSetLit"-pattern EXIT_SET_LIT = GroupName "exitSetLit"+pattern EGRESS_SET_LIT = GroupName "egressSetLit"+pattern VIRUS_SET_LIT = GroupName "virusSetLit"+pattern VIRUS_SET_DARK = GroupName "virusSetDark" -- ** Used in PlaceKind, but not in CaveKind. Not singletons. pattern TREE_SHADE_WALKABLE_LIT = GroupName "treeShadeWalkableLit"@@ -179,9 +182,9 @@ pattern ORDINARY_STAIRCASE_DOWN = GroupName "ordinary staircase down" pattern STAIRCASE_OUTDOOR_DOWN = GroupName "staircase outdoor down" pattern GATED_STAIRCASE_DOWN = GroupName "gated staircase down"-pattern ESCAPE_UP = GroupName "escape up"-pattern ESCAPE_DOWN = GroupName "escape down"-pattern ESCAPE_OUTDOOR_DOWN = GroupName "escape outdoor down"+pattern TILE_INDOOR_ESCAPE_UP = GroupName "indoor escape up"+pattern TILE_INDOOR_ESCAPE_DOWN = GroupName "indoor escape down"+pattern TILE_OUTDOOR_ESCAPE_DOWN = GroupName "outdoor escape down" pattern TRANSPARENT_WALL = GroupName "transparent wall" pattern ICE_BUILDUP = GroupName "ice buildup" pattern WORKSHOP = GroupName "workshop"@@ -233,7 +236,8 @@ pattern DECON_LIFT_DOWN = GroupName "decon lift down" pattern WELDED_STAIRCASE_UP = GroupName "welded staircase up" pattern WELDED_LIFT_UP = GroupName "welded lift up"-pattern ESCAPE_SPACESHIP_DOWN = GroupName "escape spaceship down"+pattern TILE_ALARM_ESCAPE_UP = GroupName "alarm escape up"+pattern TILE_SPACESHIP_ESCAPE_DOWN = GroupName "spaceship escape down" pattern ORDINARY_LIFT_UP = GroupName "ordinary lift up" pattern ORDINARY_LIFT_DOWN = GroupName "ordinary lift down" pattern RUBBLE_OR_WASTE_LIT = GroupName "rubbleOrWaste_Lit"@@ -290,7 +294,7 @@ pattern BRAWL_SET_DARK = GroupName "brawlSetDark" pattern NOISE_SET_DARK = GroupName "noiseSetDark" pattern SHOOTOUT_SET_DARK = GroupName "shootoutSetDark"-pattern EXIT_SET_DARK = GroupName "exitSetDark"+pattern EGRESS_SET_DARK = GroupName "egressSetDark" pattern HUNT_SET_DARK = GroupName "huntSetDark" -- * Not used, but needed, because auto-generated. Singletons.@@ -303,11 +307,11 @@ [unknown, unknownOuterFence, basicOuterFence, bedrock, wall, wallSuspect, wallObscured, wallObscuredDefaced, wallObscuredFrescoed, pillar, pillarCache, lampPost, signboardUnread, signboardRead, treeLit, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTrappedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTrappedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bushLit, bushBurnt, bushBurning, fog, fogDark, smoke, smokeDark, doorOpen, floorCorridor, floorArena, floorDamp, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorAshes, shallowWater, shallowWaterSpice, shallowWater2, floorRed, floorBlue, floorBrown, floorArenaShade ] ++ map makeDarkColor ldarkColorable -- Allure-specific- ++ [oriel, outerHullWall, rubbleBurning, rubbleBurningSpice, wallOpenable, wallObscuredSafety, signboardReadExtinguisher, wallObscured3dBillboard, wallObscuredPipework, wallObscuredScary, liftShaft, rock, pillarCache2, pillarCache3, pillarCache4, pillarCache5, stairsTrappedDownOil, stairsDecontaminatingUp, stairsWelded, stairsLiftUp, stairsLiftTrappedUp, stairsLiftGatedUp, stairsLiftDecontaminatingUp, stairsLiftWelded, stairsDecontaminatingDown, stairsLiftDown, stairsLiftTrappedDown, stairsLiftGatedDown, stairsLiftDecontaminatingDown, escapeSpaceshipDown, emptyAirlock, reinforcedWall, reinforcedWallSpice, wallShuttle, wallShuttleSpice, doorStuck, barrel, barrelSpice, machineWall, machineWallSpice, bushEdible, bushEdibleSpice, underbrushBurning, floorOily, oilSpill, oilSpillSpice, oilBurning, floorWindow, underbrush, workshop]+ ++ [oriel, outerHullWall, rubbleBurning, rubbleBurningSpice, wallOpenable, wallObscuredSafety, signboardReadExtinguisher, wallObscured3dBillboard, wallObscuredPipework, wallObscuredScary, liftShaft, rock, pillarCache2, pillarCache3, pillarCache4, pillarCache5, stairsTrappedDownOil, stairsDecontaminatingUp, stairsWelded, stairsLiftUp, stairsLiftTrappedUp, stairsLiftGatedUp, stairsLiftDecontaminatingUp, stairsLiftWelded, stairsDecontaminatingDown, stairsLiftDown, stairsLiftTrappedDown, stairsLiftGatedDown, stairsLiftDecontaminatingDown, escapeAlarmUp, escapeSpaceshipDown, emptyAirlock, reinforcedWall, reinforcedWallSpice, wallShuttle, wallShuttleSpice, doorStuck, barrel, barrelSpice, machineWall, machineWallSpice, bushEdible, bushEdibleSpice, underbrushBurning, floorOily, oilSpill, oilSpillSpice, oilBurning, floorWindow, underbrush, workshop] unknown, unknownOuterFence, basicOuterFence, bedrock, wall, wallSuspect, wallObscured, wallObscuredDefaced, wallObscuredFrescoed, pillar, pillarCache, lampPost, signboardUnread, signboardRead, treeLit, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, stairsUp, stairsTrappedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTrappedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, pillarIce, pulpit, bushLit, bushBurnt, bushBurning, fog, fogDark, smoke, smokeDark, doorOpen, floorCorridor, floorArena, floorDamp, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorAshes, shallowWater, shallowWaterSpice, shallowWater2, floorRed, floorBlue, floorBrown, floorArenaShade :: TileKind -- Allure-specific-oriel, outerHullWall, rubbleBurning, rubbleBurningSpice, wallOpenable, wallObscuredSafety, signboardReadExtinguisher, wallObscured3dBillboard, wallObscuredPipework, wallObscuredScary, liftShaft, rock, pillarCache2, pillarCache3, pillarCache4, pillarCache5, stairsTrappedDownOil, stairsDecontaminatingUp, stairsWelded, stairsLiftUp, stairsLiftTrappedUp, stairsLiftGatedUp, stairsLiftDecontaminatingUp, stairsLiftWelded, stairsDecontaminatingDown, stairsLiftDown, stairsLiftTrappedDown, stairsLiftGatedDown, stairsLiftDecontaminatingDown, escapeSpaceshipDown, emptyAirlock, reinforcedWall, reinforcedWallSpice, wallShuttle, wallShuttleSpice, doorStuck, barrel, barrelSpice, machineWall, machineWallSpice, bushEdible, bushEdibleSpice, underbrushBurning, floorOily, oilSpill, oilSpillSpice, oilBurning, floorWindow, underbrush, workshop :: TileKind+oriel, outerHullWall, rubbleBurning, rubbleBurningSpice, wallOpenable, wallObscuredSafety, signboardReadExtinguisher, wallObscured3dBillboard, wallObscuredPipework, wallObscuredScary, liftShaft, rock, pillarCache2, pillarCache3, pillarCache4, pillarCache5, stairsTrappedDownOil, stairsDecontaminatingUp, stairsWelded, stairsLiftUp, stairsLiftTrappedUp, stairsLiftGatedUp, stairsLiftDecontaminatingUp, stairsLiftWelded, stairsDecontaminatingDown, stairsLiftDown, stairsLiftTrappedDown, stairsLiftGatedDown, stairsLiftDecontaminatingDown, escapeAlarmUp, escapeSpaceshipDown, emptyAirlock, reinforcedWall, reinforcedWallSpice, wallShuttle, wallShuttleSpice, doorStuck, barrel, barrelSpice, machineWall, machineWallSpice, bushEdible, bushEdibleSpice, underbrushBurning, floorOily, oilSpill, oilSpillSpice, oilBurning, floorWindow, underbrush, workshop :: TileKind ldarkColorable :: [TileKind] ldarkColorable = [treeLit, bushLit, floorCorridor, floorArena, floorDamp, floorDirt, floorDirtSpice, floorActor, floorActorItem, shallowWater, shallowWaterSpice, shallowWater2, floorOily]@@ -372,7 +376,7 @@ , tfreq = [ (FILLER_WALL, 1) , (ROGUE_SET, 60), (MUSEUM_SET_DARK, 4), (NOISE_SET_LIT, 450) , (POWER_SET_DARK, 450), (BATTLE_SET_DARK, 250)- , (ESCAPE_SET_DARK, 4)+ , (FLIGHT_SET_DARK, 4) , (STAIR_TERMINAL_LIT, 100), (STAIR_TERMINAL_DARK, 100) , (DOORLESS_WALL, 80), (DOORLESS_MACHINERY, 1) ] , tcolor = BrWhite@@ -409,7 +413,7 @@ wallObscuredDefaced = TileKind { tsymbol = '#' , tname = "defaced wall"- , tfreq = [ (OBSCURED_WALL, 25), (ESCAPE_SET_DARK, 2)+ , tfreq = [ (OBSCURED_WALL, 25), (FLIGHT_SET_DARK, 2) , (MUSEUM_SET_DARK, 2) ] , tcolor = BrWhite , tcolor2 = defFG@@ -484,7 +488,7 @@ , tname = "signboard" , tfreq = [ (SIGNBOARD, 80), (EMPTY_SET_LIT, 7) , (ARENA_SET_LIT, 1), (ARENA_SET_DARK, 2), (MUSEUM_SET_DARK, 1)- , (ESCAPE_SET_DARK, 2) ]+ , (FLIGHT_SET_DARK, 2) ] , tcolor = BrCyan , tcolor2 = Cyan , talter = 5@@ -497,7 +501,7 @@ , tname = "tree" , tfreq = [ (ARENA_SET_LIT, 9), (EMPTY_SET_LIT, 4), (BRAWL_SET_LIT, 140) , (SHOOTOUT_SET_LIT, 10), (HUNT_SET_LIT, 10)- , (ESCAPE_SET_LIT, 35), (ZOO_SET_DARK, 20)+ , (FLIGHT_SET_LIT, 35), (ZOO_SET_DARK, 20) , (S_TREE_LIT, 1) ] , tcolor = BrGreen , tcolor2 = Green@@ -533,7 +537,7 @@ , tfreq = [ (S_RUBBLE_PILE, 1), (RUBBLE_BURNING_OR_NOT, 50) , (STAIR_TERMINAL_LIT, 6), (STAIR_TERMINAL_DARK, 6) , (LIFT_TERMINAL_LIT, 6), (LIFT_TERMINAL_DARK, 6)- , (EMPTY_SET_LIT, 12), (EXIT_SET_LIT, 6)+ , (EMPTY_SET_LIT, 12), (EGRESS_SET_LIT, 6), (VIRUS_SET_DARK, 6) , (NOISE_SET_LIT, 40), (POWER_SET_DARK, 120) , (ZOO_SET_DARK, 150), (AMBUSH_SET_DARK, 3) ] , tcolor = BrYellow@@ -646,8 +650,8 @@ } escapeUp = TileKind { tsymbol = '<'- , tname = "exit hatch up"- , tfreq = [(ESCAPE_UP, 1)]+ , tname = "escape hatch up"+ , tfreq = [(TILE_INDOOR_ESCAPE_UP, 1)] , tcolor = BrYellow , tcolor2 = BrYellow , talter = 0 -- anybody can escape (or guard escape)@@ -655,16 +659,16 @@ } escapeDown = TileKind { tsymbol = '>'- , tname = "exit trapdoor down"- , tfreq = [(ESCAPE_DOWN, 1)]+ , tname = "escape trapdoor down"+ , tfreq = [(TILE_INDOOR_ESCAPE_DOWN, 1)] , tcolor = BrYellow , tcolor2 = BrYellow , talter = 0 -- anybody can escape (or guard escape) , tfeature = [Embed ESCAPE, ConsideredByAI] } escapeOutdoorDown = escapeDown- { tname = "exit back to town"- , tfreq = [(ESCAPE_OUTDOOR_DOWN, 1)]+ { tname = "escape back to town"+ , tfreq = [(TILE_OUTDOOR_ESCAPE_DOWN, 1)] } -- *** Clear@@ -718,7 +722,7 @@ , tname = "bush" , tfreq = [ (S_BUSH_LIT, 1), (EMPTY_SET_LIT, 8), (ARENA_SET_LIT, 13) , (BRAWL_SET_LIT, 5), (SHOOTOUT_SET_LIT, 30), (HUNT_SET_LIT, 30)- , (ESCAPE_SET_LIT, 40), (ZOO_SET_DARK, 100)+ , (FLIGHT_SET_LIT, 40), (ZOO_SET_DARK, 100) , (BUSH_CLUMP_LIT, 2), (BUSH_CLUMP_DARK, 2) -- always lit , (BUSH_GROVE_LIT, 5), (BUSH_GROVE_DARK, 5) -- always lit , (PUMPS_LIT, 300) -- dark in PUMPS_DARK@@ -778,7 +782,7 @@ } fogDark = fog -- always dark { tname = "thick fog"- , tfreq = [(ESCAPE_SET_DARK, 50), (LIFT_TERMINAL_DARK, 40)]+ , tfreq = [(FLIGHT_SET_DARK, 50), (LIFT_TERMINAL_DARK, 40)] , tfeature = Dark : tfeature fog } smoke = TileKind -- always lit@@ -788,7 +792,8 @@ , (STAIR_TERMINAL_LIT, 2), (LIFT_TERMINAL_LIT, 6) , (SMOKE_CLUMP_LIT, 3), (SMOKE_CLUMP_DARK, 3) , (ASHES_SMOKE_LIT, 1), (ASHES_SMOKE_DARK, 1)- , (EXIT_SET_LIT, 20), (AMBUSH_SET_DARK, 20) ]+ , (EGRESS_SET_LIT, 20), (VIRUS_SET_DARK, 30)+ , (AMBUSH_SET_DARK, 20) ] , tcolor = Brown , tcolor2 = BrBlack , talter = 0@@ -796,7 +801,7 @@ } smokeDark = smoke -- always dark { tname = "lingering smoke"- , tfreq = [ (POWER_SET_DARK, 100)+ , tfreq = [ (POWER_SET_DARK, 100), (VIRUS_SET_DARK, 30) , (ZOO_SET_DARK, 20), (AMBUSH_SET_DARK, 40), (BATTLE_SET_DARK, 5) , (STAIR_TERMINAL_DARK, 2), (LIFT_TERMINAL_DARK, 6) ] , tfeature = Dark : tfeature smoke@@ -827,12 +832,13 @@ floorArena = floorCorridor { tfreq = [ (FLOOR_ARENA_LIT, 1), (ARENA_SET_LIT, 400) , (MUSEUM_SET_LIT, 400), (NOISE_SET_LIT, 50), (POWER_SET_LIT, 50)- , (EMPTY_SET_LIT, 400), (EXIT_SET_LIT, 100), (ZOO_SET_LIT, 500) ]+ , (EMPTY_SET_LIT, 400), (EGRESS_SET_LIT, 100), (VIRUS_SET_LIT, 80)+ , (ZOO_SET_LIT, 500) ] } floorDamp = floorArena { tname = "damp floor" , tfreq = [ (NOISE_SET_LIT, 550), (EMPTY_SET_LIT, 3000)- , (ESCAPE_SET_LIT, 300), (DAMP_FLOOR_LIT, 1)+ , (FLIGHT_SET_LIT, 300), (DAMP_FLOOR_LIT, 1) , (STAIR_TERMINAL_LIT, 20), (LIFT_TERMINAL_LIT, 6) ] , tfeature = ChangeWith ProjYes [(1, OIL_SOURCE)] S_OIL_SPILL -- oil floats : ChangeWith ProjYes [(1, COLD_SOURCE)] S_FROZEN_PATH@@ -842,7 +848,7 @@ floorDirt = floorArena { tname = "dirt floor" , tfreq = [ (BRAWL_SET_LIT, 900), (SHOOTOUT_SET_LIT, 900)- , (HUNT_SET_LIT, 900), (ESCAPE_SET_LIT, 700)+ , (HUNT_SET_LIT, 900), (FLIGHT_SET_LIT, 700) , (AMBUSH_SET_LIT, 1000), (BATTLE_SET_LIT, 500) , (DIRT_LIT, 1) ] }@@ -860,7 +866,7 @@ , tfeature = VeryOftenItem : tfeature floorActor } floorAshes = floorActor -- always lit- { tfreq = [ (SMOKE_CLUMP_LIT, 1), (SMOKE_CLUMP_DARK, 1)+ { tfreq = [ (SMOKE_CLUMP_LIT, 1) , (S_FLOOR_ASHES_LIT, 1), (S_FLOOR_ASHES_DARK, 1) , (ASHES_SMOKE_LIT, 2), (ASHES_SMOKE_DARK, 5) , (RUBBLE_BURNING_OR_NOT, 25) ]@@ -938,15 +944,16 @@ -- *** Not clear -oriel = TileKind+oriel = TileKind -- no dark variant; it looks dark even when lit { tsymbol = '%' -- story-wise it's transparent, hence the symbol , tname = "oriel" , tfreq = [ (ORIELS_FENCE, 15) , (AIRLOCK_FENCE, 5), (EMPTY_AIRLOCK_FENCE, 5) ]- , tcolor = White- , tcolor2 = Black+ , tcolor = BrBlack+ , tcolor2 = BrBlack , talter = 5- , tfeature = [Embed BLACK_STARRY_SKY, Dark]+ , tfeature = [Embed BLACK_STARRY_SKY]+ -- this is morally @Clear@, but technically it would reach outside the map } outerHullWall = basicOuterFence { tname = "outer hull wall"@@ -984,7 +991,7 @@ wallObscuredSafety = TileKind { tsymbol = '#' , tname = "safety procedures board"- , tfreq = [(OBSCURED_WALL, 4), (EXIT_SET_LIT, 1)]+ , tfreq = [(OBSCURED_WALL, 4), (EGRESS_SET_LIT, 1), (VIRUS_SET_DARK, 1)] , tcolor = BrWhite , tcolor2 = defFG , talter = 5@@ -998,8 +1005,9 @@ , tfreq = [ (SIGNBOARD, 20) , (LIFT_TERMINAL_LIT, 10), (LIFT_TERMINAL_DARK, 10) , (EMPTY_SET_LIT, 7), (ARENA_SET_LIT, 1), (ARENA_SET_DARK, 2)- , (MUSEUM_SET_DARK, 1), (EXIT_SET_LIT, 1), (NOISE_SET_LIT, 1)- , (ESCAPE_SET_DARK, 1), (AMBUSH_SET_DARK, 1) ]+ , (MUSEUM_SET_DARK, 1), (EGRESS_SET_LIT, 1), (VIRUS_SET_DARK, 1)+ , (NOISE_SET_LIT, 1), (FLIGHT_SET_DARK, 1)+ , (AMBUSH_SET_DARK, 1) ] , tcolor = BrCyan , tcolor2 = Cyan , talter = 5@@ -1198,15 +1206,21 @@ , tcolor2 = Blue , tfeature = Embed DECONTAMINATION_CHAMBER : tfeature stairsLiftDown }+escapeAlarmUp = escapeUp+ { tname = "alarm console"+ , tfreq = [(TILE_ALARM_ESCAPE_UP, 1)]+ , tcolor = BrRed+ , tcolor2 = Red+ } escapeSpaceshipDown = escapeDown { tname = "airlock to a shuttle"- , tfreq = [(ESCAPE_SPACESHIP_DOWN, 1), (AIRLOCK_FENCE, 3)]+ , tfreq = [(TILE_SPACESHIP_ESCAPE_DOWN, 1), (AIRLOCK_FENCE, 3)] } emptyAirlock = escapeDown { tname = "empty airlock" , tfreq = [ (AIRLOCK_FENCE, 2), (EMPTY_AIRLOCK_FENCE, 7) , (EMPTY_SET_LIT, 8), (AMBUSH_SET_DARK, 7) ]- -- not in exitSetLit; space can't be seen+ -- not in egressSetLit; space can't be seen , tcolor = BrBlack , tcolor2 = BrBlack , tfeature = [Embed DISENGAGED_DOCKING_GEAR]@@ -1214,7 +1228,8 @@ reinforcedWall = TileKind { tsymbol = '#' , tname = "reinforced wall"- , tfreq = [(S_REINFORCED_WALL, 1), (ROGUE_SET, 15), (EXIT_SET_LIT, 20)]+ , tfreq = [ (S_REINFORCED_WALL, 1), (ROGUE_SET, 15), (EGRESS_SET_LIT, 20)+ , (VIRUS_SET_LIT, 30), (VIRUS_SET_DARK, 6)] , tcolor = White , tcolor2 = BrBlack , talter = 100@@ -1250,8 +1265,9 @@ { tsymbol = '0' , tname = "large barrel" , tfreq = [ (BARREL, 1)- , (EXIT_SET_LIT, 3), (NOISE_SET_LIT, 20), (POWER_SET_DARK, 50)- , (ZOO_SET_DARK, 30), (AMBUSH_SET_DARK, 2) ]+ , (EGRESS_SET_LIT, 3), (VIRUS_SET_DARK, 10), (NOISE_SET_LIT, 20)+ , (POWER_SET_DARK, 50), (ZOO_SET_DARK, 30)+ , (AMBUSH_SET_DARK, 2) ] , tcolor = BrBlue , tcolor2 = Blue , talter = 0 -- projectiles can trigger the embed@@ -1273,7 +1289,7 @@ , tname = "hardware rack" , tfreq = [ (S_HARDWARE_RACK, 1) , (ROGUE_SET, 25), (NOISE_SET_LIT, 250), (POWER_SET_DARK, 250)- , (EXIT_SET_LIT, 30)+ , (EGRESS_SET_LIT, 30), (VIRUS_SET_LIT, 60), (VIRUS_SET_DARK, 30) , (LIFT_TERMINAL_LIT, 40), (LIFT_TERMINAL_DARK, 40) ] , tcolor = White , tcolor2 = BrBlack@@ -1289,7 +1305,7 @@ , tname = "ripe bush" , tfreq = [ (EMPTY_SET_LIT, 4), (ARENA_SET_LIT, 2), (ARENA_SET_DARK, 4) , (SHOOTOUT_SET_LIT, 1), (HUNT_SET_LIT, 1)- , (ESCAPE_SET_DARK, 4), (ZOO_SET_DARK, 1)+ , (FLIGHT_SET_DARK, 4), (ZOO_SET_DARK, 1) , (LIFT_TERMINAL_LIT, 1), (LIFT_TERMINAL_DARK, 1) ] , tcolor = BrMagenta , tcolor2 = Magenta@@ -1332,7 +1348,8 @@ floorOily = floorArena { tname = "oily floor"- , tfreq = [ (MUSEUM_SET_LIT, 40), (POWER_SET_LIT, 550), (EXIT_SET_LIT, 800)+ , tfreq = [ (MUSEUM_SET_LIT, 40), (POWER_SET_LIT, 550)+ , (EGRESS_SET_LIT, 800), (VIRUS_SET_LIT, 700) , (BATTLE_SET_LIT, 1000) , (OILY_FLOOR_LIT, 1), (RUBBLE_OR_WASTE_LIT, 1) , (OIL_RESIDUE_LIT, 4) ]@@ -1343,7 +1360,7 @@ oilSpill = TileKind -- always lit { tsymbol = '~' , tname = "oil spill"- , tfreq = [ (POWER_SET_DARK, 35), (EXIT_SET_LIT, 9)+ , tfreq = [ (POWER_SET_DARK, 35), (EGRESS_SET_LIT, 9), (VIRUS_SET_DARK, 15) , (AMBUSH_SET_DARK, 20), (S_OIL_SPILL, 1) ] , tcolor = BrYellow , tcolor2 = BrGreen@@ -1366,27 +1383,28 @@ oilBurning = TileKind -- always lit { tsymbol = '~' , tname = "burning oil"- , tfreq = [(POWER_SET_DARK, 1), (AMBUSH_SET_DARK, 1), (S_BURNING_OIL, 1)]+ , tfreq = [ (POWER_SET_DARK, 1), (VIRUS_SET_DARK, 1), (AMBUSH_SET_DARK, 1)+ , (S_BURNING_OIL, 1) ] , tcolor = BrRed , tcolor2 = Red , talter = 2 -- due to this, projectiles can't put out the fire -- and don't get burned , tfeature = [ Walkable, Clear -- clear, no smoke, as in oil lamps , NoItem, NoActor- , Embed SMALL_FIRE_5 , Embed OIL_PUDDLE+ , Embed SMALL_FIRE_5 , ChangeWith ProjNo [(1, FIREPROOF_CLOTH)] OILY_FLOOR_LIT -- safely soaks oil, if crafting fails or unintended , ChangeTo S_OIL_SPILL ] -- TODO: change only after all 5 fires used up }-floorWindow = floorArena -- always lit- { tsymbol = ' ' -- story-wise it's transparent, hence the symbol+floorWindow = floorArena -- no dark variant; it looks dark even when lit+ { tsymbol = floorSymbol -- story-wise it's transparent, but no good symbol , tname = "floor window" , tfreq = [(EMPTY_SET_LIT, 24)]- , tcolor = defFG- , tcolor2 = defFG- , tfeature = Embed BLACK_STARRY_SKY : tfeature floorCorridor+ , tcolor = BrBlack -- not yellow, because light sucked away+ , tcolor2 = BrBlack+ , tfeature = Embed BLACK_STARRY_SKY : tfeature floorArena } underbrush = TileKind -- always lit { tsymbol = floorSymbol@@ -1395,7 +1413,7 @@ , (UNDERBRUSH_CLUMP_LIT, 1), (UNDERBRUSH_CLUMP_DARK, 1) , (EMPTY_SET_LIT, 200), (ARENA_SET_LIT, 80), (BRAWL_SET_LIT, 100) , (SHOOTOUT_SET_LIT, 100), (HUNT_SET_LIT, 100)- , (ESCAPE_SET_LIT, 100), (ZOO_SET_DARK, 5)+ , (FLIGHT_SET_LIT, 100), (ZOO_SET_DARK, 5) , (AMBUSH_SET_DARK, 20) , (BUSH_CLUMP_LIT, 1), (BUSH_CLUMP_DARK, 1) , (TRAIL_LIT, 50), (SAFE_TRAIL_LIT, 50) ]
GameDefinition/InGameHelp.txt view
@@ -168,7 +168,7 @@ C-c exit to desktop without saving ? display help F1 display help immediately- F12 open dashboard+ F12 show history v voice last action again V voice recorded macro again ' start recording commands
GameDefinition/Main.hs view
@@ -17,8 +17,8 @@ import Control.Concurrent.Async import qualified Control.Exception as Ex+import qualified GHC.IO.Encoding as SIO import qualified Options.Applicative as OA-import System.Exit import qualified System.IO as SIO #ifndef USE_JSFILE@@ -38,6 +38,10 @@ -- run the game and handle exit. main :: IO () main = do+ -- Correct unset or some other too primitive encodings.+ let enc = SIO.localeEncoding+ when (show enc `elem` ["ASCII", "ISO-8859-1", "ISO-8859-2"]) $+ SIO.setLocaleEncoding SIO.utf8 -- This test is faulty with JS, because it reports the browser console -- is not a terminal, but then we can't open files to contain the logs. -- Also it bloats the outcome JS file, so disabled.@@ -69,7 +73,5 @@ _ -> e case resOrEx of Right () -> return ()- Left e -> case Ex.fromException $ unwrapEx e of- Just ExitSuccess ->- exitSuccess -- we are in the main thread, so here it really exits- _ -> Ex.throwIO $ unwrapEx e+ Left ex -> Ex.throwIO $ unwrapEx ex+ -- we are in the main thread, so now really exit
GameDefinition/PLAYING.md view
@@ -113,13 +113,16 @@ Game difficulty level, from the new game setup menu, determines how hard the survival in the game is. Each of the several named optional challenges make the game additionally much harder, but usually simpler, as well.+Not that in-game hints don't take challenges into account+so kindly ignore, e.g., advice to use ranged combat more often,+if the chosen challenge bans ranged combat use altogether. Of the convenience settings, the `suspect terrain` choice is of particular interest, because it determines not only screen display of the floor map, but also whether suspect tiles are considered for mouse go-to, auto-explore and for the `C-?` command that marks the nearest unexplored position. Game scenarios, as ordered by their number, lead the player along-an optional story arc. The first two adventures double as tutorials+an optional story arc. The first three adventures double as tutorials that offer rudimentary preparation for the main game, the long crawl. They gradually introduce exploration, stealth and melee combat, helping the player develop his repertoire of squad formations@@ -128,7 +131,7 @@ with hints about strategies known to work in the given tactical context. Alternatively, the player may postpone reading these messages and instead try to puzzle out the tactics himself --- this is not so hard, as there are-not yet so many moving parts to figure out in the first two adventures.+not yet so many moving parts to figure out in the first three adventures. In the third scenario, the main 'crawl' game mode, the player starts employing ranged combat, stealth, light sources, item and terrain alteration.@@ -491,7 +494,7 @@ You win an adventure if you escape the location alive (which may prove difficult, because your foes tend to gradually build up the ambush squad-blocking your escape route) or, in scenarios with no exit locations,+blocking your escape route) or, in scenarios with no escape 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@@ -520,7 +523,8 @@ FAQ --- -- Q: I've already explored first three decks and I don't know what to do next.+- Q: I've explored the first three decks of the crawl game mode and I don't+know what to do next. A: Role-play a little. Re-read the scenario description, deck descriptions for all three levels and the description of crucial@@ -553,12 +557,13 @@ or examine interesting terrain more often. Listen to what encountered unique characters say. Read the descriptions and piece the puzzles together. If still no luck, it may be that there was a murder and the item-you look for got stranded. In that case, explore every tile,+enabling the easiest solution got stranded. In that case, explore every tile, pick up every item, equip it and try opening the staircase. The item can't be destroyed and is too scary to be picked up by foes, so your success is assured. Ask on a forum if desperate. If that's any consolation, it's the only blocking puzzle in the game. All other puzzles and mini-games can be brute-forced (with some losses).+BTW, there are less obvious but more advantageous ways of opening that path. - Q: Where to buy light sources in the crawl scenario game?
GameDefinition/config.ui.default view
@@ -132,4 +132,4 @@ ; any more, the game crashes. To prevent that, one of the first three components ; of the game version should be bumped whenever fonts are changed. ; Configs from old versions are rejected, preventing the crash.-version = 0.10.3+version = 0.11.0
GameDefinition/game-src/Client/UI/Content/Input.hs view
@@ -58,7 +58,7 @@ , aiming = Accept } )) , ("space", ( [CmdMinimal, CmdAim] , "clear messages/show history/cycle detail level"- , ByAimMode AimModeCmd { exploration = ExecuteIfClear LastHistory+ , ByAimMode AimModeCmd { exploration = ExecuteIfClear AllHistory , aiming = DetailCycle } )) , ("Tab", memberCycle Forward [CmdMinimal, CmdMove]) -- listed here to keep proper order of the minimal cheat sheet@@ -99,7 +99,7 @@ , ChooseItemMenu MOwned )) , ("@", ( [CmdMeta, CmdDashboard] , "describe organs of the pointman"- , ChooseItemMenu MOrgans ))+ , ChooseItemMenu (MLore SBody) )) , ("#", ( [CmdMeta, CmdDashboard] , "show skill summary of the pointman" , ChooseItemMenu MSkills ))@@ -111,18 +111,21 @@ , ("safeD0", ([CmdInternal, CmdDashboard], "", Cancel)) -- blank line ] ++- map (\(k, slore) -> ("safeD" ++ show (k :: Int)- , ( [CmdInternal, CmdDashboard]- , "display" <+> ppSLore slore <+> "lore"- <+> if slore == SEmbed- then "(including crafting recipes)"- else ""+ zipWith (\k slore -> ("safeD" ++ show (k :: Int)+ , ( [CmdInternal, CmdDashboard]+ , "display" <+> ppSLore slore <+> "lore"+ <+> if slore == SEmbed+ then "(including crafting recipes)"+ else "" , ChooseItemMenu (MLore slore) )))- (zip [1..] [minBound..maxBound])+ [1..] [minBound..SEmbed] ++- [ ("safeD97", ( [CmdInternal, CmdDashboard]+ [ ("safeD96", ( [CmdInternal, CmdDashboard] , "display place lore" , ChooseItemMenu MPlaces) )+ , ("safeD97", ( [CmdInternal, CmdDashboard]+ , "display faction lore"+ , ChooseItemMenu MFactions) ) , ("safeD98", ( [CmdInternal, CmdDashboard] , "display adventure lore" , ChooseItemMenu MModes) )@@ -179,7 +182,7 @@ , ("C-c", ([CmdMeta], "exit to desktop without saving", GameDrop)) , ("?", ([CmdMeta], "display help", Hint)) , ("F1", ([CmdMeta, CmdDashboard], "display help immediately", Help))- , ("F12", ([CmdMeta], "open dashboard", Dashboard))+ , ("F12", ([CmdMeta, CmdDashboard], "show history", AllHistory)) , ("v", repeatLastTriple 1 [CmdMeta]) , ("C-v", repeatLastTriple 25 []) , ("A-v", repeatLastTriple 100 [])@@ -190,9 +193,6 @@ , ("C-S", ([CmdMeta], "save game backup", GameSave)) , ("C-P", ([CmdMeta], "print screen", PrintScreen)) - -- Dashboard, in addition to commands marked above- , ("safeD101", ([CmdInternal, CmdDashboard], "display history", AllHistory))- -- Mouse , ( "LeftButtonRelease" , mouseLMB goToCmd@@ -213,6 +213,8 @@ , ("WheelSouth", ([CmdMouse], "unswerve the aiming line", Macro ["-"])) -- Debug and others not to display in help screens+ , ("Escape", ([CmdMeta], "", AutomateBack))+ , ("Escape", ([CmdMeta], "", MainMenu)) , ("C-semicolon", ( [] , "move one step towards the crosshair" , MoveOnceToXhair ))@@ -254,17 +256,17 @@ , "accept target" , Accept )) , ("safe11", ( [CmdInternal]- , "show history"- , LastHistory ))- , ("safe12", ( [CmdInternal] , "wait a turn, bracing for impact" , Wait ))- , ("safe13", ( [CmdInternal]+ , ("safe12", ( [CmdInternal] , "lurk 0.1 of a turn" , Wait10 ))- , ("safe14", ( [CmdInternal]+ , ("safe13", ( [CmdInternal] , "snap crosshair to enemy" , XhairPointerEnemy ))+ , ("safe14", ( [CmdInternal]+ , "open dashboard"+ , Dashboard )) ] ++ map defaultHeroSelect [0..9]
GameDefinition/game-src/Implementation/MonadClientImplementation.hs view
@@ -32,7 +32,6 @@ import Game.LambdaHack.Client.MonadClient import Game.LambdaHack.Client.State import Game.LambdaHack.Client.UI-import Game.LambdaHack.Client.UI.SessionUI import Game.LambdaHack.Common.ClientOptions import Game.LambdaHack.Common.Kind import Game.LambdaHack.Common.MonadStateRead@@ -126,14 +125,15 @@ -- | Run the main client loop, with the given arguments and empty -- initial states, in the @IO@ monad.-executorCli :: CCUI -> UIOptions -> ClientOptions+executorCli :: CCUI -> UIOptions -> ClientOptions -> Bool -> COps- -> Bool -> FactionId -> ChanServer -> IO ()-executorCli ccui sUIOptions clientOptions cops@COps{corule} isUI fid cliDict =- let cliSession | isUI = Just $ emptySessionUI sUIOptions+executorCli ccui sUIOptions clientOptions startsNewGame+ cops@COps{corule} fid cliDict =+ let cliSession | isJust (requestUIS cliDict) =+ Just $ emptySessionUI sUIOptions | otherwise = Nothing stateToFileName (cli, _) = ssavePrefixCli (soptions cli) <> Save.saveNameCli corule (sside cli)@@ -145,6 +145,6 @@ , cliToSave , cliSession }- m = loopCli ccui sUIOptions clientOptions+ m = loopCli ccui sUIOptions clientOptions startsNewGame exe = evalStateT (runCliImplementation m) . totalState in Save.wrapInSaves cops stateToFileName exe
GameDefinition/game-src/Implementation/MonadServerImplementation.hs view
@@ -20,6 +20,7 @@ import Game.LambdaHack.Core.Prelude import Control.Concurrent+import Control.Concurrent.Async import qualified Control.Exception as Ex import qualified Control.Monad.IO.Class as IO import Control.Monad.Trans.State.Strict hiding (State)@@ -27,7 +28,7 @@ import qualified Data.Text.IO as T import Options.Applicative (defaultPrefs, execParserPure, handleParseResult)-import System.Exit (ExitCode (ExitSuccess))+import System.Exit (ExitCode) import System.IO (hFlush, stdout) import Game.LambdaHack.Atomic@@ -86,9 +87,9 @@ instance MonadServerComm SerImplementation where {-# INLINE getsDict #-} getsDict f = SerImplementation $ gets $ f . serDict- {-# INLINE modifyDict #-}- modifyDict f = SerImplementation $ state $ \serS ->- let !newSerS = serS {serDict = f $ serDict serS}+ {-# INLINE putDict #-}+ putDict newSerDict = SerImplementation $ state $ \serS ->+ let !newSerS = serS {serDict = newSerDict} in ((), newSerS) liftIO = SerImplementation . IO.liftIO @@ -151,7 +152,8 @@ $ sclientOptions soptionsNxtRaw soptionsNxt = soptionsNxtRaw {sclientOptions = clientOptions} -- Partially applied main loop of the clients.- executorClient = executorCli ccui sUIOptions clientOptions cops+ executorClient startsNewGame =+ executorCli ccui sUIOptions clientOptions startsNewGame cops -- Wire together game content, the main loop of game clients -- and the game server loop. let stateToFileName (_, ser) =@@ -166,11 +168,14 @@ m = loopSer soptionsNxt executorClient exe = evalStateT (runSerImplementation m) . totalState exeWithSaves = Save.wrapInSaves cops stateToFileName exe+ unwrapEx e = case Ex.fromException e of+ Just (ExceptionInLinkedThread _ ex) -> unwrapEx ex+ _ -> e -- Wait for clients to exit even in case of server crash -- (or server and client crash), which gives them time to save -- and report their own inconsistencies, if any.- Ex.handle (\ex -> case Ex.fromException ex of- Just ExitSuccess ->+ Ex.handle (\ex -> case Ex.fromException (unwrapEx ex) :: Maybe ExitCode of+ Just{} -> -- User-forced shutdown, not crash, so the intention is -- to keep old saves and also clients may be not ready to save. Ex.throwIO ex
GameDefinition/game-src/TieKnot.hs view
@@ -30,6 +30,7 @@ import Game.LambdaHack.Common.Point (speedupHackXSize) import qualified Game.LambdaHack.Common.Tile as Tile import qualified Game.LambdaHack.Content.CaveKind as CK+import qualified Game.LambdaHack.Content.FactionKind as FK import qualified Game.LambdaHack.Content.ItemKind as IK import qualified Game.LambdaHack.Content.ModeKind as MK import qualified Game.LambdaHack.Content.PlaceKind as PK@@ -40,6 +41,7 @@ import qualified Client.UI.Content.Input as Content.Input import qualified Client.UI.Content.Screen as Content.Screen import qualified Content.CaveKind+import qualified Content.FactionKind import qualified Content.ItemKind import qualified Content.ModeKind import qualified Content.PlaceKind@@ -70,40 +72,45 @@ -- equal to what was generated last time, ensures the same item boost. initialGen <- maybe SM.newSMGen return sdungeonRng let soptionsNxt = options {sdungeonRng = Just initialGen}+ corule = RK.makeData Content.RuleKind.standardRules boostedItems = IK.boostItemKindList initialGen Content.ItemKind.items itemContent = if sboostRandomItem then boostedItems ++ Content.ItemKind.otherItemContent else Content.ItemKind.content- coitem = IK.makeData (RK.ritemSymbols Content.RuleKind.standardRules)+ coitem = IK.makeData (RK.ritemSymbols corule) itemContent Content.ItemKind.groupNamesSingleton Content.ItemKind.groupNames- coItemSpeedup = speedupItem coitem cotile = TK.makeData Content.TileKind.content Content.TileKind.groupNamesSingleton Content.TileKind.groupNames- coTileSpeedup = Tile.speedupTile sallClear cotile+ cofact = FK.makeData Content.FactionKind.content+ Content.FactionKind.groupNamesSingleton+ Content.FactionKind.groupNames -- Common content operations, created from content definitions. -- Evaluated fully to discover errors ASAP and to free memory. -- Fail here, not inside server code, so that savefiles are not removed, -- because they are not the source of the failure. copsRaw = COps- { cocave = CK.makeData Content.CaveKind.content+ { cocave = CK.makeData corule+ Content.CaveKind.content Content.CaveKind.groupNamesSingleton Content.CaveKind.groupNames+ , cofact , coitem- , comode = MK.makeData Content.ModeKind.content+ , comode = MK.makeData cofact+ Content.ModeKind.content Content.ModeKind.groupNamesSingleton Content.ModeKind.groupNames , coplace = PK.makeData cotile Content.PlaceKind.content Content.PlaceKind.groupNamesSingleton Content.PlaceKind.groupNames- , corule = RK.makeData Content.RuleKind.standardRules+ , corule , cotile- , coItemSpeedup- , coTileSpeedup+ , coItemSpeedup = speedupItem coitem+ , coTileSpeedup = Tile.speedupTile sallClear cotile } -- Evaluating for compact regions catches all kinds of errors in content ASAP, -- even in unused items.@@ -119,13 +126,13 @@ -- It is reparsed at each start of the game executable. -- Fail here, not inside client code, so that savefiles are not removed, -- because they are not the source of the failure.- sUIOptions <- mkUIOptions (corule cops) (sclientOptions soptionsNxt)+ sUIOptions <- mkUIOptions corule (sclientOptions soptionsNxt) -- Client content operations containing default keypresses -- and command descriptions. let !ccui = CCUI { coinput = IC.makeData (Just sUIOptions) Content.Input.standardKeysAndMouse- , coscreen = SC.makeData Content.Screen.standardLayoutAndFeatures+ , coscreen = SC.makeData corule Content.Screen.standardLayoutAndFeatures } -- Wire together game content, the main loops of game clients -- and the game server loop.
Makefile view
@@ -16,6 +16,9 @@ short-caves: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix know --newGame 5 --dumpInitRngs --gameMode short --knowItems --exposePlaces --exposeItems --exposeActors --showItemSamples --benchmark --noAnim --maxFps 1000 +fun-caves:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix know --newGame 5 --dumpInitRngs --gameMode fun --knowItems --exposePlaces --exposeItems --exposeActors --showItemSamples --benchmark --noAnim --maxFps 1000+ configure-debug: cabal configure --enable-profiling --profiling-detail=all-functions -fwith_expensive_assertions --disable-optimization @@ -32,10 +35,10 @@ google-chrome --no-sandbox --js-flags="--logfile=%t.log --prof" ../allureofthestars.github.io/play/index.html minific:- npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.10.3.0/x/Allure/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.10.3.0/x/Allure/build/Allure/Allure.jsexe/all.js.externs --externs=/home/mikolaj/r/lambdahack.github.io/lz-string.extern.js --jscomp_off="*" > ../allureofthestars.github.io/play/allure.all.js+ npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.11.0.0/x/Allure/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.11.0.0/x/Allure/build/Allure/Allure.jsexe/all.js.externs --externs=/home/mikolaj/r/lambdahack.github.io/lz-string.extern.js --jscomp_off="*" > ../allureofthestars.github.io/play/allure.all.js minificForNode:- npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.10.3.0/x/Allure/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=/home/mikolaj/r/lambdahack.github.io/lz-string.extern.js --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.10.3.0/x/Allure/build/Allure/Allure.jsexe/all.js.externs --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/assert.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/child_process.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/crypto.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dns.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/events.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/globals.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/https.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/os.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/punycode.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/readline.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/stream.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tls.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/url.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/vm.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/buffer.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/cluster.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dgram.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/domain.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/fs.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/http.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/net.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/path.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/querystring.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/repl.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/string_decoder.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tty.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/util.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/zlib.js --jscomp_off="*" > ../allureofthestars.github.io/play/allure.all.js+ npx google-closure-compiler dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.11.0.0/x/Allure/build/Allure/Allure.jsexe/all.js --compilation_level=ADVANCED_OPTIMIZATIONS --isolation_mode=IIFE --assume_function_wrapper --externs=/home/mikolaj/r/lambdahack.github.io/lz-string.extern.js --externs=dist-newstyle/build/x86_64-linux/ghcjs-8.6.0.1/Allure-0.11.0.0/x/Allure/build/Allure/Allure.jsexe/all.js.externs --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/assert.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/child_process.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/crypto.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dns.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/events.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/globals.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/https.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/os.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/punycode.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/readline.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/stream.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tls.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/url.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/vm.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/buffer.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/cluster.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/dgram.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/domain.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/fs.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/http.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/net.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/path.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/querystring.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/repl.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/string_decoder.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/tty.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/util.js --externs=/home/mikolaj/r/closure-compiler/contrib/nodejs/zlib.js --jscomp_off="*" > ../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@@ -44,6 +47,9 @@ find ~/.Allure/screenshots/ -name 'prtscn*.bmp' -print0 | xargs -0 -r mogrify -format gif ../gifsicle/src/gifsicle -O3 --careful -d2 --colors 255 --no-extensions --no-conserve-memory -l ~/.Allure/screenshots/prtscn*.gif -o ~/.Allure/screenshots/screenshot.gif +frontendGauntlet:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode gauntlet --benchMessages --exposeActors+ frontendRaid: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode raid --benchMessages --exposeActors @@ -56,8 +62,8 @@ frontendHunt: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 5 --dumpInitRngs --automateAll --gameMode hunt -frontendEscape:- $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 3 --dumpInitRngs --automateAll --gameMode escape+frontendFlight:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 3 --dumpInitRngs --automateAll --gameMode flight frontendZoo: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --savePrefix test --newGame 2 --dumpInitRngs --automateAll --gameMode zoo --exposeActors@@ -164,7 +170,7 @@ test-short: test-short-new test-short-load -test-medium: testRaid-medium testBrawl-medium testShootout-medium testHunt-medium testEscape-medium testZoo-medium testAmbush-medium testCrawlEmpty-medium testCrawl-medium-know testSafari-medium testSafariSurvival-medium testBattle-medium testBattleDefense-medium testBattleSurvival-medium testDig-medium testDefenseEmpty-medium testMany-teletype+test-medium: testGauntlet-medium testRaid-medium testBrawl-medium testShootout-medium testHunt-medium testFlight-medium testZoo-medium testAmbush-medium testCrawlEmpty-medium testCrawl-medium-know testSafari-medium testSafariSurvival-medium testBattle-medium testBattleDefense-medium testBattleSurvival-medium testDig-medium testDefenseEmpty-medium testMany-teletype test-sniff: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --newGame 5 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterFrames 1 --dumpInitRngs --automateAll --keepAutomated --gameMode raid --sniff > /tmp/teletypetest.log 2>&1@@ -175,6 +181,9 @@ testMany-sdlInit: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 0 --boostRandomItem --newGame 9 --maxFps 100000 --benchmark --benchMessages --stopAfterSeconds 50 --dumpInitRngs --automateAll --keepAutomated 2> /tmp/teletypetest.log +testGauntlet-medium:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode gauntlet 2> /tmp/teletypetest.log+ testRaid-medium: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode raid 2> /tmp/teletypetest.log @@ -187,8 +196,8 @@ testHunt-medium: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --maxFps 100000 --frontendTeletype --benchmark --benchMessages --stopAfterSeconds 20 --dumpInitRngs --automateAll --keepAutomated --gameMode hunt 2> /tmp/teletypetest.log -testEscape-medium:- $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 3 --maxFps 100000 --frontendTeletype --benchmark --benchMessages --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode escape 2> /tmp/teletypetest.log+testFlight-medium:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 3 --maxFps 100000 --frontendTeletype --benchmark --benchMessages --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode flight 2> /tmp/teletypetest.log testZoo-medium: $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 2 --maxFps 100000 --frontendTeletype --benchmark --benchMessages --stopAfterSeconds 40 --dumpInitRngs --automateAll --keepAutomated --gameMode zoo 2> /tmp/teletypetest.log@@ -234,11 +243,12 @@ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --newGame 1 --noAnim --maxFps 100000 --frontendTeletype --benchmark --stopAfterFrames 100 --dumpInitRngs --automateAll --keepAutomated --gameMode dig 2> /tmp/teletypetest.log test-short-new:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix gauntlet --dumpInitRngs --automateAll --keepAutomated --gameMode gauntlet --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix brawl --dumpInitRngs --automateAll --keepAutomated --gameMode brawl --showItemSamples --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix shootout --dumpInitRngs --automateAll --keepAutomated --gameMode shootout --showItemSamples --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix hunt --dumpInitRngs --automateAll --keepAutomated --gameMode hunt --showItemSamples --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log- $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix escape --dumpInitRngs --automateAll --keepAutomated --gameMode escape --showItemSamples --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix flight --dumpInitRngs --automateAll --keepAutomated --gameMode flight --showItemSamples --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix zoo --dumpInitRngs --automateAll --keepAutomated --gameMode zoo --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --newGame 5 --savePrefix crawl --dumpInitRngs --automateAll --keepAutomated --gameMode crawl --frontendTeletype --stopAfterSeconds 2 2> /tmp/teletypetest.log@@ -251,11 +261,12 @@ # $(RNGOPTS) is needed for determinism relative to seed # generated before game save test-short-load:+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix gauntlet --dumpInitRngs --automateAll --keepAutomated --gameMode gauntlet --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix brawl --dumpInitRngs --automateAll --keepAutomated --gameMode brawl --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix shootout --dumpInitRngs --automateAll --keepAutomated --gameMode shootout --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix hunt --dumpInitRngs --automateAll --keepAutomated --gameMode hunt --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log- $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix escape --dumpInitRngs --automateAll --keepAutomated --gameMode escape --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log+ $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix flight --dumpInitRngs --automateAll --keepAutomated --gameMode flight --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix zoo --dumpInitRngs --automateAll --keepAutomated --gameMode zoo --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log $$(cabal list-bin exe:Allure) --dbgMsgSer --logPriority 4 --boostRandomItem --savePrefix crawl --dumpInitRngs --automateAll --keepAutomated --gameMode crawl --frontendTeletype --stopAfterSeconds 2 $(RNGOPTS) 2> /tmp/teletypetest.log
README.md view
@@ -150,7 +150,7 @@ and then you can compile (and recompile) with - cabal build .+ cabal build and run the game with @@ -174,7 +174,7 @@ Integration tests can be run and displayed with - cabal test test --enable-tests --test-show-details=direct+ cabal test --test-show-details=direct The [Makefile](https://github.com/AllureOfTheStars/Allure/blob/master/Makefile) contains many sample automated play test commands.
test/Spec.hs view
@@ -40,8 +40,8 @@ ++ let corule = RK.makeData Content.RuleKind.standardRules uiOptions = unsafePerformIO $ mkUIOptions corule defClientOptions- testFontset :: (Int, String) -> TestTree- testFontset (n, fontsetName) =+ testFontset :: Int -> String -> TestTree+ testFontset n fontsetName = testCase ("SDL fronted; init only; " ++ fontsetName ++ " fontset") $ do -- This test only works when run from the same directory that -- the .cabal file is in. And this is what Debian needs, so OK.@@ -53,5 +53,5 @@ , "--fontset", fontsetName ] serverOptions2 <- handleParseResult $ execParserPure defaultPrefs serverOptionsPI args2 tieKnot serverOptions2- in map testFontset $ zip [0..] $ map T.unpack $ map fst $ uFontsets uiOptions+ in zipWith testFontset [0..] $ map (T.unpack . fst) $ uFontsets uiOptions #endif