diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
--- a/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: haskell
-
-install:
-  - cd ..
-  - git clone --depth=50 --branch=mikolaj git://github.com/kosmikus/LambdaHack.git
-  - cd LambdaHack
-  - cabal install gtk2hs-buildtools
-  - cabal install
-  - cd ../Allure
-  - cabal install --only-dependencies
-
-script:
-  - cabal install
-  - make test-travis || (cat ~/.Allure/config.rules.dump ; tail -n 200 /tmp/stdtest.log ; exit 77)
diff --git a/Allure.cabal b/Allure.cabal
--- a/Allure.cabal
+++ b/Allure.cabal
@@ -1,18 +1,16 @@
 name:          Allure
-version:       0.4.10.5
+version:       0.4.12
 synopsis:      Near-future roguelike game in very early and active development
 description:   This is an alpha release of Allure of the Stars,
                a near-future Sci-Fi roguelike and tactical squad game.
                The game is barely fun at this stage and not yet
                really Sci-Fi. See the wiki for design notes and contribute.
                .
-               New since 0.4.8 are screensaver game modes (AI vs AI),
-               improved AI (can now climbs stairs, etc.), multiple,
-               multi-floor staircases, multiple savefiles, configurable
-               framerate and combat animations and more.
-               Long term goals are high replayability and auto-balancing
-               through procedural content generation and persistent content
-               modification based on player behaviour.
+               Please see the changelog file for recent improvements
+               and the issue tracker for short-term plans. Long term goals
+               are high replayability and auto-balancing through procedural
+               content generation and persistent content modification
+               based on player behaviour.
                .
                The game is written using the LambdaHack roguelike game engine
                available at <http://hackage.haskell.org/package/LambdaHack>.
@@ -20,10 +18,11 @@
 bug-reports:   http://github.com/Mikolaj/Allure/issues
 license:       OtherLicense
 license-file:  LICENSE
-tested-with:   GHC == 7.4.2, GHC == 7.6.3, GHC == 7.7
-data-files:    config.rules.default, config.ui.default, scores
-extra-source-files: LICENSE, CREDITS, changelog, PLAYING.md, README.md,
-                    Makefile, MainMenu.ascii, .travis.yml
+tested-with:   GHC == 7.6.3, GHC == 7.8
+data-files:    GameDefinition/config.ui.default,
+               GameDefinition/scores
+extra-source-files: GameDefinition/PLAYING.md, GameDefinition/MainMenu.ascii,
+                    README.md, LICENSE, CREDITS, changelog, Makefile
 author:        Andres Loeh, Mikolaj Konarski and others
 maintainer:    Mikolaj Konarski <mikolaj.konarski@funktory.com>
 category:      Game
@@ -35,7 +34,7 @@
   location:           git://github.com/Mikolaj/Allure.git
 
 executable Allure
-  hs-source-dirs:     src
+  hs-source-dirs:     GameDefinition
   main-is:            Main.hs
   other-modules:      Content.ActorKind,
                       Content.CaveKind,
@@ -46,11 +45,11 @@
                       Content.RuleKind,
                       Content.TileKind,
                       Paths_Allure
-  build-depends:      LambdaHack >= 0.2.10.5 && < 0.2.11,
+  build-depends:      LambdaHack >= 0.2.12 && < 0.2.13,
                       template-haskell >= 2.6 && < 3,
 
-                      ConfigFile >= 1.1.1   && < 2,
                       array      >= 0.3.0.3 && < 1,
+                      assert-failure >= 0.1 && < 1,
                       base       >= 4       && < 5,
                       binary     >= 0.7     && < 1,
                       bytestring >= 0.9.2   && < 1,
@@ -60,16 +59,20 @@
                       enummapset-th >= 0.6.0.0 && < 1,
                       filepath   >= 1.2.0.1 && < 2,
                       ghc-prim   >= 0.2,
-                      hashable   >= 1.2     && < 2,
+                      hashable   >= 1.1.2.5 && < 2,
+                      hsini      >= 0.2     && < 2,
                       keys       >= 3       && < 4,
                       miniutter  >= 0.4.1   && < 2,
                       mtl        >= 2.0.1   && < 3,
                       old-time   >= 1.0.0.7 && < 2,
+                      pretty-show >= 1.6    && < 2,
                       random     >= 1.0.1   && < 2,
                       stm        >= 2.4     && < 3,
                       text       >= 0.11.2.3 && < 2,
                       transformers >= 0.3   && < 1,
                       unordered-containers >= 0.2.3 && < 1,
+                      vector     >= 0.10    && < 1,
+                      vector-binary-instances >= 0.2 && < 1,
                       zlib       >= 0.5.3.1 && < 1
 
   default-language:   Haskell2010
diff --git a/GameDefinition/Content/ActorKind.hs b/GameDefinition/Content/ActorKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/ActorKind.hs
@@ -0,0 +1,93 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Monsters and heroes for Allure of the Stars.
+module Content.ActorKind ( cdefs ) where
+
+import Game.LambdaHack.Common.Ability
+import Game.LambdaHack.Common.Color
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Common.Random
+import Game.LambdaHack.Common.Time
+import Game.LambdaHack.Content.ActorKind
+
+cdefs :: ContentDef ActorKind
+cdefs = ContentDef
+  { getSymbol = asymbol
+  , getName = aname
+  , getFreq = afreq
+  , validate = validateActorKind
+  , content =
+      [hero, projectile, eye, fastEye, nose]
+  }
+hero,        projectile, eye, fastEye, nose :: ActorKind
+
+hero = ActorKind
+  { asymbol = '@'
+  , aname   = "hero"
+  , afreq   = [("hero", 1)]
+  , acolor  = BrWhite  -- modified if many hero factions
+  , ahp     = rollDice 50 1
+  , aspeed  = toSpeed 2
+  , asight  = True
+  , asmell  = False
+  , aiq     = 15  -- higher that that leads to looping movement
+  , aregen  = 500
+  , acanDo  = [minBound..maxBound]
+  }
+
+projectile = ActorKind  -- includes homing missiles
+  { asymbol = '*'
+  , aname   = "projectile"
+  , afreq   = [("projectile", 1)]  -- Does not appear randomly in the dungeon.
+  , acolor  = BrWhite
+  , ahp     = rollDice 0 0
+  , aspeed  = toSpeed 0
+  , asight  = False
+  , asmell  = False
+  , aiq     = 0
+  , aregen  = maxBound
+  , acanDo  = [Track]
+  }
+
+eye = ActorKind
+  { asymbol = 'r'
+  , aname   = "deranged household robot"
+  , afreq   = [("robot", 60), ("horror", 60)]
+  , acolor  = BrYellow
+  , ahp     = rollDice 7 4
+  , aspeed  = toSpeed 2
+  , asight  = True
+  , asmell  = False
+  , aiq     = 16  -- leads to robotic, repetitious, looping movement
+  , aregen  = 100
+  , acanDo  = [minBound..maxBound]
+  }
+fastEye = ActorKind
+  { asymbol = 'm'
+  , aname   = "deformed monkey"
+  , afreq   = [("animal", 15), ("horror", 15)]
+  , acolor  = BrMagenta
+  , ahp     = rollDice 1 6
+  , aspeed  = toSpeed 4
+  , asight  = True
+  , asmell  = False
+  , aiq     = 12
+  , aregen  = 10  -- Regenerates fast (at max HP most of the time!).
+  , acanDo  = [minBound..maxBound]
+  }
+nose = ActorKind
+  { asymbol = 'h'
+  , aname   = "tentacled horror"
+  , afreq   = [("alien", 20), ("horror", 20)]
+  , acolor  = Green
+  , ahp     = rollDice 17 2
+  , aspeed  = toSpeed 1.8
+  , asight  = False
+  , asmell  = True
+  , aiq     = 0
+  , aregen  = 100
+  , acanDo  = [minBound..maxBound]
+  }
diff --git a/GameDefinition/Content/CaveKind.hs b/GameDefinition/Content/CaveKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/CaveKind.hs
@@ -0,0 +1,130 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Cave layouts for Allure of the Stars.
+module Content.CaveKind ( cdefs ) where
+
+import Data.Ratio
+
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Common.Misc
+import Game.LambdaHack.Common.Random as Random
+import Game.LambdaHack.Content.CaveKind
+
+cdefs :: ContentDef CaveKind
+cdefs = ContentDef
+  { getSymbol = csymbol
+  , getName = cname
+  , getFreq = cfreq
+  , validate = validateCaveKind
+  , content =
+      [rogue, arena, empty, noise, combat, battle]
+  }
+rogue,        arena, empty, noise, combat, battle :: CaveKind
+
+rogue = CaveKind
+  { csymbol       = '$'
+  , cname         = "Storage area"
+  , cfreq         = [("dng", 100), ("caveRogue", 1)]
+  , cxsize        = fst normalLevelBound + 1
+  , cysize        = snd normalLevelBound + 1
+  , cgrid         = rollDiceXY [(3, 2)] [(1, 2), (2, 1)]
+  , cminPlaceSize = rollDiceXY [(2, 2), (2, 1)] [(4, 1)]
+  , cmaxPlaceSize = rollDiceXY [(fst normalLevelBound, 1)]
+                               [(snd normalLevelBound, 1)]
+  , cdarkChance   = rollDeep (1, 54) (0, 0)
+  , cnightChance  = intToDeep 100
+  , cauxConnects  = 1%3
+  , cmaxVoid      = 1%6
+  , cminStairDist = 30
+  , cdoorChance   = 1%2
+  , copenChance   = 1%10
+  , chidden       = 8
+  , citemNum      = rollDice 7 2
+  , citemFreq     = [(70, "useful"), (30, "treasure")]
+  , cdefTile        = "fillerWall"
+  , cdarkCorTile    = "floorCorridorDark"
+  , clitCorTile     = "floorCorridorLit"
+  , cfillerTile     = "fillerWall"
+  , couterFenceTile = "basic outer fence"
+  , clegendDarkTile = "legendDark"
+  , clegendLitTile  = "legendLit"
+  }
+arena = rogue
+  { csymbol       = 'A'
+  , cname         = "Recreational deck"
+  , cfreq         = [("dng", 100), ("caveArena", 1)]
+  , cgrid         = rollDiceXY [(2, 2)] [(1, 2), (1, 1)]
+  , cminPlaceSize = rollDiceXY [(2, 2), (3, 1)] [(4, 1)]
+  , cdarkChance   = rollDeep (1, 80) (1, 60)
+  , cnightChance  = intToDeep 0
+  , cmaxVoid      = 1%3
+  , chidden       = 1000
+  , citemNum      = rollDice 5 2  -- few rooms
+  , cdefTile      = "arenaSet"
+  , cdarkCorTile  = "trailLit"  -- let paths around rooms be lit
+  , clitCorTile   = "trailLit"
+  , couterFenceTile = "oriels fence"
+  }
+empty = rogue
+  { csymbol       = '.'
+  , cname         = "Construction site"
+  , cfreq         = [("dng", 100), ("caveEmpty", 1)]
+  , cgrid         = rollDiceXY [(1, 2), (1, 1)] [(1, 1)]
+  , cminPlaceSize = rollDiceXY [(10, 1)] [(10, 1)]
+  , cmaxPlaceSize = rollDiceXY [(fst normalLevelBound * 3 `div` 5, 1)]
+                               [(snd normalLevelBound * 3 `div` 5, 1)]
+  , cdarkChance   = rollDeep (1, 80) (1, 80)
+  , cnightChance  = intToDeep 0
+  , cauxConnects  = 1
+  , cmaxVoid      = 1%2
+  , cminStairDist = 50
+  , chidden       = 1000
+  , citemNum      = rollDice 8 2  -- whole floor strewn with treasure
+  , cdefTile      = "emptySet"
+  , cdarkCorTile  = "trailLit"  -- let paths around rooms be lit
+  , clitCorTile   = "floorArenaLit"
+  , couterFenceTile = "oriels fence"
+  }
+noise = rogue
+  { csymbol       = '!'
+  , cname         = "Machine rooms"
+  , cfreq         = [("dng", 100), ("caveNoise", 1)]
+  , cgrid         = rollDiceXY [(2, 2)] [(1, 2), (1, 1)]
+  , cminPlaceSize = rollDiceXY [(3, 2), (2, 1)] [(5, 1)]
+  , cdarkChance   = rollDeep (1, 80) (1, 40)
+  , cnightChance  = rollDeep (1, 40) (1, 40)
+  , cmaxVoid      = 0
+  , chidden       = 1000
+  , citemNum      = rollDice 4 2  -- fewer rooms
+  , cdefTile      = "noiseSet"
+  , cdarkCorTile  = "trailLit"  -- let trails give off light
+  , clitCorTile   = "trailLit"
+  }
+combat = rogue
+  { csymbol       = 'C'
+  , cname         = "Combat arena"
+  , cfreq         = [("caveCombat", 1)]
+  , cgrid         = rollDiceXY [(2, 2), (3, 1)] [(1, 2), (2, 1)]
+  , cminPlaceSize = rollDiceXY [(3, 1)] [(3, 1)]
+  , cmaxPlaceSize = rollDiceXY [(5, 1)] [(5, 1)]
+  , cdarkChance   = intToDeep 100
+  , cnightChance  = rollDeep (1, 67) (0, 0)
+  , chidden       = 1000
+  , cauxConnects  = 0
+  , cdoorChance   = 1
+  , copenChance   = 0
+  , citemNum      = rollDice 12 2
+  , citemFreq     = [(100, "useful")]
+  , cdefTile      = "combatSet"
+  , cdarkCorTile  = "trailLit"  -- let trails give off light
+  , clitCorTile   = "floorArenaLit"
+  }
+battle = combat  -- TODO: actors can get stuck forever among trees
+  { csymbol       = 'B'
+  , cname         = "Battle arena"
+  , cfreq         = [("caveBattle", 1)]
+  , cdefTile      = "battleSet"
+  }
diff --git a/GameDefinition/Content/FactionKind.hs b/GameDefinition/Content/FactionKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/FactionKind.hs
@@ -0,0 +1,84 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | The type of kinds of game factions (heroes, enemies, NPCs, etc.)
+-- for Allure of the Stars.
+module Content.FactionKind ( cdefs ) where
+
+import Data.List
+
+import Game.LambdaHack.Common.Ability
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Content.FactionKind
+
+cdefs :: ContentDef FactionKind
+cdefs = ContentDef
+  { getSymbol = fsymbol
+  , getName = fname
+  , getFreq = ffreq
+  , validate = validateFactionKind
+  , content =
+      [hero, alien, animal, robot, horror]
+  }
+hero,        alien, animal, robot, horror :: FactionKind
+
+hero = FactionKind
+  { fsymbol        = '@'
+  , fname          = "hero"
+  , ffreq          = [("hero", 1)]
+  , fAbilityLeader = allAbilities
+  , fAbilityOther  = meleeAdjacent
+  }
+
+-- Includes alien-operated robots, alien-conditioned animals and hybrids.
+alien = FactionKind
+  { fsymbol        = 'a'
+  , fname          = "alien"
+  , ffreq          = [("alien", 1), ("summon", 20)]
+  , fAbilityLeader = allAbilities
+  , fAbilityOther  = allAbilities
+  }
+
+animal = FactionKind
+  { fsymbol        = 'd'
+  , fname          = "animal"
+  , ffreq          = [("animal", 1), ("summon", 50)]
+  , fAbilityLeader = animalAbility
+  , fAbilityOther  = animalAbility
+  }
+
+-- Autonomous robots.
+robot = FactionKind
+  { fsymbol        = 'r'
+  , fname          = "robot"
+  , ffreq          = [("robot", 1), ("summon", 10)]
+  , fAbilityLeader = robotAbility
+  , fAbilityOther  = robotAbility
+  }
+
+horror = FactionKind
+  { fsymbol        = 'h'
+  , fname          = "horror"
+  , ffreq          = [("horror", 1), ("summon", 50)]
+  , fAbilityLeader = allAbilities
+  , fAbilityOther  = allAbilities
+  }
+
+
+_noAbility, _onlyFollowTrack, meleeAdjacent, _meleeAndRanged, animalAbility, robotAbility, allAbilities :: [Ability]
+
+_noAbility = []  -- not even projectiles will fly
+
+_onlyFollowTrack = [Track]  -- projectiles enabled
+
+meleeAdjacent = [Track, Melee]
+
+_meleeAndRanged = [Track, Melee, Ranged]  -- melee and reaction fire
+
+animalAbility = [Track, Flee, Melee, Displace, Chase, Wander]
+
+robotAbility = delete Flee [minBound..maxBound]
+
+allAbilities = [minBound..maxBound]
diff --git a/GameDefinition/Content/ItemKind.hs b/GameDefinition/Content/ItemKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/ItemKind.hs
@@ -0,0 +1,309 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Weapons and treasure for Allure of the Stars.
+module Content.ItemKind ( cdefs ) where
+
+import qualified Data.List as L
+
+import Game.LambdaHack.Common.Color
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Common.Effect
+import Game.LambdaHack.Common.Flavour
+import Game.LambdaHack.Common.ItemFeature
+import Game.LambdaHack.Common.Random
+import Game.LambdaHack.Content.ItemKind
+
+cdefs :: ContentDef ItemKind
+cdefs = ContentDef
+  { getSymbol = isymbol
+  , getName = iname
+  , getFreq = ifreq
+  , validate = validateItemKind
+  , content =
+      [necklace, dart, gem1, gem2, gem3, currency, javelin, kitchenKnife, potion1, potion2, potion3, ring, scroll1, scroll2, scroll3, sword, wand1, wand2, fist, foot, tentacle, fragrance, mist_healing, mist_wounding, glass_piece, smoke]
+  }
+necklace,        dart, gem1, gem2, gem3, currency, javelin, kitchenKnife, potion1, potion2, potion3, ring, scroll1, scroll2, scroll3, sword, wand1, wand2, fist, foot, tentacle, fragrance, mist_healing, mist_wounding, glass_piece, smoke :: ItemKind
+
+gem, potion, scroll, wand :: ItemKind  -- generic templates
+
+-- castDeep (aDb, xDy) = castDice aDb + (lvl - 1) * castDice xDy / (depth - 1)
+
+{- Item group symbols (from Angband, only as an informal convention for now):
+
+! potion, flask, concoction, bottle, jar, vial, canister
+? scroll, book, note, tablet, remote
+, food
+- magical wand, magical rod, transmitter, pistol, rifle
+_ magical staff, scanner
+= ring
+" necklace
+$ currency, gem
+~ light, tool
+/ polearm
+| edged weapon
+\ hafted weapon
+} launcher
+{ projectile
+( clothes
+[ torso armour
+] misc. armour
+) shield
+
+-}
+
+necklace = ItemKind
+  { isymbol  = '"'
+  , iname    = "necklace"
+  , ifreq    = [("useful", 6)]
+  , iflavour = zipFancy [BrGreen]
+  , icount   = intToDeep 1
+  , iverbApply   = "tear down"
+  , iverbProject = "cast"
+  , iweight  = 30
+  , itoThrow = -50  -- not dense enough
+  , ifeature = [Cause $ Regeneration (rollDeep (2, 3) (1, 10))]
+  }
+dart = ItemKind
+  { isymbol  = '{'
+  , iname    = "billiard ball"
+  , ifreq    = [("useful", 20)]
+  , iflavour = zipPlain [BrWhite]
+  , icount   = rollDeep (3, 3) (0, 0)
+  , iverbApply   = "splinter"
+  , iverbProject = "hurl"
+  , iweight  = 50
+  , itoThrow = 0  -- a cheap dart
+  , ifeature = [Cause $ Hurt (rollDice 1 2) (rollDeep (1, 2) (1, 2))]
+  }
+gem = ItemKind
+  { isymbol  = '*'
+  , iname    = "precious gem"
+  , ifreq    = [("treasure", 20)]  -- x3, but rare on shallow levels
+  , iflavour = zipPlain $ L.delete BrYellow brightCol  -- natural, so not fancy
+  , icount   = intToDeep 0
+  , iverbApply   = "crush"
+  , iverbProject = "toss"
+  , iweight  = 50
+  , itoThrow = 0
+  , ifeature = []
+  }
+gem1 = gem
+  { icount   = rollDeep (0, 0) (1, 1)  -- appears on max depth
+  }
+gem2 = gem
+  { icount   = rollDeep (0, 0) (1, 2)  -- appears halfway
+  }
+gem3 = gem
+  { icount   = rollDeep (0, 0) (1, 3)  -- appears early
+  }
+currency = ItemKind
+  { isymbol  = '$'
+  , iname    = "gold grain"
+  , ifreq    = [("treasure", 20), ("currency", 1)]
+  , iflavour = zipPlain [BrYellow]
+  , icount   = rollDeep (0, 0) (10, 10)  -- appears on lvl 2
+  , iverbApply   = "smear"
+  , iverbProject = "blow away"
+  , iweight  = 1
+  , itoThrow = 0
+  , ifeature = []
+  }
+javelin = ItemKind
+  { isymbol  = '{'
+  , iname    = "javelin"
+  , ifreq    = [("useful", 30)]
+  , iflavour = zipPlain [Brown]
+  , icount   = rollDeep (0, 0) (1, 1)
+  , iverbApply   = "break up"
+  , iverbProject = "hurl"
+  , iweight  = 2000
+  , itoThrow = 0  -- cheap but deadly
+  , ifeature = [Cause $ Hurt (rollDice 2 2) (rollDeep (1, 2) (2, 2))]
+  }
+kitchenKnife = ItemKind
+  { isymbol  = '{'
+  , iname    = "kitchen knife"
+  , ifreq    = [("useful", 25)]
+  , iflavour = zipPlain [BrCyan]
+  , icount   = rollDeep (0, 0) (1, 2)
+  , iverbApply   = "bend"
+  , iverbProject = "throw"
+  , iweight  = 200
+  , itoThrow = -50  -- too flexible and the handle causes air resistance
+  , ifeature = [Cause $ Hurt (rollDice 1 1) (rollDeep (0, 0) (1, 2))]
+  }
+potion = ItemKind
+  { isymbol  = '!'
+  , iname    = "vial"
+  , ifreq    = [("useful", 15)]
+  , iflavour = zipFancy stdCol
+  , icount   = intToDeep 1
+  , iverbApply   = "gulp down"
+  , iverbProject = "lob"
+  , iweight  = 200
+  , itoThrow = -50  -- oily, bad grip
+  , ifeature = []
+  }
+potion1 = potion
+  { ifreq    = [("useful", 5)]
+  , ifeature = [Cause ApplyPerfume, Explode "fragrance"]
+  }
+potion2 = potion
+  { ifeature = [Cause $ Heal 5, Explode "mist healing"]
+  }
+potion3 = potion
+  { ifreq    = [("useful", 5)]
+  , ifeature = [Cause $ Heal (-5), Explode "mist wounding"]
+  }
+ring = ItemKind
+  { isymbol  = '='
+  , iname    = "ring"
+  , ifreq    = []  -- [("useful", 10)]  -- TODO: make it useful
+  , iflavour = zipPlain [White]
+  , icount   = intToDeep 1
+  , iverbApply   = "squeeze down"
+  , iverbProject = "toss"
+  , iweight  = 15
+  , itoThrow = 0
+  , ifeature = [Cause $ Searching (rollDeep (1, 6) (3, 2))]
+  }
+scroll = ItemKind
+  { isymbol  = '?'
+  , iname    = "tablet"
+  , ifreq    = [("useful", 4)]
+  , iflavour = zipFancy darkCol  -- arcane and old
+  , icount   = intToDeep 1
+  , iverbApply   = "dial"
+  , iverbProject = "lob"
+  , iweight  = 700
+  , itoThrow = -25  -- bad grip
+  , ifeature = []
+  }
+scroll1 = scroll
+  { ifreq    = [("useful", 2)]
+  , ifeature = [Cause $ CallFriend 1]
+  }
+scroll2 = scroll
+  { ifeature = [Cause $ Summon 1]
+  }
+scroll3 = scroll
+  { ifeature = [Cause $ Ascend 1]
+  }
+sword = ItemKind
+  { isymbol  = '/'
+  , iname    = "sharpened pipe"
+  , ifreq    = [("useful", 40)]
+  , iflavour = zipPlain [Cyan]
+  , icount   = intToDeep 1
+  , iverbApply   = "hit"
+  , iverbProject = "heave"
+  , iweight  = 3000
+  , itoThrow = -25  -- bad grip
+  , ifeature = [Cause $ Hurt (rollDice 5 1) (rollDeep (1, 2) (4, 2))]
+  }
+wand = ItemKind
+  { isymbol  = '-'
+  , iname    = "injector"
+  , ifreq    = [("useful", 5)]
+  , iflavour = zipFancy brightCol
+  , icount   = intToDeep 1
+  , iverbApply   = "snap"
+  , iverbProject = "zap"
+  , iweight  = 300
+  , itoThrow = 25  -- jet
+  , ifeature = [Fragile]
+  }
+wand1 = wand
+  { ifeature = ifeature wand ++ [Cause Dominate]
+  }
+wand2 = wand
+  { ifreq    = [("useful", 2)]
+  , ifeature = ifeature wand ++ [Cause $ Heal (-25)]
+  }
+fist = sword
+  { isymbol  = '@'
+  , iname    = "fist"
+  , ifreq    = [("hth", 1), ("unarmed", 100)]
+  , iverbApply   = "punch"
+  , iverbProject = "ERROR, please report: iverbProject fist"
+  , ifeature = [Cause $ Hurt (rollDice 5 1) (intToDeep 0)]
+  }
+foot = sword
+  { isymbol  = '@'
+  , iname    = "foot"
+  , ifreq    = [("hth", 1), ("unarmed", 50)]
+  , iverbApply   = "kick"
+  , iverbProject = "ERROR, please report: iverbProject foot"
+  , ifeature = [Cause $ Hurt (rollDice 5 1) (intToDeep 0)]
+  }
+tentacle = sword
+  { isymbol  = 'S'
+  , iname    = "tentacle"
+  , ifreq    = [("hth", 1), ("monstrous", 100)]
+  , iverbApply   = "hit"
+  , iverbProject = "ERROR, please report: iverbProject tentacle"
+  , ifeature = [Cause $ Hurt (rollDice 5 1) (intToDeep 0)]
+  }
+fragrance = ItemKind
+  { isymbol  = '\''
+  , iname    = "fragrance"
+  , ifreq    = [("fragrance", 1)]
+  , iflavour = zipFancy [BrMagenta]
+  , icount   = rollDeep (5, 2) (0, 0)
+  , iverbApply   = "smell"
+  , iverbProject = "exude"
+  , iweight  = 1
+  , itoThrow = -93  -- the slowest that gets anywhere (1 step only)
+  , ifeature = [Fragile]
+  }
+mist_healing = ItemKind
+  { isymbol  = '\''
+  , iname    = "mist"
+  , ifreq    = [("mist healing", 1)]
+  , iflavour = zipFancy [White]
+  , icount   = rollDeep (12, 2) (0, 0)
+  , iverbApply   = "inhale"
+  , iverbProject = "blow"
+  , iweight  = 1
+  , itoThrow = -87  -- the slowest that travels at least 2 steps
+  , ifeature = [Cause $ Heal 1, Fragile]
+  }
+mist_wounding = ItemKind
+  { isymbol  = '\''
+  , iname    = "mist"
+  , ifreq    = [("mist wounding", 1)]
+  , iflavour = zipFancy [White]
+  , icount   = rollDeep (12, 2) (0, 0)
+  , iverbApply   = "inhale"
+  , iverbProject = "blow"
+  , iweight  = 1
+  , itoThrow = -87
+  , ifeature = [Cause $ Heal (-1), Fragile]
+  }
+glass_piece = ItemKind
+  { isymbol  = '\''
+  , iname    = "glass piece"
+  , ifreq    = [("glass piece", 1)]
+  , iflavour = zipPlain [BrBlue]
+  , icount   = rollDeep (10, 2) (0, 0)
+  , iverbApply   = "grate"
+  , iverbProject = "toss"
+  , iweight  = 10
+  , itoThrow = 0
+  , ifeature = [Cause $ Hurt (rollDice 1 1) (intToDeep 0), Fragile, Linger 20]
+  }
+smoke = ItemKind
+  { isymbol  = '\''
+  , iname    = "smoke"
+  , ifreq    = [("smoke", 1)]
+  , iflavour = zipPlain [BrBlack]
+  , icount   = rollDeep (12, 2) (0, 0)
+  , iverbApply   = "inhale"
+  , iverbProject = "blow"
+  , iweight  = 1
+  , itoThrow = -70
+  , ifeature = [Fragile]
+  }
diff --git a/GameDefinition/Content/ModeKind.hs b/GameDefinition/Content/ModeKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/ModeKind.hs
@@ -0,0 +1,364 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | The type of kinds of game modes for Allure of the Stars.
+module Content.ModeKind ( cdefs ) where
+
+import qualified Data.EnumMap.Strict as EM
+
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Content.ModeKind
+
+cdefs :: ContentDef ModeKind
+cdefs = ContentDef
+  { getSymbol = msymbol
+  , getName = mname
+  , getFreq = mfreq
+  , validate = validateModeKind
+  , content =
+      [campaign, skirmish, battle, pvp, coop, defense, testCampaign, testSkirmish, testBattle, testPvP, testCoop, testDefense, peekCampaign, peekSkirmish]
+  }
+campaign,        skirmish, battle, pvp, coop, defense, testCampaign, testSkirmish, testBattle, testPvP, testCoop, testDefense, peekCampaign, peekSkirmish :: ModeKind
+
+campaign = ModeKind
+  { msymbol  = 'r'
+  , mname    = "campaign"
+  , mfreq    = [("campaign", 1)]
+  , mplayers = playersCampaign
+  , mcaves   = cavesCampaign
+  }
+
+skirmish = ModeKind
+  { msymbol  = 'k'
+  , mname    = "skirmish"
+  , mfreq    = [("skirmish", 1)]
+  , mplayers = playersSkirmish
+  , mcaves   = cavesCombat
+  }
+
+battle = ModeKind
+  { msymbol  = 'b'
+  , mname    = "battle"
+  , mfreq    = [("battle", 1)]
+  , mplayers = playersBattle
+  , mcaves   = cavesBattle
+  }
+
+pvp = ModeKind
+  { msymbol  = 'v'
+  , mname    = "PvP"
+  , mfreq    = [("PvP", 1)]
+  , mplayers = playersPvP
+  , mcaves   = cavesCombat
+  }
+
+coop = ModeKind
+  { msymbol  = 'o'
+  , mname    = "Coop"
+  , mfreq    = [("Coop", 1)]
+  , mplayers = playersCoop
+  , mcaves   = cavesCampaign
+  }
+
+defense = ModeKind
+  { msymbol  = 'e'
+  , mname    = "defense"
+  , mfreq    = [("defense", 1)]
+  , mplayers = playersDefense
+  , mcaves   = cavesCampaign
+  }
+
+testCampaign = ModeKind
+  { msymbol  = 't'
+  , mname    = "testCampaign"
+  , mfreq    = [("testCampaign", 1)]
+  , mplayers = playersTestCampaign
+  , mcaves   = cavesCampaign
+  }
+
+testSkirmish = ModeKind
+  { msymbol  = 't'
+  , mname    = "testSkirmish"
+  , mfreq    = [("testSkirmish", 1)]
+  , mplayers = playersTestSkirmish
+  , mcaves   = cavesCombat
+  }
+
+testBattle = ModeKind
+  { msymbol  = 't'
+  , mname    = "testBattle"
+  , mfreq    = [("testBattle", 1)]
+  , mplayers = playersTestBattle
+  , mcaves   = cavesBattle
+  }
+
+testPvP = ModeKind
+  { msymbol  = 't'
+  , mname    = "testPvP"
+  , mfreq    = [("testPvP", 1)]
+  , mplayers = playersTestPvP
+  , mcaves   = cavesCombat
+  }
+
+testCoop = ModeKind
+  { msymbol  = 't'
+  , mname    = "testCoop"
+  , mfreq    = [("testCoop", 1)]
+  , mplayers = playersTestCoop
+  , mcaves   = cavesCampaign
+  }
+
+testDefense = ModeKind
+  { msymbol  = 't'
+  , mname    = "testDefense"
+  , mfreq    = [("testDefense", 1)]
+  , mplayers = playersTestDefense
+  , mcaves   = cavesCampaign
+  }
+
+peekCampaign = ModeKind
+  { msymbol  = 'p'
+  , mname    = "peekCampaign"
+  , mfreq    = [("peekCampaign", 1)]
+  , mplayers = playersPeekCampaign
+  , mcaves   = cavesCampaign
+  }
+
+peekSkirmish = ModeKind
+  { msymbol  = 'p'
+  , mname    = "peekSkirmish"
+  , mfreq    = [("peekSkirmish", 1)]
+  , mplayers = playersPeekSkirmish
+  , mcaves   = cavesCombat
+  }
+
+
+playersCampaign, playersSkirmish, playersBattle, playersPvP, playersCoop, playersDefense, playersTestCampaign, playersTestSkirmish, playersTestBattle, playersTestPvP, playersTestCoop, playersTestDefense, playersPeekCampaign, playersPeekSkirmish :: Players
+
+playersCampaign = Players
+  { playersList = [ playerHero {playerInitial = 1}
+                  , playerMonster
+                  , playerAnimal
+                  , playerRobot ]
+  , playersEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")
+                   , ("Spacefarer Crew", "Animal Kingdom")
+                   , ("Spacefarer Crew", "Robot Anarchy") ]
+  , playersAlly = [] }
+
+playersSkirmish = Players
+  { playersList = [ playerHero {playerName = "White"}
+                  , playerAntiHero {playerName = "Purple"}
+                  , playerHorror ]
+  , playersEnemy = [ ("White", "Purple")
+                   , ("White", "Horror Den")
+                   , ("Purple", "Horror Den") ]
+  , playersAlly = [] }
+
+playersBattle = Players
+  { playersList = [ playerHero {playerInitial = 5}
+                  , playerMonster { playerInitial = 10
+                                  , playerSpawn = 0 }
+                  , playerAnimal { playerInitial = 10
+                                 , playerSpawn = 0 }
+                  , playerRobot { playerInitial = 10
+                                , playerSpawn = 0 } ]
+  , playersEnemy = [ ("Spacefarer Crew", "Alien Hierarchy")
+                   , ("Spacefarer Crew", "Animal Kingdom")
+                   , ("Spacefarer Crew", "Robot Anarchy") ]
+  , playersAlly = [] }
+
+playersPvP = Players
+  { playersList = [ playerHero {playerName = "Red"}
+                  , playerHero {playerName = "Blue"}
+                  , playerHorror ]
+  , playersEnemy = [ ("Red", "Blue")
+                   , ("Red", "Horror Den")
+                   , ("Blue", "Horror Den") ]
+  , playersAlly = [] }
+
+playersCoop = Players
+  { playersList = [ playerHero { playerName = "Coral"
+                               , playerInitial = 1 }
+                  , playerHero { playerName = "Amber"
+                               , playerInitial = 1 }
+                  , playerMonster
+                  , playerAnimal
+                  , playerRobot ]
+  , playersEnemy = [ ("Coral", "Alien Hierarchy")
+                   , ("Coral", "Animal Kingdom")
+                   , ("Coral", "Robot Anarchy")
+                   , ("Amber", "Alien Hierarchy")
+                   , ("Amber", "Animal Kingdom")
+                   , ("Amber", "Robot Anarchy") ]
+  , playersAlly = [("Coral", "Amber")] }
+
+playersDefense = Players
+  { playersList = [ playerMonster { playerInitial = 1
+                                  , playerAiLeader = False
+                                  , playerHuman = True
+                                  , playerUI = True }
+                  , playerAnimal
+                  , playerRobot
+                  , playerAntiHero {playerName = "Green"}
+                  , playerAntiHero {playerName = "Yellow"}
+                  , playerAntiHero {playerName = "Cyan"} ]
+  , playersEnemy = [ ("Green", "Alien Hierarchy")
+                   , ("Green", "Animal Kingdom")
+                   , ("Green", "Robot Anarchy")
+                   , ("Yellow", "Alien Hierarchy")
+                   , ("Yellow", "Animal Kingdom")
+                   , ("Yellow", "Robot Anarchy")
+                   , ("Cyan", "Alien Hierarchy")
+                   , ("Cyan", "Animal Kingdom")
+                   , ("Cyan", "Robot Anarchy") ]
+  , playersAlly = [ ("Green", "Yellow")
+                  , ("Green", "Cyan")
+                  , ("Yellow", "Cyan") ] }
+
+playersTestCampaign = playersCampaign
+  { playersList = [ playerHero { playerInitial = 5
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerMonster
+                  , playerAnimal
+                  , playerRobot ] }
+
+playersTestSkirmish = playersSkirmish
+  { playersList = [ playerHero { playerName = "White"
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerAntiHero { playerName = "Purple" }
+                  , playerHorror ] }
+
+playersTestBattle = playersBattle
+  { playersList = [ playerHero { playerInitial = 5
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerMonster { playerInitial = 10
+                                  , playerSpawn = 0 }
+                  , playerAnimal { playerInitial = 10
+                                 , playerSpawn = 0 }
+                  , playerRobot { playerInitial = 10
+                                , playerSpawn = 0 } ] }
+
+playersTestPvP = playersPvP
+  { playersList = [ playerHero { playerName = "Red"
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerHero { playerName = "Blue"
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerHorror ] }
+
+playersTestCoop = playersCoop
+  { playersList = [ playerHero { playerName = "Coral"
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerHero { playerName = "Amber"
+                               , playerAiLeader = True
+                               , playerHuman = False }
+                  , playerMonster
+                  , playerAnimal
+                  , playerRobot ] }
+
+playersTestDefense = playersDefense
+  { playersList = [ playerMonster { playerInitial = 1
+                                  , playerUI = True }
+                  , playerAnimal
+                  , playerRobot
+                  , playerAntiHero {playerName = "Green"}
+                  , playerAntiHero {playerName = "Yellow"}
+                  , playerAntiHero {playerName = "Cyan"} ] }
+
+playersPeekCampaign = playersCampaign
+  { playersList = [ playerHero {playerInitial = 1}
+                  , playerMonster {playerUI = True}
+                  , playerAnimal
+                  , playerRobot ] }
+
+playersPeekSkirmish = playersSkirmish
+  { playersList = [ playerHero {playerName = "White"}
+                  , playerAntiHero { playerName = "Purple"
+                                   , playerUI = True }
+                  , playerHorror ] }
+
+
+playerHero, playerAntiHero, playerMonster, playerAnimal, playerRobot, playerHorror :: Player
+
+playerHero = Player
+  { playerName = "Spacefarer Crew"
+  , playerFaction = "hero"
+  , playerSpawn = 0
+  , playerEntry = toEnum 1
+  , playerInitial = 3
+  , playerAiLeader = False
+  , playerAiOther = True
+  , playerHuman = True
+  , playerUI = True
+  }
+
+playerAntiHero = playerHero
+  { playerAiLeader = True
+  , playerHuman = False
+  , playerUI = False
+  }
+
+playerMonster = Player
+  { playerName = "Alien Hierarchy"
+  , playerFaction = "alien"
+  , playerSpawn = 20
+  , playerEntry = toEnum 5
+  , playerInitial = 3
+  , playerAiLeader = True
+  , playerAiOther = True
+  , playerHuman = False
+  , playerUI = False
+  }
+
+playerAnimal = Player
+  { playerName = "Animal Kingdom"
+  , playerFaction = "animal"
+  , playerSpawn = 50
+  , playerEntry = toEnum 3
+  , playerInitial = 3
+  , playerAiLeader = True
+  , playerAiOther = True
+  , playerHuman = False
+  , playerUI = False
+  }
+
+playerRobot = Player
+  { playerName = "Robot Anarchy"
+  , playerFaction = "robot"
+  , playerSpawn = 10
+  , playerEntry = toEnum 4
+  , playerInitial = 3
+  , playerAiLeader = True
+  , playerAiOther = True
+  , playerHuman = False
+  , playerUI = False
+  }
+
+playerHorror = Player
+  { playerName = "Horror Den"
+  , playerFaction = "horror"
+  , playerSpawn = 0
+  , playerEntry = toEnum 1
+  , playerInitial = 0
+  , playerAiLeader = True
+  , playerAiOther = True
+  , playerHuman = False
+  , playerUI = False
+  }
+
+
+cavesCampaign, cavesCombat, cavesBattle :: Caves
+
+cavesCampaign = EM.fromList [ (toEnum 1, ("caveRogue", Nothing))
+                            , (toEnum 12, ("caveNoise", Just True))]
+
+cavesCombat = EM.fromList [(toEnum 3, ("caveCombat", Nothing))]
+
+cavesBattle = EM.fromList [(toEnum (-3), ("caveBattle", Nothing))]
diff --git a/GameDefinition/Content/PlaceKind.hs b/GameDefinition/Content/PlaceKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/PlaceKind.hs
@@ -0,0 +1,148 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Rooms, halls and passages for Allure of the Stars.
+module Content.PlaceKind ( cdefs ) where
+
+import Game.LambdaHack.Common.ContentDef
+import Game.LambdaHack.Content.PlaceKind
+
+cdefs :: ContentDef PlaceKind
+cdefs = ContentDef
+  { getSymbol = psymbol
+  , getName = pname
+  , getFreq = pfreq
+  , validate = validatePlaceKind
+  , content =
+      [rect, oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells]
+  }
+rect,        oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind
+
+rect = PlaceKind  -- Valid for any nonempty area, hence low frequency.
+  { psymbol  = 'r'
+  , pname    = "room"
+  , pfreq    = [("rogue", 100)]
+  , pcover   = CStretch
+  , pfence   = FWall
+  , ptopLeft = ["."]
+  }
+oval = PlaceKind
+  { psymbol  = 'o'
+  , pname    = "oval room"
+  , pfreq    = [("rogue", 1000)]
+  , pcover   = CStretch
+  , pfence   = FWall
+  , ptopLeft = [ "####.."
+               , "##...."
+               , "#....."
+               , "#....."
+               , "......"
+               , "......"
+               ]
+  }
+ovalFloor = oval  -- Without outer solid fence, visible from outside.
+  { pfreq    = [("rogue", 10000)]
+  , pfence   = FFloor
+  , ptopLeft = [ "XXXX+#"
+               , "XX###."
+               , "X##..."
+               , "X#...."
+               , "+#...."
+               , "#....."
+               ]
+  }
+ovalSquare = ovalFloor
+  { ptopLeft = [ "X###+"
+               , "##..."
+               , "#...."
+               , "#...."
+               , "+...."
+               ]
+  }
+colonnade = PlaceKind
+  { psymbol  = 'c'
+  , pname    = "colonnade"
+  , pfreq    = [("rogue", 1000)]
+  , pcover   = CAlternate
+  , pfence   = FFloor
+  , ptopLeft = [ ".#"
+               , "#."
+               ]
+  }
+colonnadeWide = colonnade
+  { pfreq    = [("rogue", 50)]
+  , pfence   = FWall
+  , ptopLeft = [ ".."
+               , ".#"
+               ]
+  }
+maze = PlaceKind
+  { psymbol  = 'm'
+  , pname    = "maze"
+  , pfreq    = [("rogue", 20)]
+  , pcover   = CStretch
+  , pfence   = FNone
+  , ptopLeft = [ "#.#.##"
+               , "##.#.."
+               , "#.##.#"
+               , "#.#.#."
+               ]
+  }
+maze2 = maze
+  { ptopLeft = [ "###.##"
+               , ".###.."
+               , "..#..#"
+               , ".#..#."
+               ]
+  }
+maze3 = maze
+  { ptopLeft = [ "###.##"
+               , ".##.#."
+               , "..##.#"
+               , ".#..#."
+               ]
+  }
+mazeBig = maze
+  { pfreq    = [("rogue", 1000)]
+  , ptopLeft = [ "#.#.##"
+               , ".#.#.."
+               , "#.&.##"
+               , ".#.#.."
+               , "#.#..#"
+               , "#.#.#."
+               ]
+  }
+mazeBig2 = mazeBig
+  { ptopLeft = [ "##..##"
+               , "#.##.."
+               , ".#.###"
+               , ".##.#."
+               , "#.#&.#"
+               , "#.#.#."
+               ]
+  }
+mazeBig3 = mazeBig
+  { ptopLeft = [ "##..##"
+               , "#.###."
+               , ".#...#"
+               , ".#.##."
+               , "##.#.#"
+               , "#.#.#."
+               ]
+  }
+cells = PlaceKind
+  { psymbol  = '#'
+  , pname    = "cells"
+  , pfreq    = [("rogue", 30)]
+  , pcover   = CReflect
+  , pfence   = FWall
+  , ptopLeft = [ "..#"
+               , "..#"
+               , "##."
+               ]
+  }
+-- TODO: obtain all the reet as places nested within places.
+-- 3 places are enough, with 1 or 2 tiles between places,
+-- on all sides, only vertical, only horizontal,
diff --git a/GameDefinition/Content/RuleKind.hs b/GameDefinition/Content/RuleKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/RuleKind.hs
@@ -0,0 +1,202 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Game rules and assorted game setup data for Allure of the Stars.
+module Content.RuleKind ( cdefs ) where
+
+import Control.Arrow (first)
+import Language.Haskell.TH.Syntax
+import System.FilePath
+
+-- Cabal
+import qualified Paths_Allure as Self (getDataFileName, version)
+
+import Game.LambdaHack.Common.ContentDef
+import qualified Game.LambdaHack.Common.Effect as Effect
+import qualified Game.LambdaHack.Common.Feature as F
+import Game.LambdaHack.Common.HumanCmd
+import qualified Game.LambdaHack.Common.Key as K
+import Game.LambdaHack.Content.RuleKind
+
+cdefs :: ContentDef RuleKind
+cdefs = ContentDef
+  { getSymbol = rsymbol
+  , getName = rname
+  , getFreq = rfreq
+  , validate = validateRuleKind
+  , content =
+      [standard]
+  }
+
+standard :: RuleKind
+standard = RuleKind
+  { rsymbol        = 's'
+  , rname          = "standard Allure of the Stars ruleset"
+  , rfreq          = [("standard", 100)]
+  -- Check whether one position is accessible from another.
+  -- Precondition: the two positions are next to each other.
+  -- TODO: in the future check flying for chasms, swimming for water, etc.
+  , raccessible    = Nothing
+  , raccessibleDoor = Nothing
+  , rtitle         = "Allure of the Stars"
+  , rpathsDataFile = Self.getDataFileName
+  , rpathsVersion  = Self.version
+  , ritemMelee     = "/|\\"
+  , ritemRanged    = "}{"
+  -- Wasting weapons and armour would be too cruel to the player.
+  , ritemProject   = "!?,-~}{"
+  -- The strings containing the default configuration file
+  -- included from config.ui.default.
+  , rcfgUIName = "config.ui"
+  , rcfgUIDefault = $(do
+      let path = "GameDefinition" </> "config.ui" ++ ".default"
+      qAddDependentFile path
+      x <- qRunIO (readFile path)
+      lift x)
+  -- ASCII art for the Main Menu. Only pure 7-bit ASCII characters are
+  -- allowed. The picture should be exactly 24 rows by 80 columns,
+  -- plus an extra frame (of any characters) that is ignored.
+  -- For a different screen size, the picture is centered and the outermost
+  -- rows and columns cloned. When displayed in the Main Menu screen,
+  -- it's overwritten with the game version string and keybinding strings.
+  -- The game version string begins and ends with a space and is placed
+  -- in the very bottom right corner. The keybindings overwrite places
+  -- marked with 25 left curly brace signs '{' in a row. The sign is forbidden
+  -- everywhere else. A specific number of such places with 25 left braces
+  -- are required, at most one per row, and all are overwritten
+  -- with text that is flushed left and padded with spaces.
+  -- The Main Menu is displayed dull white on black.
+  -- TODO: Show highlighted keybinding in inverse video or bright white on grey
+  -- background. The spaces that pad keybindings are not highlighted.
+  , rmainMenuArt = $(do
+      let path = "GameDefinition/MainMenu.ascii"
+      qAddDependentFile path
+      x <- qRunIO (readFile path)
+      lift x)
+  , rhumanCommands = map (first K.mkKM)
+      -- All commands are defined here, except some movement and leader picking
+      -- commands. All commands are shown on help screens except debug commands
+      -- and macros with empty descriptions.
+      -- The order below determines the order on the help screens.
+      -- Remember to put commands that show information (e.g., enter targeting
+      -- mode) first.
+
+      -- Main Menu, which apart of these includes a few extra commands
+      [ ("CTRL-x", (CmdMenu, GameExit))
+      , ("CTRL-r", (CmdMenu, GameRestart "campaign"))
+      , ("CTRL-k", (CmdMenu, GameRestart "skirmish"))
+      , ("CTRL-v", (CmdMenu, GameRestart "PvP"))
+      , ("CTRL-o", (CmdMenu, GameRestart "Coop"))
+      , ("CTRL-e", (CmdMenu, GameRestart "defense"))
+      , ("CTRL-d", (CmdMenu, GameDifficultyCycle))
+
+      -- Movement and terrain alteration
+      , ("less", (CmdMove, TriggerTile
+           [ TriggerFeature { verb = "ascend"
+                            , object = "a level"
+                            , feature = F.Cause (Effect.Ascend 1) }
+           , TriggerFeature { verb = "exit"
+                            , object = "spaceship"
+                            , feature = F.Cause (Effect.Escape 1) } ]))
+      , ("CTRL-less", (CmdMove, TriggerTile
+           [ TriggerFeature { verb = "ascend"
+                            , object = "10 levels"
+                            , feature = F.Cause (Effect.Ascend 10) } ]))
+      , ("greater", (CmdMove, TriggerTile
+           [ TriggerFeature { verb = "descend"
+                            , object = "a level"
+                            , feature = F.Cause (Effect.Ascend (-1)) }
+           , TriggerFeature { verb = "exit"
+                            , object = "spaceship"
+                            , feature = F.Cause (Effect.Escape (-1)) } ]))
+      , ("CTRL-greater", (CmdMove, TriggerTile
+           [ TriggerFeature { verb = "descend"
+                            , object = "10 levels"
+                            , feature = F.Cause (Effect.Ascend (-10)) } ]))
+      , ("CTRL-semicolon", (CmdMove, StepToTarget))
+      , ("semicolon", (CmdMove, Macro "go to target for 100 steps"
+                                      ["CTRL-semicolon", "P"]))
+      , ("x", (CmdMove, Macro "explore the closest unknown spot"
+                              [ "BackSpace"
+                              , "CTRL-question", "CTRL-semicolon", "P" ]))
+      , ("X", (CmdMove, Macro "autoexplore 100 times"
+                              [ "BackSpace"
+                              , "'", "CTRL-question", "CTRL-semicolon", "'"
+                              , "P" ]))
+      , ("R", (CmdMove, Macro "rest (wait 100 times)" ["KP_Begin", "P"]))
+      , ("c", (CmdMove, AlterDir
+           [ AlterFeature { verb = "close"
+                          , object = "door"
+                          , feature = F.CloseTo "closed door" } ]))
+
+      -- Inventory and items
+      , ("I", (CmdItem, Inventory))
+      , ("g", (CmdItem, Pickup))
+      , ("d", (CmdItem, Drop))
+      , ("q", (CmdItem, Apply [ApplyItem { verb = "quaff"
+                                         , object = "drink"
+                                         , symbol = '!' }]))
+      , ("r", (CmdItem, Apply [ApplyItem { verb = "read"
+                                         , object = "tablet"
+                                         , symbol = '?' }]))
+      , ("a", (CmdItem, Apply [ApplyItem { verb = "apply"
+                                         , object = "consumable"
+                                         , symbol = ' ' }]))
+-- a: Apply [ApplyItem {verb = "apply", object = "consumable", symbol = ' '}, ApplyItem {verb = "eat", object = "food", symbol = ','}, ApplyItem {verb = "activate", object = "emitter", symbol = '_'}, ApplyItem {verb = "use", object = "tool", symbol = '~'}, ApplyItem {verb = "quaff", object = "drink", symbol = '!'}, ApplyItem {verb = "read", object = "tablet", symbol = '?'}]
+      , ("t", (CmdItem, Project [ ApplyItem { verb = "throw"
+                                            , object = "projectile"
+                                            , symbol = '}' }
+                                , ApplyItem { verb = "throw"
+                                            , object = "projectile"
+                                            , symbol = '{' } ]))
+      , ("z", (CmdItem, Project [ ApplyItem { verb = "zap"
+                                            , object = "mechanism"
+                                            , symbol = '-' } ]))
+      , ("f", (CmdItem, Project [ ApplyItem { verb = "fling"
+                                            , object = "missile"
+                                            , symbol = ' ' } ]))
+-- f: Project [ApplyItem {verb = "fling", object = "missile", symbol = ' '}, ApplyItem {verb = "throw", object = "projectile", symbol = '}'}, ApplyItem {verb = "throw", object = "projectile", symbol = '{'}, ApplyItem {verb = "zap", object = "mechanism", symbol = '-'}]
+
+      -- Targeting
+      , ("asterisk", (CmdTgt, TgtEnemy))
+      , ("slash", (CmdTgt, TgtFloor))
+      , ("plus", (CmdTgt, EpsIncr True))
+      , ("minus", (CmdTgt, EpsIncr False))
+      , ("BackSpace", (CmdTgt, TgtClear))
+      , ("CTRL-question", (CmdTgt, TgtUnknown))
+      , ("CTRL-I", (CmdTgt, TgtItem))
+      , ("CTRL-braceleft", (CmdTgt, TgtStair True))
+      , ("CTRL-braceright", (CmdTgt, TgtStair False))
+
+      -- Assorted
+      , ("question", (CmdMeta, Help))
+      , ("D", (CmdMeta, History))
+      , ("T", (CmdMeta, MarkSuspect))
+      , ("V", (CmdMeta, MarkVision))
+      , ("S", (CmdMeta, MarkSmell))
+      , ("Tab", (CmdMeta, MemberCycle))
+      , ("ISO_Left_Tab", (CmdMeta, MemberBack))
+      , ("equal", (CmdMeta, SelectActor))
+      , ("underscore", (CmdMeta, SelectNone))
+      , ("p", (CmdMeta, Repeat 1))
+      , ("P", (CmdMeta, Repeat 100))
+      , ("CTRL-p", (CmdMeta, Repeat 1000))
+      , ("apostrophe", (CmdMeta, Record))
+      , ("space", (CmdMeta, Clear))
+      , ("Escape", (CmdMeta, Cancel))
+      , ("Return", (CmdMeta, Accept))
+
+      -- Debug and others not to display in help screens
+      , ("CTRL-s", (CmdDebug, GameSave))
+      , ("CTRL-y", (CmdDebug, Resend))
+      ]
+  , rfirstDeathEnds = False
+  , rfovMode = Digital 12
+  , rsaveBkpClips = 500
+  , rleadLevelClips = 100
+  , rscoresFile = "scores"
+  , rsavePrefix = "save"
+  }
diff --git a/GameDefinition/Content/TileKind.hs b/GameDefinition/Content/TileKind.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Content/TileKind.hs
@@ -0,0 +1,227 @@
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | Terrain tiles for Allure of the Stars.
+module Content.TileKind ( cdefs ) where
+
+import Control.Arrow (first)
+import Data.Text (Text)
+import qualified Data.Text as T
+
+import Game.LambdaHack.Common.Color
+import Game.LambdaHack.Common.ContentDef
+import qualified Game.LambdaHack.Common.Effect as Effect
+import Game.LambdaHack.Common.Feature
+import Game.LambdaHack.Common.Msg
+import Game.LambdaHack.Content.TileKind
+
+cdefs :: ContentDef TileKind
+cdefs = ContentDef
+  { getSymbol = tsymbol
+  , getName = tname
+  , getFreq = tfreq
+  , validate = validateTileKind
+  , content =
+      [wall, wallCache, hardRock, oriel, pillar, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorRedLit, floorBlueLit, floorGreenLit]
+      ++ map makeDarkColor [floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit]
+  }
+wall,        wallCache, hardRock, oriel, pillar, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorRedLit, floorBlueLit, floorGreenLit :: TileKind
+
+wall = TileKind
+  { tsymbol  = '#'
+  , tname    = "granite wall"
+  , tfreq    = [ ("fillerWall", 1), ("cachable", 70)
+               , ("legendLit", 100), ("legendDark", 100)
+               , ("noiseSet", 55) ]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [HideAs "suspect wall"]
+  }
+wallCache = TileKind
+  { tsymbol  = '&'
+  , tname    = "cache"
+  , tfreq    = [ ("cachable", 30)
+               , ("legendLit", 100), ("legendDark", 100) ]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [Suspect, Cause $ Effect.CreateItem 1, ChangeTo "cachable"]
+  }
+hardRock = TileKind
+  { tsymbol  = '#'
+  , tname    = "outer hull"
+  , tfreq    = [("basic outer fence", 100), ("oriels fence", 98)]
+  , tcolor   = BrBlack
+  , tcolor2  = BrBlack
+  , tfeature = [Impenetrable]
+  }
+oriel = TileKind
+  { tsymbol  = '\''
+  , tname    = "oriel"
+  , tfreq    = [("oriels fence", 2)]
+  , tcolor   = White
+  , tcolor2  = Black
+  , tfeature = [Dark, Impenetrable]
+  }
+pillar = TileKind
+  { tsymbol  = 'O'
+  , tname    = "rock"
+  , tfreq    = [ ("legendLit", 100), ("legendDark", 100)
+               , ("combatSet", 3), ("battleSet", 9) ]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = []
+  }
+tree = TileKind
+  { tsymbol  = 'O'
+  , tname    = "tree"
+  , tfreq    = [("combatSet", 8)]
+  , tcolor   = BrGreen
+  , tcolor2  = Green
+  , tfeature = []
+  }
+wallSuspect = TileKind
+  { tsymbol  = '#'
+  , tname    = "moldy wall"
+  , tfreq    = [("suspect wall", 1)]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [Suspect, RevealAs "closed door"]
+  }
+doorClosed = TileKind
+  { tsymbol  = '+'
+  , tname    = "closed door"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100), ("closed door", 1)]
+  , tcolor   = Brown
+  , tcolor2  = BrBlack
+  , tfeature = [OpenTo "open door", HideAs "suspect wall"]
+  }
+doorOpen = TileKind
+  { tsymbol  = '\''
+  , tname    = "open door"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100), ("open door", 1)]
+  , tcolor   = Brown
+  , tcolor2  = BrBlack
+  , tfeature = [Walkable, Clear, CloseTo "closed door"]
+  }
+stairsUp = TileKind
+  { tsymbol  = '<'
+  , tname    = "staircase up"
+  , tfreq    = []  -- TODO: [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [Walkable, Clear, Cause $ Effect.Ascend 1]
+  }
+stairsDown = TileKind
+  { tsymbol  = '>'
+  , tname    = "staircase down"
+  , tfreq    = []  -- TODO: [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [Walkable, Clear, Cause $ Effect.Ascend (-1)]
+  }
+escapeUp = TileKind
+  { tsymbol  = '<'
+  , tname    = "exit airlock up"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrYellow
+  , tcolor2  = BrYellow
+  , tfeature = [Walkable, Clear, Cause $ Effect.Escape 1]
+  }
+escapeDown = TileKind
+  { tsymbol  = '>'
+  , tname    = "exit airlock down"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrYellow
+  , tcolor2  = BrYellow
+  , tfeature = [Walkable, Clear, Cause $ Effect.Escape (-1)]
+  }
+liftUp = TileKind
+  { tsymbol  = '<'
+  , tname    = "lift up"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrCyan
+  , tcolor2  = BrCyan
+  , tfeature = [Walkable, Clear, Cause $ Effect.Ascend 1]
+  }
+lift = TileKind
+  { tsymbol  = '<'
+  , tname    = "lift"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrBlue
+  , tcolor2  = BrBlue
+  , tfeature = [ Walkable, Clear
+               , Cause $ Effect.Ascend 1
+               , Cause $ Effect.Ascend (-1) ]
+  }
+liftDown = TileKind
+  { tsymbol  = '>'
+  , tname    = "lift down"
+  , tfreq    = [("legendLit", 100), ("legendDark", 100)]
+  , tcolor   = BrCyan
+  , tcolor2  = BrCyan
+  , tfeature = [Walkable, Clear, Cause $ Effect.Ascend (-1)]
+  }
+unknown = TileKind
+  { tsymbol  = ' '
+  , tname    = "unknown space"
+  , tfreq    = [("unknown space", 1)]
+  , tcolor   = defFG
+  , tcolor2  = defFG
+  , tfeature = [Dark]
+  }
+floorCorridorLit = TileKind
+  { tsymbol  = '.'
+  , tname    = "floor"
+  , tfreq    = [ ("floorCorridorLit", 1), ("floorArenaLit", 1)
+               , ("arenaSet", 1), ("noiseSet", 100), ("combatSet", 100) ]
+  , tcolor   = BrWhite
+  , tcolor2  = defFG
+  , tfeature = [Walkable, Clear]
+  }
+floorActorLit = floorCorridorLit
+  { tfreq    = [("floorActorLit", 1), ("battleSet", 100)]
+  , tfeature = CanActor : tfeature floorCorridorLit
+  }
+floorItemLit = floorCorridorLit
+  { tfreq    = []
+  , tfeature = CanItem : tfeature floorCorridorLit
+  }
+floorActorItemLit = floorItemLit
+  { tfreq    = [("legendLit", 100), ("emptySet", 1)]
+  , tfeature = CanActor : tfeature floorItemLit
+  }
+floorRedLit = floorCorridorLit
+  { tname    = "emergency walkway"
+  , tfreq    = [("trailLit", 20)]
+  , tcolor   = BrRed
+  , tcolor2  = Red
+  , tfeature = Trail : tfeature floorCorridorLit
+  }
+floorBlueLit = floorRedLit
+  { tname    = "transport route"
+  , tfreq    = [("trailLit", 100)]
+  , tcolor   = BrBlue
+  , tcolor2  = Blue
+  }
+floorGreenLit = floorRedLit
+  { tname    = "greenery trail"
+  , tfreq    = [("trailLit", 100)]
+  , tcolor   = BrGreen
+  , tcolor2  = Green
+  }
+
+
+makeDark :: TileKind -> TileKind
+makeDark k = let textLit :: Text -> Text
+                 textLit t = maybe t (<> "Dark") $ T.stripSuffix "Lit" t
+                 litFreq = map (first textLit) $ tfreq k
+             in k { tfreq    = litFreq
+                  , tfeature = Dark : tfeature k
+                  }
+
+makeDarkColor :: TileKind -> TileKind
+makeDarkColor k = (makeDark k) { tcolor  = BrYellow
+                               , tcolor2 = BrBlack
+                               }
diff --git a/GameDefinition/Main.hs b/GameDefinition/Main.hs
new file mode 100644
--- /dev/null
+++ b/GameDefinition/Main.hs
@@ -0,0 +1,55 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-- Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+-- This file is a part of the computer game Allure of the Stars
+-- and is released under the terms of the GNU Affero General Public License.
+-- For license and copyright information, see the file LICENSE.
+--
+-- | The main source code file of Allure of the Stars. Here the knot of engine
+-- code pieces and the Allure-specific content defintions is tied,
+-- resulting in an executable game.
+module Main ( main ) where
+
+import qualified Content.ActorKind
+import qualified Content.CaveKind
+import qualified Content.FactionKind
+import qualified Content.ItemKind
+import qualified Content.ModeKind
+import qualified Content.PlaceKind
+import qualified Content.RuleKind
+import qualified Content.TileKind
+import Game.LambdaHack.Client
+import Game.LambdaHack.Client.Action.ActionType
+import Game.LambdaHack.Common.Action (MonadAtomic (..))
+import Game.LambdaHack.Common.AtomicCmd
+import Game.LambdaHack.Common.AtomicSem
+import qualified Game.LambdaHack.Common.Kind as Kind
+import Game.LambdaHack.Server
+import Game.LambdaHack.Server.Action.ActionType
+import Game.LambdaHack.Server.AtomicSemSer
+
+-- | The game-state semantics of atomic game commands
+-- as computed on the server.
+instance MonadAtomic ActionSer where
+  execAtomic = atomicSendSem
+
+-- | The game-state semantics of atomic game commands
+-- as computed on clients. Special effects (@SfxAtomic@) don't modify state.
+instance MonadAtomic (ActionCli c d) where
+  execAtomic (CmdAtomic cmd) = cmdAtomicSem cmd
+  execAtomic (SfxAtomic _) = return ()
+
+-- | Tie the LambdaHack engine clients and server code
+-- with the Allure-specific content defintions and run the game.
+main :: IO ()
+main =
+  let copsSlow = Kind.COps
+        { coactor   = Kind.createOps Content.ActorKind.cdefs
+        , cocave    = Kind.createOps Content.CaveKind.cdefs
+        , cofaction = Kind.createOps Content.FactionKind.cdefs
+        , coitem    = Kind.createOps Content.ItemKind.cdefs
+        , comode    = Kind.createOps Content.ModeKind.cdefs
+        , coplace   = Kind.createOps Content.PlaceKind.cdefs
+        , corule    = Kind.createOps Content.RuleKind.cdefs
+        , cotile    = Kind.createOps Content.TileKind.cdefs
+        }
+  in mainSer copsSlow executorSer $ exeFrontend executorCli executorCli
diff --git a/GameDefinition/MainMenu.ascii b/GameDefinition/MainMenu.ascii
new file mode 100644
--- /dev/null
+++ b/GameDefinition/MainMenu.ascii
@@ -0,0 +1,26 @@
+----------------------------------------------------------------------------------
+|                                                                                |
+|                      >> Allure of the Stars <<                                 |
+|                                                                                |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
+|                                                                                |
+|                                                                                |
+|                        Version X.X.X (frontend: gtk, engine: LambdaHack X.X.X) |
+----------------------------------------------------------------------------------
diff --git a/GameDefinition/PLAYING.md b/GameDefinition/PLAYING.md
new file mode 100644
--- /dev/null
+++ b/GameDefinition/PLAYING.md
@@ -0,0 +1,207 @@
+Playing Allure of the Stars
+===========================
+
+Playing Allure of the Stars involves walking around an abandoned
+Solar System space-ship, alone or in a party of trusted crew-members,
+setting up ambushes, hiding in shadow, covering tracks,
+breaking through to deeper spaceship decks, bumping into
+hostile intruders, doors and walls, gathering technical resources
+and making creative use of them. The bloodthirsty alien monsters
+and their horrible minions do the same, intelligence allowing,
+while tirelessly chasing the stranded heroes by smell and sight.
+
+Once the few basic command keys and on-screen symbols are learned,
+mastery and enjoyment of the game is the matter of tactical skill
+and literary imagination. To be honest, a lot of imagination is required
+at this stage, but the game is already playable and winnable.
+The game also features experimental multiplayer cooperative and competitive
+modes, but they are troublesome to play with the shared-screen
+and shared-keyboard interface available at this time.
+Contributions welcome.
+
+
+Terrain
+-------
+
+The heroes are marked on the map with symbols `@` and `1` through `9`.
+Their goal is to explore an old, gigantic, once luxurious space liner,
+battle the horrors within, gather as much gold and precious gems
+as possible, and escape to tell the tale. The spaceship, in the campaign
+game mode, consists of many levels covered with varying terrain
+of the following basic kinds.
+
+               terrain type                       on-screen symbol
+               floor                              .
+               wall                               #
+               rock or tree                       O
+               cache                              &
+               stairs up                          <
+               stairs down                        >
+               open door                          '
+               closed door                        +
+
+The game world is persistent, i.e., every time the player visits a level
+during a single game, the level layout is the same.
+
+
+Keys
+----
+
+You move throughout the level using the numerical keypad or
+the vi text editor keys (also known as "Rogue-like keys").
+
+                7 8 9          y k u
+                 \|/            \|/
+                4-5-6          h-.-l
+                 /|\            /|\
+                1 2 3          b j n
+
+`SHIFT` (or `CTRL`) and a movement key make the current party leader
+(and currently selected party members, if any) run in the indicated
+direction, until anything of interest is spotted.
+The `5` and `.` keys consume a turn and make you brace for combat,
+which confers a chance to block blows for the remainder of the turn.
+In targeting mode the same keys move the targeting cursor.
+
+Melee, searching for secret doors and opening closed doors
+can be done by bumping into a monster, a wall and a door, respectively.
+Few commands other than movement are necessary for casual play.
+Some are provided only as building blocks for more complex convenience
+commands, e.g., the autoexplore command (key `X`) could be defined
+by the player as a macro using `BACKSPACE`, `CTRL-?`, `CTRL-;` and `P`.
+
+Below are the remaining keys for movement and terrain alteration.
+
+                keys           command
+                <              ascend a level
+                CTRL-<         ascend 10 levels
+                >              descend a level
+                CTRL->         descend 10 levels
+                CTRL-;         make one step towards the target
+                ;              go to target for 100 steps
+                x              explore the closest unknown spot
+                X              autoexplore 100 times
+                R              rest (wait 100 times)
+                c              close door
+
+Inventory and items-related keys are as follows. The `a` and `f` commands
+are generalized versions the other item manipulation commands, offering
+a wider default item choice.
+
+
+                keys           command
+                I              display inventory
+                g and ,        get an object
+                d              drop an object
+                q              quaff drink
+                r              read tablet
+                a              apply consumable
+                t              throw projectile
+                z              zap mechanism
+                f              fling missile
+
+To make a ranged attack, as in the last few commands above,
+you need to set your target first (however, initial target is set
+automatically as soon as a monster comes into view). Once in targeting mode,
+you can move the targeting cursor with arrow keys and switch focus
+among enemies with `*` (or among friends and enemies, depending
+on targeting mode set by `/`). The details of the shared cursor position
+and of the personal target are described at the bottom of the screen.
+All targeting keys are listed below.
+
+                keys           command
+                *              target enemy
+                /              cycle targeting mode
+                +              swerve targeting line
+                -              unswerve targeting line
+                BACKSPACE      clear target/cursor
+                CTRL-?         target the closest unknown spot
+                CTRL-I         target the closest item
+                CTRL-{         target the closest stairs up
+                CTRL-}         target the closest stairs down
+
+Assorted remaining keys and commands follow.
+
+                keys           command
+                ?              display help
+                D              display player diary
+                T              mark suspect terrain
+                V              mark visible area
+                S              mark smell
+                TAB            cycle among party members on the level
+                SHIFT-TAB      cycle among party members in the dungeon
+                =              select (or deselect) a party member
+                _              deselect (or select) all on the level
+                p              play back last keys
+                P              play back last keys 100 times
+                CTRL-p         play back last keys 1000 times
+                '              start recording a macro
+                SPACE          clear messages
+                ESC            cancel action
+                RET            accept choice
+                0--9           pick a new hero leader anywhere in the dungeon
+
+Commands for saving and exiting the current game, starting a new game, etc.,
+are listed in the Main Menu, brought up by the `ESC` key.
+All but the campaign and skirmish game modes are experimental
+and feature multiple human or computer players (allied or not).
+Game difficulty setting affects hitpoints at birth for any actors
+of any UI-using faction.
+
+                keys           command
+                CTRL-x         save and exit
+                CTRL-r         new campaign game
+                CTRL-k         new skirmish game
+                CTRL-v         new PvP game
+                CTRL-o         new Coop game
+                CTRL-e         new defense game
+                CTRL-d         cycle next game difficulty
+
+There are also some debug, testing and cheat options and game modes
+that can be specified on the command line when starting the game server.
+Use at your own peril! :) Of these, you may find the screensaver modes
+the least spoilery and the most fun, e.g.:
+
+    Allure --newGame --noMore --maxFps 45 --savePrefix test --gameMode testCampaign --difficulty 1
+
+
+Monsters
+--------
+
+Heroes are not alone in the spaceship. Monsters roam the dark halls
+and crawl from damp air-ducts day and night. While heroes pay attention
+to all other party members and take care to move one at a time,
+monsters don't care about each other and all move at once,
+sometimes brutally colliding by accident.
+
+When the hero bumps into a monster or a monster attacks the hero,
+melee combat occurs. The best weapon carried by each opponent
+is taken into account for calculating bonus damage. The total damage
+the current hero can potentially inflict is displayed at the bottom
+of the screen. The total damage potential of a monster may change
+as it finds and picks up new weapons. Heroes and monsters running into
+one another (with the `SHIFT` key) do not inflict damage, but change places.
+This gives the opponent a free blow, but can improve the tactical situation
+or aid escape.
+
+Throwing weapons at targets wounds them, consuming the weapon in the process.
+You may throw any object in your possession (press `?` to choose
+an object and press it again for a non-standard choice) or on the floor
+(press `-`). Only objects of a few kinds inflict any damage.
+Whenever the monster's or hero's hit points reach zero, the combatant dies.
+When the last hero dies, the game ends.
+
+
+On Winning and Dying
+--------------------
+
+You win the game if you escape the spaceship alive (or eliminate
+all opposition, in some game modes). Your score is
+the sum of all gold you've plundered plus 100 gold grains for each gem.
+Only the loot in possession of the party members on the current level
+counts (the rest of the party is considered MIA).
+
+If all heroes die, your score is halved and only the treasure carried
+by the last standing hero counts. You are free to start again
+from a different entrance to the spaceship, but all your previous wealth
+is gone and fresh, undaunted enemies bar your way.
diff --git a/GameDefinition/config.ui.default b/GameDefinition/config.ui.default
new file mode 100644
--- /dev/null
+++ b/GameDefinition/config.ui.default
@@ -0,0 +1,31 @@
+; ; Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
+; ; This file is a part of the computer game Allure of the Stars
+; ; and is released under the terms of the GNU Affero General Public License.
+; ; For license and copyright information, see the file LICENSE.
+; ;
+; ; This is a commented out copy of the default UI settings config file
+; ; that is embedded in the binary.
+; ; A user config file can overrides these options. The game looks for it at
+; ; ~/.Allure/config.ui.ini (or a similar path, depending on the OS).
+; ; Warning: options are case-sensitive and only ';' for comments is permitted.
+
+; [extra_commands]
+; ; Handy shorthands with Vi keys:
+; Macro_1 = ("comma", (CmdItem, Macro "" ["g"]))
+; Macro_2 = ("period", (CmdMove, Macro "" ["KP_Begin"]))
+
+; [hero_names]
+; HeroName_0 = Haskell Alvin
+; HeroName_1 = Alonzo Barkley
+; HeroName_2 = Ines Galenti
+; HeroName_3 = Ernst Abraham
+; HeroName_4 = Samuel Saunders
+; HeroName_5 = Roger Robin
+
+; [ui]
+; font = "Terminus,Monospace normal normal normal normal 12"
+; historyMax = 5000
+; maxFps = 15
+; noAnim = False
+; runStopMsgs = False
+[dummy]
diff --git a/GameDefinition/scores b/GameDefinition/scores
new file mode 100644
Binary files /dev/null and b/GameDefinition/scores differ
diff --git a/MainMenu.ascii b/MainMenu.ascii
deleted file mode 100644
--- a/MainMenu.ascii
+++ /dev/null
@@ -1,26 +0,0 @@
-----------------------------------------------------------------------------------
-|                                                                                |
-|                      >> Allure of the Stars <<                                 |
-|                                                                                |
-|                                                                                |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                      {{{{{{{{{{{{{{{{{{{{{{{{{                                 |
-|                                                                                |
-|                                                                                |
-|                                                                                |
-|                        Version X.X.X (frontend: gtk, engine: LambdaHack X.X.X) |
-----------------------------------------------------------------------------------
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
+# Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
 # This file is a part of the computer game Allure of the Stars
 # and is released under the terms of the GNU Affero General Public License.
 # For license and copyright information, see the file LICENSE.
@@ -18,134 +18,228 @@
 	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer
 
 xcpeekCampaign:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekCampaign --gameMode peekCampaign
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign
 
 xcpeekSkirmish:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekSkirmish --gameMode peekSkirmish
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish
 
 xcfrontendCampaign:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 45 --savePrefix test --gameMode screensaver
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testCampaign --difficulty 1
 
+xcfrontendSkirmish:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testSkirmish
+
+xcfrontendBattle:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testBattle --difficulty 1
+
+xcfrontendPvP:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testPvP --fovMode Shadow
+
 xcfrontendCoop:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --fovMode Permissive --savePrefix test --gameMode testCoop
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testCoop --difficulty 1 --fovMode Permissive
 
 xcfrontendDefense:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 45 --savePrefix test --gameMode testDefense
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testDefense --difficulty 9
 
+xcbenchCampaign:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendNo --benchmark --stopAfter 60 --gameMode testCampaign --difficulty 1 --setDungeonRng 42 --setMainRng 42
 
-xctest-travis: xctest-short xctest-medium
+xcbenchBattle:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendNo --benchmark --stopAfter 60 --gameMode testBattle --difficulty 1 --setDungeonRng 42 --setMainRng 42
 
+xcbenchFrontendCampaign:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --benchmark --stopAfter 60 --gameMode testCampaign --difficulty 1 --setDungeonRng 42 --setMainRng 42
+
+xcbenchFrontendBattle:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --benchmark --stopAfter 60 --gameMode testBattle --difficulty 1 --setDungeonRng 42 --setMainRng 42
+
+xcbenchNo: xcbenchCampaign xcbenchBattle
+
+xcbench: xcbenchCampaign xcbenchFrontendCampaign xcbenchBattle xcbenchFrontendBattle
+
+xctest-travis: xctest-short xctest-medium xcbenchNo
+
+xctest-travis-long: xctest-short xctest-long xcbenchNo
+
 xctest: xctest-short xctest-medium xctest-long
 
 xctest-short: xctest-short-new xctest-short-load
 
-xctest-medium: xctestCampaign-medium xctestCoop-medium xctestDefense-medium
+xctest-medium: xctestCampaign-medium xctestSkirmish-medium xctestBattle-medium xctestPvP-medium xctestCoop-medium xctestDefense-medium
 
 xctest-long: xctestCampaign-long xctestCoop-long xctestDefense-long
 
 xctestCampaign-long:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --gameMode screensaver --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testCampaign --difficulty 1 > /tmp/stdtest.log
 
 xctestCampaign-medium:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --gameMode screensaver --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testCampaign --difficulty 1 > /tmp/stdtest.log
 
+xctestSkirmish-long:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testSkirmish > /tmp/stdtest.log
+
+xctestSkirmish-medium:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testSkirmish > /tmp/stdtest.log
+
+xctestBattle-long:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testBattle --difficulty 1 > /tmp/stdtest.log
+
+xctestBattle-medium:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testBattle --difficulty 1 > /tmp/stdtest.log
+
+xctestPvP-long:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testPvP > /tmp/stdtest.log
+
+xctestPvP-medium:
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testPvP > /tmp/stdtest.log
+
 xctestCoop-long:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --fovMode Permissive --savePrefix test --gameMode testCoop --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testCoop --difficulty 1 > /tmp/stdtest.log
 
 xctestCoop-medium:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --fovMode Shadow --savePrefix test --gameMode testCoop --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testCoop --difficulty 1 > /tmp/stdtest.log
 
 xctestDefense-long:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noAnim --maxFps 100000 --savePrefix test --gameMode testDefense --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testDefense --difficulty 9 > /tmp/stdtest.log
 
 xctestDefense-medium:
-	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --gameMode testDefense --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testDefense --difficulty 9 > /tmp/stdtest.log
 
 xctest-short-new:
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix campaign --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix skirmish --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix PvP --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix Coop --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix defense --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix peekCampaign --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix peekSkirmish --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix campaign --dumpInitRngs --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix skirmish --dumpInitRngs --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix battle --dumpInitRngs --gameMode battle --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix PvP --dumpInitRngs --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix Coop --dumpInitRngs --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix defense --dumpInitRngs --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --newGame --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
 
 xctest-short-load:
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix campaign --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix skirmish --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix PvP --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix Coop --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix defense --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekCampaign --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekSkirmish --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix campaign --dumpInitRngs --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix skirmish --dumpInitRngs --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix battle --dumpInitRngs --gameMode battle --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix PvP --dumpInitRngs --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix Coop --dumpInitRngs --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix defense --dumpInitRngs --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
 
 
 play:
 	dist/build/Allure/Allure --dbgMsgSer
 
 peekCampaign:
-	dist/build/Allure/Allure --dbgMsgSer --savePrefix peekCampaign --gameMode peekCampaign
+	dist/build/Allure/Allure --dbgMsgSer --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign
 
 peekSkirmish:
-	dist/build/Allure/Allure --dbgMsgSer --savePrefix peekSkirmish --gameMode peekSkirmish
+	dist/build/Allure/Allure --dbgMsgSer --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish
 
 frontendCampaign:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 45 --savePrefix test --gameMode screensaver
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testCampaign --difficulty 1
 
+frontendSkirmish:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testSkirmish
+
+frontendBattle:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testBattle --difficulty 1
+
+frontendPvP:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testPvP --fovMode Shadow
+
 frontendCoop:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --fovMode Permissive --savePrefix test --gameMode testCoop
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testCoop --difficulty 1 --fovMode Permissive
 
 frontendDefense:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 45 --savePrefix test --gameMode testDefense
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 180 --savePrefix test --dumpInitRngs --gameMode testDefense --difficulty 9
 
+benchCampaign:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendNo --benchmark --stopAfter 60 --gameMode testCampaign --difficulty 1 --setDungeonRng 42 --setMainRng 42
 
-test-travis: test-short test-medium
+benchBattle:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendNo --benchmark --stopAfter 60 --gameMode testBattle --difficulty 1 --setDungeonRng 42 --setMainRng 42
 
+benchFrontendCampaign:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --benchmark --stopAfter 60 --gameMode testCampaign --difficulty 1 --setDungeonRng 42 --setMainRng 42
+
+benchFrontendBattle:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --benchmark --stopAfter 60 --gameMode testBattle --difficulty 1 --setDungeonRng 42 --setMainRng 42
+
+benchNo: benchCampaign benchBattle
+
+bench: benchCampaign benchFrontendCampaign benchBattle benchFrontendBattle
+
+
+test-travis: test-short test-medium benchNo
+
+test-travis-long: test-short test-long benchNo
+
 test: test-short test-medium test-long
 
 test-short: test-short-new test-short-load
 
-test-medium: testCampaign-medium testCoop-medium testDefense-medium
+test-medium: testCampaign-medium testSkirmish-medium testBattle-medium testPvP-medium testCoop-medium testDefense-medium
 
 test-long: testCampaign-long testCoop-long testDefense-long
 
 testCampaign-long:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --gameMode screensaver --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testCampaign --difficulty 1 > /tmp/stdtest.log
 
 testCampaign-medium:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --gameMode screensaver --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testCampaign --difficulty 1 > /tmp/stdtest.log
 
+testSkirmish-long:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testSkirmish > /tmp/stdtest.log
+
+testSkirmish-medium:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testSkirmish > /tmp/stdtest.log
+
+testBattle-long:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testBattle --difficulty 1 > /tmp/stdtest.log
+
+testBattle-medium:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testBattle --difficulty 1 > /tmp/stdtest.log
+
+testPvP-long:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testPvP > /tmp/stdtest.log
+
+testPvP-medium:
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testPvP > /tmp/stdtest.log
+
 testCoop-long:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --fovMode Permissive --savePrefix test --gameMode testCoop --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testCoop --difficulty 1 > /tmp/stdtest.log
 
 testCoop-medium:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --fovMode Shadow --savePrefix test --gameMode testCoop --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testCoop --difficulty 1 > /tmp/stdtest.log
 
 testDefense-long:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noAnim --maxFps 100000 --savePrefix test --gameMode testDefense --frontendStd --stopAfter 1000 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 580 --dumpInitRngs --gameMode testDefense --difficulty 9 > /tmp/stdtest.log
 
 testDefense-medium:
-	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --maxFps 100000 --savePrefix test --gameMode testDefense --frontendStd --dumpConfig --stopAfter 200 > /tmp/stdtest.log
+	dist/build/Allure/Allure --dbgMsgSer --newGame --noMore --noDelay --noAnim --maxFps 100000 --savePrefix test --frontendStd --benchmark --stopAfter 280 --dumpInitRngs --gameMode testDefense --difficulty 9 > /tmp/stdtest.log
 
 test-short-new:
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix campaign --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix skirmish --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix PvP --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix Coop --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix defense --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix peekCampaign --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix peekSkirmish --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix campaign --dumpInitRngs --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix skirmish --dumpInitRngs --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix battle --dumpInitRngs --gameMode battle --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix PvP --dumpInitRngs --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix Coop --dumpInitRngs --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix defense --dumpInitRngs --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --newGame --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
 
 test-short-load:
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix skirmish --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix PvP --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix Coop --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix defense --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix peekCampaign --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
-	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix peekSkirmish --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --dumpInitRngs --gameMode campaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix skirmish --dumpInitRngs --gameMode skirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix battle --dumpInitRngs --gameMode battle --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix PvP --dumpInitRngs --gameMode PvP --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix Coop --dumpInitRngs --gameMode Coop --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix defense --dumpInitRngs --gameMode defense --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix peekCampaign --dumpInitRngs --gameMode peekCampaign --frontendStd --stopAfter 0 > /tmp/stdtest.log
+	while true; do echo ' '; echo '.'; sleep 1; done | dist/build/Allure/Allure --dbgMsgSer --savePrefix peekSkirmish --dumpInitRngs --gameMode peekSkirmish --frontendStd --stopAfter 0 > /tmp/stdtest.log
 
 
+
 # The rest of the makefile is unmaintained at the moment.
 
 default : dist/setup-config
@@ -158,4 +252,4 @@
 	runghc Setup clean
 
 ghci :
-	ghci -XCPP -idist/build/autogen:src
+	ghci -XCPP -idist/build/autogen:GameDefinition
diff --git a/PLAYING.md b/PLAYING.md
deleted file mode 100644
--- a/PLAYING.md
+++ /dev/null
@@ -1,174 +0,0 @@
-Playing Allure of the Stars
-===========================
-
-Playing Allure of the Stars involves walking around an abandoned
-Solar System space-ship, alone or in a party of trusted crew-members,
-setting up ambushes, hiding in shadow, covering tracks,
-breaking through to deeper spaceship decks, bumping into
-hostile intruders, doors and walls, gathering technical resources
-and making creative use of them. The bloodthirsty alien monsters
-and their horrible minions do the same, intelligence allowing,
-while tirelessly chasing the stranded heroes by smell and sight.
-
-Once the few basic command keys and on-screen symbols are learned,
-mastery and enjoyment of the game is the matter of tactical skill
-and literary imagination. To be honest, a lot of imagination is required
-at this stage, but the game is already playable and winnable.
-The game also features multiplayer cooperative and competitive modes,
-though only a shared-screen interface is provided at this time.
-Contributions welcome.
-
-
-Terrain
--------
-
-The heroes are marked on the map with symbols '@' and '1' through '9'.
-Their goal is to explore an old, gigantic, once luxurious space liner,
-battle the horrors within, gather as much gold and precious gems
-as possible, and escape to tell the tale. The spaceship, in the campaign
-game mode, consists of many levels covered with varying terrain
-of the following basic kinds:
-
-               terrain type                       on-screen symbol
-               floor                              .
-               wall                               #
-               rock or tree                       O
-               cache                              &
-               stairs up                          <
-               stairs down                        >
-               open door                          '
-               closed door                        +
-
-The game world is persistent, i.e., every time the player visits a level
-during a single game, the level layout is the same.
-
-
-Keys
-----
-
-You move throughout the level using the numerical keypad or
-the vi text editor keys (also known as "Rogue-like keys").
-
-               7 8 9     y k u
-                \|/       \|/
-               4-5-6     h-.-l
-                /|\       /|\
-               1 2 3     b j n
-
-SHIFT (or CTRL) and a movement key make the selected hero run in the indicated
-direction, until anything of interest is spotted. The '5' and '.' keys take
-a turn to brace for combat, which gives a chance to block blows
-for the remainder of the turn. Melee, searching for secret doors
-and opening closed doors can be done by bumping into a monster,
-a wall and a door, respectively.
-
-Below are the default keys for major commands. The last four commands
-are specialized versions of 'a' and 'p', offering narrower default item choice.
-The commands that take player time are marked with a star.
-
-               key       command
-               <         ascend a level*
-               >         descend a level*
-               ?         display help
-               I         display inventory
-               a         apply a consumable*
-               c         close a door*
-               d         drop an object*
-               g         get an object*
-               o         open a door*
-               p         project a projectile*
-               q         quaff a drink*
-               r         read a tablet*
-               t         throw a missile*
-               z         zap a mechanism*
-
-To make a ranged attack, you need to set your target first,
-using targeting mode ('*' and '/' keys). The target, for the few
-commands that require any, is indicated by the targeting cursor.
-To avoid confusion, commands that take time are blocked when targeting
-at a remote level (when the cursor is displayed on a different level
-than the selected hero). The targeting commands and all the less used
-commands are listed below. None of them takes hero time.
-
-               key       command
-               ESC       cancel action or bring up the Main Menu
-               RET       accept choice
-               TAB       cycle among heroes on the level
-               SHIFT-TAB cycle among heroes in the dungeon
-               *         target monster
-               +         swerve targeting line
-               -         unswerve targeting line
-               /         target position
-               P         display previous messages
-               S         mark smell
-               T         mark suspect terrain
-               V         mark visible area
-               [         target next shallower level
-               ]         target next deeper level
-               {         target 10 levels shallower
-               }         target 10 levels deeper
-               0--9      select a hero anywhere in the dungeon
-
-Commands for saving and exiting the current game, starting a new game, etc.,
-are listed in the Main Menu, brough up by the ESC key.
-Some of the game modes are multiplayer or feature multiple computer
-players (allied or not). The setup of the modes can be modified
-via a configuration file.
-
-               key       command
-               CTRL-x    save and exit
-               CTRL-r    new campaign game
-               CTRL-k    new skirmish game
-               CTRL-p    new PvP game
-               CTRL-o    new Coop game
-               CTRL-e    new defense game
-
-There are also some debug, testing and cheat options and game modes
-that can be specified on the command line when starting the game server.
-Use at your own peril! :) Of these, you may find the screensaver modes
-the least spoilery and the most fun, e.g.:
-
-    Allure --newGame --noMore --maxFps 45 --savePrefix screensaver --gameMode screensaver
-
-
-Monsters
---------
-
-Heroes are not alone in the spaceship. Monsters roam the dark halls
-and crawl from damp air-ducts day and night. While heroes pay attention
-to all other party members and take care to move one at a time,
-monsters don't care about each other and all move at once,
-sometimes brutally colliding by accident.
-
-When the hero bumps into a monster or a monster attacks the hero,
-melee combat occurs. The best weapon carried by each opponent
-is taken into account for calculating bonus damage. The total damage
-the current hero can potentially inflict is displayed at the bottom
-of the screen. The total damage potential of a monster may change
-as it finds and picks up new weapons. Heroes and monsters running into
-one another (with the Shift key) do not inflict damage, but change places.
-This gives the opponent a free blow, but can improve the tactical situation
-or aid escape.
-
-Throwing weapons at targets wounds them, consuming the weapon in the process.
-Target a monster with the '*' key from the top keyboard row or from keypad.
-You may throw any object in your possession (press '?' to choose
-an object and press it again for a non-standard choice) or on the floor
-(press '-'). Only objects of a few kinds inflict any damage.
-Whenever the monster's or hero's hit points reach zero, the combatant dies.
-When the last hero dies, the game ends.
-
-
-On Winning and Dying
---------------------
-
-You win the game if you escape the spaceship alive (or eliminate
-all opposition, in some game modes). Your score is
-the sum of all gold you've plundered plus 100 gold grains for each gem.
-Only the loot in possession of the party members on the current level
-counts (the rest of the party is considered MIA).
-
-If all heroes die, your score is halved and only the treasure carried
-by the last standing hero counts. You are free to start again
-from a different entrance to the spaceship, but all your previous wealth
-is gone and fresh, undaunted enemies bar your way.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-Allure of the Stars [![Build Status](https://secure.travis-ci.org/Mikolaj/Allure.png)](http://travis-ci.org/Mikolaj/Allure)
+Allure of the Stars [![Build Status](https://secure.travis-ci.org/Mikolaj/Allure.png)](http://travis-ci.org/Mikolaj/Allure)[![Build Status](https://drone.io/github.com/Mikolaj/Allure/status.png)](https://drone.io/github.com/Mikolaj/Allure/latest)
 ===================
 
 This is an alpha release of Allure of the Stars,
@@ -12,47 +12,48 @@
 Compilation and installation
 ----------------------------
 
-The game is best compiled and installed via Cabal, which also takes care
-of all dependencies. The latest official version of the game can be downloaded
-automatically by Cabal from [Hackage] [4] as follows
+The game is best compiled and installed via Cabal (already a part
+of your OS distribution, or available within [The Haskell Platform] [7]),
+which also takes care of all the dependencies. The latest official
+version of the game can be downloaded automatically by Cabal
+from [Hackage] [4] as follows
 
     cabal install Allure
 
 For a newer version, install a matching LambdaHack library snapshot
 from a development branch, download the game source from [github] [3]
-and run `cabal install` from the main directory.
+and run `cabal install` from the main directory (for sample commands
+see file `.travis.yml`).
 
 
 Compatibility notes
 -------------------
 
-The current code was tested with GHC 7.6.3, but should also work with
-other GHC versions (see file .travis.yml.7.4.2 for GHC 7.4.2 commands).
+The current code was tested with GHC 7.6 and 7.8, but should also work with
+other GHC versions (see file `.travis.yml.7.4.2` for GHC 7.4 commands).
 
-If you are using the curses or vty frontends,
-numerical keypad may not work correctly depending on the versions
-of curses, terminfo and terminal emulators.
-Selecting heroes via number keys or SHIFT-keypad keys is disabled
-with curses, because CTRL-keypad for running does not work there,
-so the numbers produced by the keypad have to be used. With vty on xterm,
-CTRL-direction keys seem to work OK, but on rxvt they do not.
-Vi keys (ykuhlbjn) should work everywhere regardless. Gtk works fine, too.
+If you are using the terminal frontends, numerical keypad may not work
+correctly depending on versions of the libraries, terminfo and terminal
+emulators. The curses frontend is not fully supported due to the limitations
+of the curses library. With the vty frontend run in an xterm,
+CTRL-keypad keys for running seem to work OK, but on rxvt they do not.
+Vi keys (ykuhlbjn) should work everywhere regardless. GTK works fine, too.
 
 
 Testing and debugging
 ---------------------
 
-The Makefile contains many sample test commands. All that use the screensaver
+The `Makefile` contains many sample test commands. All that use the screensaver
 game modes (AI vs. AI) and the simplest stdout frontend are gathered
-in `make test`. Of these, travis runs the set contained in
-`make test-travis` on each push to the repo. Commands with prefix
+in `make test`. Of these, travis runs one of the sets prefixed
+`test-travis` on each push to the repo. Commands with prefix
 `frontend` run AI vs. AI games with the standard, user-friendly frontend.
 Commands with prefix `peek` set up a game mode where the player peeks
 into AI moves each time an AI actor dies or autosave kicks in.
 Run `Allure --help` to see a brief description of all debug options.
 Of these, `--sniffIn` and `--sniffOut` are very useful (though verbose
 and initially cryptic), for monitoring the traffic between clients
-and the server. Some options in config files may turn out useful too,
+and the server. Some options in the config file may turn out useful too,
 though they mostly overlap with commandline options (and will be totally
 merged at some point).
 
@@ -61,7 +62,7 @@
 -------------------
 
 For more information, visit the [wiki] [6]
-and see the files PLAYING.md, CREDITS and LICENSE.
+and see `GameDefinition/PLAYING.md`, `CREDITS` and `LICENSE`.
 
 Have fun!
 
@@ -69,7 +70,7 @@
 Copyright
 ---------
 
-Copyright (c) 2008--2011 Andres Loeh, 2010--2013 Mikolaj Konarski
+Copyright (c) 2008--2011 Andres Loeh, 2010--2014 Mikolaj Konarski
 
 Allure of the Stars is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
@@ -93,3 +94,4 @@
 [4]: http://hackage.haskell.org/package/Allure
 [5]: http://github.com/kosmikus/LambdaHack
 [6]: https://github.com/Mikolaj/Allure/wiki
+[7]: http://www.haskell.org/platform
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,41 +1,50 @@
-0.4.3
-
-	* the Allure of the Stars game depends on the LambdaHack engine library
-
-0.4.4
-
-	* missiles flying for three turns (by an old kosmikus' idea)
-
-	* visual feedback for targeting
-
-	* animations of combat and individual monster moves
-
-0.4.6
-
-	* the Main Menu
+v0.4.12
 
-	* improved and configurable mode of squad combat
+        * make walls lit by default to simplify exploration
+        * improve and simplify dungeon generation
+        * simplify running and permit multi-actor runs
+        * let items explode and generate shrapnel projectiles
+        * add game difficulty setting (initial HP scaling right now)
+        * allow recording, playing back and looping commands
+        * implement pathfinding via per-actor BFS over the whole level
+        * extend setting targets for actors in UI tremendously
+        * implement autoexplore, go-to-target, etc., as macros
+        * let AI use pathfinding, switch leaders, pick levels to swarm to
+        * force level/leader changes on spawners (even when played by humans)
+        * extend and redesign UI bottom status lines
 
-0.4.6.5
+v0.4.10
 
-	* this is a minor release, primarily intended to fix the broken compilation on Hackage
+        * screensaver game modes (AI vs AI)
+        * improved AI (can now climbs stairs, etc.)
+        * multiple, multi-floor staircases
+        * multiple savefiles
+        * configurable framerate and combat animations
 
-	* changes since 0.2.6 are mostly in the engine and are unrelated to gameplay: strictly typed config files split into UI and rules; a switch from Text to String throughout the codebase; use of the external library miniutter for English sentence generation
+v0.4.8
 
-0.4.8
+        * experimental multiplayer modes
+        * a lot of gameplay changes induced by the engine overhaul and in particular the client-server rewrite
 
-	* experimental multiplayer modes
+v0.4.6.5
 
-	* a lot of gameplay changes induced by the engine overhaul and in particular the client-server rewrite
+        * this is a minor release, primarily intended to fix the broken compilation on Hackage
+        * changes since 0.4.6 are mostly unrelated to gameplay:
+          - strictly typed config files split into UI and rules
+          - a switch from Text to String throughout the codebase
+          - use of the external library miniutter for English sentence generation
 
-0.4.10
+v0.4.6
 
-	* screensaver game modes (AI vs AI)
+        * the Main Menu
+        * improved and configurable mode of squad combat
 
-	* improved AI (can now climbs stairs, etc.)
+v0.4.4
 
-	* multiple, multi-floor staircases
+        * missiles flying for three turns (by an old kosmikus' idea)
+        * visual feedback for targeting
+        * animations of combat and individual monster moves
 
-	* multiple savefiles
+v0.4.3
 
-	* configurable framerate and combat animations
+        * the Allure of the Stars game depends on the LambdaHack engine library
diff --git a/config.rules.default b/config.rules.default
deleted file mode 100644
--- a/config.rules.default
+++ /dev/null
@@ -1,33 +0,0 @@
-; ; Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
-; ; This file is a part of the computer game Allure of the Stars
-; ; and is released under the terms of the GNU Affero General Public License.
-; ; For license and copyright information, see the file LICENSE.
-; ;
-; ; This is a commented out copy of the default game rules config file
-; ; that is embedded in the binary.
-; ; A user config file can overrides these options. The game looks for it at
-; ; ~/.Allure/config.rules.ini (or a similar path, depending on the OS).
-; ; Warning: options are case-sensitive and only ';' for comments is permitted.
-
-; [engine]
-; ;dungeonRandomGenerator: 42
-; firstDeathEnds: False
-; fovMode: Digital 12
-; ;fovMode: Permissive
-; ;fovMode: Shadow
-; ;startingRandomGenerator: 42
-; saveBkpClips: 500
-
-; [file]
-; ; Names (or prefixes) of various game files.
-; ; They reside in ~/.Allure or similar.
-; savePrefix: save
-; scoresFile: scores
-
-; [heroName]
-; HeroName_0: Haskell Alvin
-; HeroName_1: Alonzo Barkley
-; HeroName_2: Ines Galenti
-; HeroName_3: Ernst Abraham
-; HeroName_4: Samuel Saunders
-; HeroName_5: Roger Robin
diff --git a/config.ui.default b/config.ui.default
deleted file mode 100644
--- a/config.ui.default
+++ /dev/null
@@ -1,69 +0,0 @@
-; ; Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
-; ; This file is a part of the computer game Allure of the Stars
-; ; and is released under the terms of the GNU Affero General Public License.
-; ; For license and copyright information, see the file LICENSE.
-; ;
-; ; This is a commented out copy of the default UI settings config file
-; ; that is embedded in the binary.
-; ; A user config file can overrides these options. The game looks for it at
-; ; ~/.Allure/config.ui.ini (or a similar path, depending on the OS).
-; ; Warning: options are case-sensitive and only ';' for comments is permitted.
-
-; [commands]
-; ; All commands are defined here, except movement, hero selection and debug.
-; ;
-; KP_Begin: Wait
-; g: Pickup
-; d: Drop
-; p: Project [ApplyItem {verb = "project", object = "missile", symbol = ' '}, ApplyItem {verb = "throw", object = "projectile", symbol = '}'}, ApplyItem {verb = "throw", object = "projectile", symbol = '{'}, ApplyItem {verb = "zap", object = "mechanism", symbol = '-'}]
-; t: Project [ApplyItem {verb = "throw", object = "projectile", symbol = '}'}, ApplyItem {verb = "throw", object = "projectile", symbol = '{'}]
-; z: Project [ApplyItem {verb = "zap", object = "mechanism", symbol = '-'}]
-; a: Apply [ApplyItem {verb = "apply", object = "consumable", symbol = ' '}, ApplyItem {verb = "eat", object = "food", symbol = ','}, ApplyItem {verb = "activate", object = "emitter", symbol = '_'}, ApplyItem {verb = "use", object = "tool", symbol = '~'}, ApplyItem {verb = "quaff", object = "drink", symbol = '!'}, ApplyItem {verb = "read", object = "tablet", symbol = '?'}]
-; q: Apply [ApplyItem {verb = "quaff", object = "drink", symbol = '!'}]
-; r: Apply [ApplyItem {verb = "read", object = "tablet", symbol = '?'}]
-; c: AlterDir [AlterFeature {verb = "close", object = "door", feature = CloseTo "closed door"}]
-; less: TriggerTile [TriggerFeature {verb = "ascend", object = "level", feature = Cause (Ascend 1)}, TriggerFeature {verb = "exit", object = "spaceship", feature = Cause Escape}]
-; greater: TriggerTile [TriggerFeature {verb = "descend", object = "level", feature = Cause (Ascend (-1))}, TriggerFeature {verb = "exit", object = "spaceship", feature = Cause Escape}]
-; CTRL-r: GameRestart "campaign"
-; ; TODO: pick game modes via arrow keys, not special keys
-; CTRL-k: GameRestart "skirmish"
-; CTRL-p: GameRestart "PvP"
-; CTRL-o: GameRestart "Coop"
-; CTRL-e: GameRestart "defense"
-; CTRL-x: GameExit
-; CTRL-s: GameSave
-; Tab: MemberCycle
-; ISO_Left_Tab: MemberBack
-; I: Inventory
-; slash: TgtFloor
-; asterisk: TgtEnemy
-; bracketleft:  TgtAscend 1
-; bracketright: TgtAscend (-1)
-; braceleft:    TgtAscend 10
-; braceright:   TgtAscend (-10)
-; plus: EpsIncr True
-; minus: EpsIncr False
-; Escape: Cancel
-; Return: Accept
-; space: Clear
-; P: History
-; V: MarkVision
-; S: MarkSmell
-; T: MarkSuspect
-; question: Help
-
-; [file]
-; ; Names (or prefixes) of various game files.
-; ; They reside in ~/.Allure or similar.
-; savePrefix: save
-
-; [macros]
-; ; Handy with Vi keys:
-; comma: g
-; period: KP_Begin
-
-; [ui]
-; font: Terminus,Monospace normal normal normal normal 12
-; historyMax: 5000
-; maxFps: 15
-; noAnim: False
diff --git a/scores b/scores
deleted file mode 100644
Binary files a/scores and /dev/null differ
diff --git a/src/Content/ActorKind.hs b/src/Content/ActorKind.hs
deleted file mode 100644
--- a/src/Content/ActorKind.hs
+++ /dev/null
@@ -1,93 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Monsters and heroes for Allure of the Stars.
-module Content.ActorKind ( cdefs ) where
-
-import Game.LambdaHack.Common.Ability
-import Game.LambdaHack.Common.Color
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Common.Random
-import Game.LambdaHack.Common.Time
-import Game.LambdaHack.Content.ActorKind
-
-cdefs :: ContentDef ActorKind
-cdefs = ContentDef
-  { getSymbol = asymbol
-  , getName = aname
-  , getFreq = afreq
-  , validate = avalidate
-  , content =
-      [hero, projectile, eye, fastEye, nose]
-  }
-hero,        projectile, eye, fastEye, nose :: ActorKind
-
-hero = ActorKind
-  { asymbol = '@'
-  , aname   = "hero"
-  , afreq   = [("hero", 1)]
-  , acolor  = BrWhite  -- modified if many hero factions
-  , ahp     = rollDice 50 1
-  , aspeed  = toSpeed 2
-  , asight  = True
-  , asmell  = False
-  , aiq     = 15  -- higher that that leads to looping movement
-  , aregen  = 500
-  , acanDo  = [minBound..maxBound]
-  }
-
-projectile = ActorKind  -- includes homing missiles
-  { asymbol = '*'
-  , aname   = "projectile"
-  , afreq   = [("projectile", 1)]  -- Does not appear randomly in the dungeon.
-  , acolor  = BrWhite
-  , ahp     = rollDice 0 0
-  , aspeed  = toSpeed 0
-  , asight  = False
-  , asmell  = False
-  , aiq     = 0
-  , aregen  = maxBound
-  , acanDo  = [Track]
-  }
-
-eye = ActorKind
-  { asymbol = 'r'
-  , aname   = "deranged household robot"
-  , afreq   = [("robot", 60), ("horror", 60)]
-  , acolor  = BrYellow
-  , ahp     = rollDice 7 4
-  , aspeed  = toSpeed 2
-  , asight  = True
-  , asmell  = False
-  , aiq     = 16  -- leads to robotic, repetitious, looping movement
-  , aregen  = 100
-  , acanDo  = [minBound..maxBound]
-  }
-fastEye = ActorKind
-  { asymbol = 'm'
-  , aname   = "deformed monkey"
-  , afreq   = [("animal", 15), ("horror", 15)]
-  , acolor  = BrMagenta
-  , ahp     = rollDice 1 4
-  , aspeed  = toSpeed 4
-  , asight  = True
-  , asmell  = False
-  , aiq     = 12
-  , aregen  = 5  -- Regenerates fast (at max HP most of the time!).
-  , acanDo  = [minBound..maxBound]
-  }
-nose = ActorKind
-  { asymbol = 'h'
-  , aname   = "tentacled horror"
-  , afreq   = [("alien", 20), ("horror", 20)]
-  , acolor  = Green
-  , ahp     = rollDice 17 2
-  , aspeed  = toSpeed 1.8
-  , asight  = False
-  , asmell  = True
-  , aiq     = 0
-  , aregen  = 100
-  , acanDo  = [minBound..maxBound]
-  }
diff --git a/src/Content/CaveKind.hs b/src/Content/CaveKind.hs
deleted file mode 100644
--- a/src/Content/CaveKind.hs
+++ /dev/null
@@ -1,121 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Cave layouts for Allure of the Stars.
-module Content.CaveKind ( cdefs ) where
-
-import Data.Ratio
-
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Common.Misc
-import Game.LambdaHack.Common.Random as Random
-import Game.LambdaHack.Content.CaveKind
-
-cdefs :: ContentDef CaveKind
-cdefs = ContentDef
-  { getSymbol = csymbol
-  , getName = cname
-  , getFreq = cfreq
-  , validate = cvalidate
-  , content =
-      [rogue, arena, empty, noise, combat]
-  }
-rogue,        arena, empty, noise, combat :: CaveKind
-
-rogue = CaveKind
-  { csymbol       = '$'
-  , cname         = "Storage area"
-  , cfreq         = [("dng", 100), ("caveRogue", 1)]
-  , cxsize        = fst normalLevelBound + 1
-  , cysize        = snd normalLevelBound + 1
-  , cgrid         = rollDiceXY [(3, 2)] [(1, 2), (2, 1)]
-  , cminPlaceSize = rollDiceXY [(2, 2), (2, 1)] [(4, 1)]
-  , cmaxPlaceSize = rollDiceXY [(fst normalLevelBound, 1)]
-                               [(snd normalLevelBound, 1)]
-  , cdarkChance   = rollDeep (1, 54) (0, 0)
-  , cnightChance  = intToDeep 100
-  , cauxConnects  = 1%3
-  , cmaxVoid      = 1%6
-  , cminStairDist = 30
-  , cdoorChance   = 1%2
-  , copenChance   = 1%10
-  , chidden       = 8
-  , citemNum      = rollDice 7 2
-  , citemFreq     = [(70, "useful"), (30, "treasure")]
-  , cdefTile        = "fillerWall"
-  , cdarkCorTile    = "floorCorridorDark"
-  , clitCorTile     = "floorCorridorLit"
-  , cfillerTile     = "fillerWall"
-  , cdarkLegendTile = "darkLegend"
-  , clitLegendTile  = "litLegend"
-  }
-arena = rogue
-  { csymbol       = 'A'
-  , cname         = "Recreational deck"
-  , cfreq         = [("dng", 100), ("caveArena", 1)]
-  , cgrid         = rollDiceXY [(2, 2)] [(2, 2)]
-  , cminPlaceSize = rollDiceXY [(2, 2), (3, 1)] [(4, 1)]
-  , cdarkChance   = rollDeep (1, 80) (1, 60)
-  , cnightChance  = intToDeep 0
-  , cmaxVoid      = 1%3
-  , chidden       = 1000
-  , citemNum      = rollDice 5 2  -- few rooms
-  , cdefTile      = "arenaSet"
-  , cdarkCorTile  = "pathDark"
-  , clitCorTile   = "pathLit"
-  }
-empty = rogue
-  { csymbol       = '.'
-  , cname         = "Construction site"
-  , cfreq         = [("dng", 100), ("caveEmpty", 1)]
-  , cgrid         = rollDiceXY [(1, 2), (1, 1)] [(1, 1)]
-  , cminPlaceSize = rollDiceXY [(10, 1)] [(10, 1)]
-  , cmaxPlaceSize = rollDiceXY [(fst normalLevelBound * 3 `div` 5, 1)]
-                               [(snd normalLevelBound * 3 `div` 5, 1)]
-  , cdarkChance   = rollDeep (1, 80) (1, 80)
-  , cnightChance  = intToDeep 0
-  , cauxConnects  = 1
-  , cmaxVoid      = 1%2
-  , cminStairDist = 50
-  , chidden       = 1000
-  , citemNum      = rollDice 8 2  -- whole floor strewn with treasure
-  , cdefTile      = "emptySet"
-  , cdarkCorTile  = "pathDark"
-  , clitCorTile   = "floorArenaLit"
-  }
-noise = rogue
-  { csymbol       = '!'
-  , cname         = "Machine rooms"
-  , cfreq         = [("dng", 100), ("caveNoise", 1)]
-  , cgrid         = rollDiceXY [(2, 2)] [(1, 2), (1, 1)]
-  , cminPlaceSize = rollDiceXY [(3, 2), (2, 1)] [(5, 1)]
-  , cdarkChance   = rollDeep (1, 80) (1, 40)
-  , cnightChance  = rollDeep (1, 40) (1, 40)
-  , cmaxVoid      = 0
-  , chidden       = 1000
-  , citemNum      = rollDice 4 2  -- fewer rooms
-  , cdefTile      = "noiseSet"
-  , cdarkCorTile  = "pathDark"
-  , clitCorTile   = "pathLit"
-  }
-combat = rogue
-  { csymbol       = 'C'
-  , cname         = "Combat arena"
-  , cfreq         = [("caveCombat", 1)]
-  , cgrid         = rollDiceXY [(2, 2), (3, 1)] [(1, 2), (2, 1)]
-  , cminPlaceSize = rollDiceXY [(3, 1)] [(3, 1)]
-  , cmaxPlaceSize = rollDiceXY [(5, 1)] [(5, 1)]
-  , cdarkChance   = intToDeep 100
-  , cnightChance  = rollDeep (1, 67) (0, 0)
-  , chidden       = 1000
-  , cauxConnects  = 0
-  , cdoorChance   = 1
-  , copenChance   = 0
-  , citemNum      = rollDice 12 2
-  , citemFreq     = [(100, "useful")]
-  , cdefTile      = "combatSet"
-  , cdarkCorTile  = "pathLit"  -- for now, let paths give off light
-  , clitCorTile   = "floorArenaLit"
-  }
diff --git a/src/Content/FactionKind.hs b/src/Content/FactionKind.hs
deleted file mode 100644
--- a/src/Content/FactionKind.hs
+++ /dev/null
@@ -1,84 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | The type of kinds of game factions (heroes, enemies, NPCs, etc.)
--- for Allure of the Stars.
-module Content.FactionKind ( cdefs ) where
-
-import Data.List
-
-import Game.LambdaHack.Common.Ability
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Content.FactionKind
-
-cdefs :: ContentDef FactionKind
-cdefs = ContentDef
-  { getSymbol = fsymbol
-  , getName = fname
-  , getFreq = ffreq
-  , validate = fvalidate
-  , content =
-      [hero, alien, animal, robot, horror]
-  }
-hero,        alien, animal, robot, horror :: FactionKind
-
-hero = FactionKind
-  { fsymbol        = '@'
-  , fname          = "hero"
-  , ffreq          = [("hero", 1)]
-  , fAbilityLeader = allAbilities
-  , fAbilityOther  = meleeAdjacent
-  }
-
--- Includes alien-operated robots, alien-conditioned animals and hybrids.
-alien = FactionKind
-  { fsymbol        = 'a'
-  , fname          = "alien"
-  , ffreq          = [("alien", 1), ("spawn", 20), ("summon", 20)]
-  , fAbilityLeader = allAbilities
-  , fAbilityOther  = allAbilities
-  }
-
-animal = FactionKind
-  { fsymbol        = 'd'
-  , fname          = "animal"
-  , ffreq          = [("animal", 1), ("spawn", 50), ("summon", 50)]
-  , fAbilityLeader = animalAbility
-  , fAbilityOther  = animalAbility
-  }
-
--- Autonomous robots.
-robot = FactionKind
-  { fsymbol        = 'r'
-  , fname          = "robot"
-  , ffreq          = [("robot", 1), ("spawn", 10), ("summon", 10)]
-  , fAbilityLeader = robotAbility
-  , fAbilityOther  = robotAbility
-  }
-
-horror = FactionKind
-  { fsymbol        = 'h'
-  , fname          = "horror"
-  , ffreq          = [("horror", 1), ("summon", 50)]
-  , fAbilityLeader = allAbilities
-  , fAbilityOther  = allAbilities
-  }
-
-
-_noAbility, _onlyFollowTrack, meleeAdjacent, _meleeAndRanged, animalAbility, robotAbility, allAbilities :: [Ability]
-
-_noAbility = []  -- not even projectiles will fly
-
-_onlyFollowTrack = [Track]  -- projectiles enabled
-
-meleeAdjacent = [Track, Melee]
-
-_meleeAndRanged = [Track, Melee, Ranged]  -- melee and reaction fire
-
-animalAbility = [Track, Flee, Melee, Chase, Wander]
-
-robotAbility = delete Flee [minBound..maxBound]
-
-allAbilities = [minBound..maxBound]
diff --git a/src/Content/ItemKind.hs b/src/Content/ItemKind.hs
deleted file mode 100644
--- a/src/Content/ItemKind.hs
+++ /dev/null
@@ -1,247 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Weapons and treasure for Allure of the Stars.
-module Content.ItemKind ( cdefs ) where
-
-import qualified Data.List as L
-
-import Game.LambdaHack.Common.Color
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Common.Effect
-import Game.LambdaHack.Common.Flavour
-import Game.LambdaHack.Common.Random
-import Game.LambdaHack.Content.ItemKind
-
-cdefs :: ContentDef ItemKind
-cdefs = ContentDef
-  { getSymbol = isymbol
-  , getName = iname
-  , getFreq = ifreq
-  , validate = ivalidate
-  , content =
-      [necklace, dart, gem1, gem2, gem3, currency, javelin, kitchenKnife, potion1, potion2, potion3, ring, scroll1, scroll2, scroll3, sword, wand1, wand2, fist, foot, tentacle]
-  }
-necklace,        dart, gem1, gem2, gem3, currency, javelin, kitchenKnife, potion1, potion2, potion3, ring, scroll1, scroll2, scroll3, sword, wand1, wand2, fist, foot, tentacle :: ItemKind
-
-gem, potion, scroll, wand :: ItemKind  -- generic templates
-
--- castDeep (aDb, xDy) = castDice aDb + (lvl - 1) * castDice xDy / (depth - 1)
-
-{- Item group symbols (from Angband, only as an informal convention for now):
-
-! potion, flask, concoction, bottle, jar, vial, canister
-? scroll, book, note, tablet, remote
-, food
-- magical wand, magical rod, transmitter, pistol, rifle
-_ magical staff, scanner
-= ring
-" necklace
-$ currency, gem
-~ light, tool
-/ polearm
-| edged weapon
-\ hafted weapon
-} launcher
-{ projectile
-( clothes
-[ torso armour
-] misc. armour
-) shield
-
--}
-
-necklace = ItemKind
-  { isymbol  = '"'
-  , iname    = "necklace"
-  , ifreq    = [("useful", 6)]
-  , iflavour = zipFancy [BrGreen]
-  , ieffect  = Regeneration (rollDeep (2, 3) (1, 10))
-  , icount   = intToDeep 1
-  , iverbApply   = "tear down"
-  , iverbProject = "cast"
-  , iweight  = 30
-  , itoThrow = -50  -- not dense enough
-  }
-dart = ItemKind
-  { isymbol  = '{'
-  , iname    = "billiard ball"
-  , ifreq    = [("useful", 20)]
-  , iflavour = zipPlain [BrWhite]
-  , ieffect  = Hurt (rollDice 1 1) (rollDeep (1, 2) (1, 2))
-  , icount   = rollDeep (3, 3) (0, 0)
-  , iverbApply   = "splinter"
-  , iverbProject = "hurl"
-  , iweight  = 50
-  , itoThrow = 0  -- a cheap dart
-  }
-gem = ItemKind
-  { isymbol  = '*'
-  , iname    = "precious gem"
-  , ifreq    = [("treasure", 20)]  -- x3, but rare on shallow levels
-  , iflavour = zipPlain $ L.delete BrYellow brightCol  -- natural, so not fancy
-  , ieffect  = NoEffect
-  , icount   = intToDeep 0
-  , iverbApply   = "crush"
-  , iverbProject = "toss"
-  , iweight  = 50
-  , itoThrow = 0
-  }
-gem1 = gem
-  { icount   = rollDeep (0, 0) (1, 1)  -- appears on max depth
-  }
-gem2 = gem
-  { icount   = rollDeep (0, 0) (1, 2)  -- appears halfway
-  }
-gem3 = gem
-  { icount   = rollDeep (0, 0) (1, 3)  -- appears early
-  }
-currency = ItemKind
-  { isymbol  = '$'
-  , iname    = "gold grain"
-  , ifreq    = [("treasure", 20), ("currency", 1)]
-  , iflavour = zipPlain [BrYellow]
-  , ieffect  = NoEffect
-  , icount   = rollDeep (0, 0) (10, 10)  -- appears on lvl 2
-  , iverbApply   = "smear"
-  , iverbProject = "blow away"
-  , iweight  = 1
-  , itoThrow = 0
-  }
-javelin = ItemKind
-  { isymbol  = '{'
-  , iname    = "javelin"
-  , ifreq    = [("useful", 30)]
-  , iflavour = zipPlain [Brown]
-  , ieffect  = Hurt (rollDice 1 2) (rollDeep (1, 2) (2, 2))
-  , icount   = rollDeep (0, 0) (1, 1)
-  , iverbApply   = "break up"
-  , iverbProject = "hurl"
-  , iweight  = 2000
-  , itoThrow = 0  -- cheap but deadly
-  }
-kitchenKnife = ItemKind
-  { isymbol  = '{'
-  , iname    = "kitchen knife"
-  , ifreq    = [("useful", 25)]
-  , iflavour = zipPlain [BrCyan]
-  , ieffect  = Hurt (rollDice 1 1) (rollDeep (0, 0) (1, 2))
-  , icount   = rollDeep (0, 0) (1, 2)
-  , iverbApply   = "bend"
-  , iverbProject = "throw"
-  , iweight  = 200
-  , itoThrow = -50  -- too flexible and the handle causes air resistance
-  }
-potion = ItemKind
-  { isymbol  = '!'
-  , iname    = "vial"
-  , ifreq    = [("useful", 15)]
-  , iflavour = zipFancy stdCol
-  , ieffect  = NoEffect
-  , icount   = intToDeep 1
-  , iverbApply   = "gulp down"
-  , iverbProject = "lob"
-  , iweight  = 200
-  , itoThrow = -50  -- oily, bad grip
-  }
-potion1 = potion
-  { ifreq    = [("useful", 5)]
-  , ieffect  = ApplyPerfume
-  }
-potion2 = potion
-  { ieffect  = Heal 5
-  }
-potion3 = potion
-  { ifreq    = [("useful", 5)]
-  , ieffect  = Heal (-5)
-  }
-ring = ItemKind
-  { isymbol  = '='
-  , iname    = "ring"
-  , ifreq    = []  -- [("useful", 10)]  -- TODO: make it useful
-  , iflavour = zipPlain [White]
-  , ieffect  = Searching (rollDeep (1, 6) (3, 2))
-  , icount   = intToDeep 1
-  , iverbApply   = "squeeze down"
-  , iverbProject = "toss"
-  , iweight  = 15
-  , itoThrow = 0
-  }
-scroll = ItemKind
-  { isymbol  = '?'
-  , iname    = "tablet"
-  , ifreq    = [("useful", 4)]
-  , iflavour = zipFancy darkCol  -- arcane and old
-  , ieffect  = NoEffect
-  , icount   = intToDeep 1
-  , iverbApply   = "dial"
-  , iverbProject = "lob"
-  , iweight  = 700
-  , itoThrow = -25  -- bad grip
-  }
-scroll1 = scroll
-  { ieffect  = CallFriend 1
-  }
-scroll2 = scroll
-  { ieffect  = Summon 1
-  }
-scroll3 = scroll
-  { ieffect  = Ascend 1
-  }
-sword = ItemKind
-  { isymbol  = '/'
-  , iname    = "sharpened pipe"
-  , ifreq    = [("useful", 40)]
-  , iflavour = zipPlain [Cyan]
-  , ieffect  = Hurt (rollDice 3 1) (rollDeep (1, 2) (4, 2))
-  , icount   = intToDeep 1
-  , iverbApply   = "hit"
-  , iverbProject = "heave"
-  , iweight  = 3000
-  , itoThrow = -25  -- bad grip
-  }
-wand = ItemKind
-  { isymbol  = '-'
-  , iname    = "injector"
-  , ifreq    = [("useful", 15)]
-  , iflavour = zipFancy brightCol
-  , ieffect  = NoEffect
-  , icount   = intToDeep 1
-  , iverbApply   = "snap"
-  , iverbProject = "zap"
-  , iweight  = 300
-  , itoThrow = 25  -- jet
-  }
-wand1 = wand
-  { ieffect  = Dominate
-  }
-wand2 = wand
-  { ifreq    = [("useful", 3)]
-  , ieffect  = Heal (-25)
-  }
-fist = sword
-  { isymbol  = '@'
-  , iname    = "fist"
-  , ifreq    = [("hth", 1), ("unarmed", 100)]
-  , ieffect  = Hurt (rollDice 3 1) (intToDeep 0)
-  , iverbApply   = "punch"
-  , iverbProject = "ERROR, please report: iverbProject fist"
-  }
-foot = sword
-  { isymbol  = '@'
-  , iname    = "foot"
-  , ifreq    = [("hth", 1), ("unarmed", 50)]
-  , ieffect  = Hurt (rollDice 3 1) (intToDeep 0)
-  , iverbApply   = "kick"
-  , iverbProject = "ERROR, please report: iverbProject foot"
-  }
-tentacle = sword
-  { isymbol  = 'S'
-  , iname    = "tentacle"
-  , ifreq    = [("hth", 1), ("monstrous", 100)]
-  , ieffect  = Hurt (rollDice 3 1) (intToDeep 0)
-  , iverbApply   = "hit"
-  , iverbProject = "ERROR, please report: iverbProject tentacle"
-  }
diff --git a/src/Content/ModeKind.hs b/src/Content/ModeKind.hs
deleted file mode 100644
--- a/src/Content/ModeKind.hs
+++ /dev/null
@@ -1,321 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | The type of kinds of game modes for Allure of the Stars.
-module Content.ModeKind ( cdefs ) where
-
-import qualified Data.EnumMap.Strict as EM
-
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Content.ModeKind
-
-cdefs :: ContentDef ModeKind
-cdefs = ContentDef
-  { getSymbol = msymbol
-  , getName = mname
-  , getFreq = mfreq
-  , validate = mvalidate
-  , content =
-      [campaign, skirmish, pvp, coop, defense, screensaver, testCoop, testDefense, peekCampaign, peekSkirmish]
-  }
-campaign,        skirmish, pvp, coop, defense, screensaver, testCoop, testDefense, peekCampaign, peekSkirmish :: ModeKind
-
-campaign = ModeKind
-  { msymbol  = 'r'
-  , mname    = "campaign"
-  , mfreq    = [("campaign", 1)]
-  , mplayers = playersCampaign
-  , mcaves   = cavesCampaign
-  }
-
-skirmish = ModeKind
-  { msymbol  = 's'
-  , mname    = "skirmish"
-  , mfreq    = [("skirmish", 1)]
-  , mplayers = playersSkirmish
-  , mcaves   = cavesCombat
-  }
-
-pvp = ModeKind
-  { msymbol  = 'p'
-  , mname    = "PvP"
-  , mfreq    = [("PvP", 1)]
-  , mplayers = playersPvP
-  , mcaves   = cavesCombat
-  }
-
-coop = ModeKind
-  { msymbol  = 'c'
-  , mname    = "Coop"
-  , mfreq    = [("Coop", 1)]
-  , mplayers = playersCoop
-  , mcaves   = cavesCampaign
-  }
-
-defense = ModeKind
-  { msymbol  = 'd'
-  , mname    = "defense"
-  , mfreq    = [("defense", 1)]
-  , mplayers = playersDefense
-  , mcaves   = cavesDefense
-  }
-
-screensaver = ModeKind
-  { msymbol  = 'n'
-  , mname    = "screensaver"
-  , mfreq    = [("screensaver", 1)]
-  , mplayers = playersScreensaver
-  , mcaves   = cavesCampaign
-  }
-
-testCoop = ModeKind
-  { msymbol  = 't'
-  , mname    = "testCoop"
-  , mfreq    = [("testCoop", 1)]
-  , mplayers = playersTestCoop
-  , mcaves   = cavesCampaign
-  }
-
-testDefense = ModeKind
-  { msymbol  = 'u'
-  , mname    = "testDefense"
-  , mfreq    = [("testDefense", 1)]
-  , mplayers = playersTestDefense
-  , mcaves   = cavesDefense
-  }
-
-peekCampaign = ModeKind
-  { msymbol  = 'e'
-  , mname    = "peekCampaign"
-  , mfreq    = [("peekCampaign", 1)]
-  , mplayers = playersPeekCampaign
-  , mcaves   = cavesCampaign
-  }
-
-peekSkirmish = ModeKind
-  { msymbol  = 'f'
-  , mname    = "peekSkirmish"
-  , mfreq    = [("peekSkirmish", 1)]
-  , mplayers = playersPeekSkirmish
-  , mcaves   = cavesCombat
-  }
-
-
-playersCampaign, playersSkirmish, playersPvP, playersCoop, playersDefense, playersScreensaver, playersTestCoop, playersTestDefense, playersPeekCampaign, playersPeekSkirmish :: Players
-
-playersCampaign = Players
-  { playersList = [ playerHero {playerInitial = 1}
-                  , playerMonster
-                  , playerAnimal
-                  , playerRobot ]
-  , playersEnemy = [ ("Spaceship Crew", "Alien Hierarchy")
-                   , ("Spaceship Crew", "Animal Kingdom")
-                   , ("Spaceship Crew", "Robotic Anarchy") ]
-  , playersAlly = [] }
-
-playersSkirmish = Players
-  { playersList = [ playerHero {playerName = "White"}
-                  , playerAntiHero {playerName = "Purple"}
-                  , playerHorror ]
-  , playersEnemy = [ ("White", "Purple")
-                   , ("White", "Horror Den")
-                   , ("Purple", "Horror Den") ]
-  , playersAlly = [] }
-
-playersPvP = Players
-  { playersList = [ playerHero {playerName = "Red"}
-                  , playerHero {playerName = "Blue"}
-                  , playerHorror ]
-  , playersEnemy = [ ("Red", "Blue")
-                   , ("Red", "Horror Den")
-                   , ("Blue", "Horror Den") ]
-  , playersAlly = [] }
-
-playersCoop = Players
-  { playersList = [ playerHero { playerName = "Coral"
-                               , playerInitial = 1 }
-                  , playerHero { playerName = "Amber"
-                               , playerInitial = 1 }
-                  , playerMonster
-                  , playerAnimal
-                  , playerRobot ]
-  , playersEnemy = [ ("Coral", "Alien Hierarchy")
-                   , ("Coral", "Animal Kingdom")
-                   , ("Coral", "Robotic Anarchy")
-                   , ("Amber", "Alien Hierarchy")
-                   , ("Amber", "Animal Kingdom")
-                   , ("Amber", "Robotic Anarchy") ]
-  , playersAlly = [("Coral", "Amber")] }
-
-playersDefense = Players
-  { playersList = [ playerMonster { playerInitial = 1
-                                  , playerEntry = toEnum 1
-                                  , playerAiLeader = False
-                                  , playerHuman = True
-                                  , playerUI = True }
-                  , playerAnimal
-                  , playerRobot
-                  , playerAntiHero {playerName = "Green"}
-                  , playerAntiHero {playerName = "Yellow"}
-                  , playerAntiHero {playerName = "Cyan"} ]
-  , playersEnemy = [ ("Green", "Alien Hierarchy")
-                   , ("Green", "Animal Kingdom")
-                   , ("Green", "Robotic Anarchy")
-                   , ("Yellow", "Alien Hierarchy")
-                   , ("Yellow", "Animal Kingdom")
-                   , ("Yellow", "Robotic Anarchy")
-                   , ("Cyan", "Alien Hierarchy")
-                   , ("Cyan", "Animal Kingdom")
-                   , ("Cyan", "Robotic Anarchy") ]
-  , playersAlly = [ ("Green", "Yellow")
-                  , ("Green", "Cyan")
-                  , ("Yellow", "Cyan") ] }
-
-playersScreensaver = Players
-  { playersList = [ playerHero { playerInitial = 5
-                               , playerAiLeader = True
-                               , playerHuman = False }
-                  , playerMonster
-                  , playerAnimal
-                  , playerRobot ]
-  , playersEnemy = [ ("Spaceship Crew", "Alien Hierarchy")
-                   , ("Spaceship Crew", "Animal Kingdom")
-                   , ("Spaceship Crew", "Robotic Anarchy") ]
-  , playersAlly = [] }
-
-playersTestCoop = Players
-  { playersList = [ playerHero { playerName = "Coral"
-                               , playerAiLeader = True
-                               , playerHuman = False }
-                  , playerHero { playerName = "Amber"
-                               , playerAiLeader = True
-                               , playerHuman = False }
-                  , playerMonster
-                  , playerAnimal
-                  , playerRobot ]
-  , playersEnemy = [ ("Coral", "Alien Hierarchy")
-                   , ("Coral", "Animal Kingdom")
-                   , ("Coral", "Robotic Anarchy")
-                   , ("Amber", "Alien Hierarchy")
-                   , ("Amber", "Animal Kingdom")
-                   , ("Amber", "Robotic Anarchy") ]
-  , playersAlly = [("Coral", "Amber")] }
-
-playersTestDefense = Players
-  { playersList = [ playerMonster { playerInitial = 1
-                                  , playerEntry = toEnum 1
-                                  , playerUI = True }
-                  , playerAnimal
-                  , playerRobot
-                  , playerAntiHero {playerName = "Green"}
-                  , playerAntiHero {playerName = "Yellow"}
-                  , playerAntiHero {playerName = "Cyan"} ]
-  , playersEnemy = [ ("Green", "Alien Hierarchy")
-                   , ("Green", "Animal Kingdom")
-                   , ("Green", "Robotic Anarchy")
-                   , ("Yellow", "Alien Hierarchy")
-                   , ("Yellow", "Animal Kingdom")
-                   , ("Yellow", "Robotic Anarchy")
-                   , ("Cyan", "Alien Hierarchy")
-                   , ("Cyan", "Animal Kingdom")
-                   , ("Cyan", "Robotic Anarchy") ]
-  , playersAlly = [ ("Green", "Yellow")
-                  , ("Green", "Cyan")
-                  , ("Yellow", "Cyan") ] }
-
-playersPeekCampaign = Players
-  { playersList = [ playerHero {playerInitial = 1}
-                  , playerMonster {playerUI = True}
-                  , playerAnimal
-                  , playerRobot ]
-  , playersEnemy = [ ("Spaceship Crew", "Alien Hierarchy")
-                   , ("Spaceship Crew", "Animal Kingdom")
-                   , ("Spaceship Crew", "Robotic Anarchy") ]
-  , playersAlly = [] }
-
-playersPeekSkirmish = Players
-  { playersList = [ playerHero {playerName = "White"}
-                  , playerAntiHero { playerName = "Purple"
-                                   , playerUI = True }
-                  , playerHorror ]
-  , playersEnemy = [ ("White", "Purple")
-                   , ("White", "Horror Den")
-                   , ("Purple", "Horror Den") ]
-  , playersAlly = [] }
-
-
-playerHero, playerAntiHero, playerMonster, playerAnimal, playerRobot, playerHorror :: Player
-
-playerHero = Player
-  { playerName = "Spaceship Crew"
-  , playerFaction = "hero"
-  , playerEntry = toEnum 1
-  , playerInitial = 3
-  , playerAiLeader = False
-  , playerAiOther = True
-  , playerHuman = True
-  , playerUI = True
-  }
-
-playerAntiHero = playerHero
-  { playerAiLeader = True
-  , playerHuman = False
-  , playerUI = False
-  }
-
-playerMonster = Player
-  { playerName = "Alien Hierarchy"
-  , playerFaction = "alien"
-  , playerEntry = toEnum 5
-  , playerInitial = 3
-  , playerAiLeader = True
-  , playerAiOther = True
-  , playerHuman = False
-  , playerUI = False
-  }
-
-playerAnimal = Player
-  { playerName = "Animal Kingdom"
-  , playerFaction = "animal"
-  , playerEntry = toEnum 3
-  , playerInitial = 3
-  , playerAiLeader = True
-  , playerAiOther = True
-  , playerHuman = False
-  , playerUI = False
-  }
-
-playerRobot = Player
-  { playerName = "Robotic Anarchy"
-  , playerFaction = "robot"
-  , playerEntry = toEnum 4
-  , playerInitial = 3
-  , playerAiLeader = True
-  , playerAiOther = True
-  , playerHuman = False
-  , playerUI = False
-  }
-
-playerHorror = Player
-  { playerName = "Horror Den"
-  , playerFaction = "horror"
-  , playerEntry = toEnum 1
-  , playerInitial = 0
-  , playerAiLeader = True
-  , playerAiOther = True
-  , playerHuman = False
-  , playerUI = False
-  }
-
-
-cavesCampaign, cavesCombat, cavesDefense :: Caves
-
-cavesCampaign = EM.fromList [ (toEnum 1, ("caveRogue", Nothing))
-                            , (toEnum 12, ("caveNoise", Just True))]
-
-cavesCombat = EM.fromList [(toEnum 3, ("caveCombat", Nothing))]
-
-cavesDefense = EM.fromList [ (toEnum 1, ("dng", Nothing))
-                           , (toEnum 5, ("caveEmpty", Just True))]
diff --git a/src/Content/PlaceKind.hs b/src/Content/PlaceKind.hs
deleted file mode 100644
--- a/src/Content/PlaceKind.hs
+++ /dev/null
@@ -1,148 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Rooms, halls and passages for Allure of the Stars.
-module Content.PlaceKind ( cdefs ) where
-
-import Game.LambdaHack.Common.ContentDef
-import Game.LambdaHack.Content.PlaceKind
-
-cdefs :: ContentDef PlaceKind
-cdefs = ContentDef
-  { getSymbol = psymbol
-  , getName = pname
-  , getFreq = pfreq
-  , validate = pvalidate
-  , content =
-      [rect, oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells]
-  }
-rect,        oval, ovalFloor, ovalSquare, colonnade, colonnadeWide, maze,  maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind
-
-rect = PlaceKind  -- Valid for any nonempty area, hence low frequency.
-  { psymbol  = 'r'
-  , pname    = "room"
-  , pfreq    = [("rogue", 100)]
-  , pcover   = CStretch
-  , pfence   = FWall
-  , ptopLeft = ["."]
-  }
-oval = PlaceKind
-  { psymbol  = 'o'
-  , pname    = "oval room"
-  , pfreq    = [("rogue", 1000)]
-  , pcover   = CStretch
-  , pfence   = FWall
-  , ptopLeft = [ "####.."
-               , "##...."
-               , "#....."
-               , "#....."
-               , "......"
-               , "......"
-               ]
-  }
-ovalFloor = oval  -- Without outer solid fence, visible from outside.
-  { pfreq    = [("rogue", 10000)]
-  , pfence   = FFloor
-  , ptopLeft = [ "XXXX+#"
-               , "XX###."
-               , "X##..."
-               , "X#...."
-               , "+#...."
-               , "#....."
-               ]
-  }
-ovalSquare = ovalFloor
-  { ptopLeft = [ "X###+"
-               , "##..."
-               , "#...."
-               , "#...."
-               , "+...."
-               ]
-  }
-colonnade = PlaceKind
-  { psymbol  = 'c'
-  , pname    = "colonnade"
-  , pfreq    = [("rogue", 1000)]
-  , pcover   = CAlternate
-  , pfence   = FFloor
-  , ptopLeft = [ ".#"
-               , "#."
-               ]
-  }
-colonnadeWide = colonnade
-  { pfreq    = [("rogue", 50)]
-  , pfence   = FWall
-  , ptopLeft = [ ".."
-               , ".#"
-               ]
-  }
-maze = PlaceKind
-  { psymbol  = 'm'
-  , pname    = "maze"
-  , pfreq    = [("rogue", 20)]
-  , pcover   = CStretch
-  , pfence   = FNone
-  , ptopLeft = [ "#.#.##"
-               , "##.#.."
-               , "#.##.#"
-               , "#.#.#."
-               ]
-  }
-maze2 = maze
-  { ptopLeft = [ "###.##"
-               , ".###.."
-               , "..#..#"
-               , ".#..#."
-               ]
-  }
-maze3 = maze
-  { ptopLeft = [ "###.##"
-               , ".##.#."
-               , "..##.#"
-               , ".#..#."
-               ]
-  }
-mazeBig = maze
-  { pfreq    = [("rogue", 1000)]
-  , ptopLeft = [ "#.#.##"
-               , ".#.#.."
-               , "#.&.##"
-               , ".#.#.."
-               , "#.#..#"
-               , "#.#.#."
-               ]
-  }
-mazeBig2 = mazeBig
-  { ptopLeft = [ "##..##"
-               , "#.##.."
-               , ".#.###"
-               , ".##.#."
-               , "#.#&.#"
-               , "#.#.#."
-               ]
-  }
-mazeBig3 = mazeBig
-  { ptopLeft = [ "##..##"
-               , "#.###."
-               , ".#...#"
-               , ".#.##."
-               , "##.#.#"
-               , "#.#.#."
-               ]
-  }
-cells = PlaceKind
-  { psymbol  = '#'
-  , pname    = "cells"
-  , pfreq    = [("rogue", 30)]
-  , pcover   = CReflect
-  , pfence   = FWall
-  , ptopLeft = [ "..#"
-               , "..#"
-               , "##."
-               ]
-  }
--- TODO: obtain all the reet as places nested within places.
--- 3 places are enough, with 1 or 2 tiles between places,
--- on all sides, only vertical, only horizontal,
diff --git a/src/Content/RuleKind.hs b/src/Content/RuleKind.hs
deleted file mode 100644
--- a/src/Content/RuleKind.hs
+++ /dev/null
@@ -1,80 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Game rules and assorted game setup data for Allure of the Stars.
-module Content.RuleKind ( cdefs ) where
-
-import Language.Haskell.TH.Syntax
-
--- Cabal
-import qualified Paths_Allure as Self (getDataFileName, version)
-
-import Game.LambdaHack.Common.ContentDef
-import qualified Game.LambdaHack.Common.Feature as F
-import Game.LambdaHack.Content.RuleKind
-import Game.LambdaHack.Content.TileKind
-
-cdefs :: ContentDef RuleKind
-cdefs = ContentDef
-  { getSymbol = rsymbol
-  , getName = rname
-  , getFreq = rfreq
-  , validate = ruvalidate
-  , content =
-      [standard]
-  }
-
-standard :: RuleKind
-standard = RuleKind
-  { rsymbol        = 's'
-  , rname          = "standard Allure of the Stars ruleset"
-  , rfreq          = [("standard", 100)]
-  -- Check whether one position is accessible from another.
-  -- Precondition: the two positions are next to each other.
-  -- TODO: in the future check flying for chasms, swimming for water, etc.
-  , raccessible    = \ _lxsize _spos _src _tpos tgt ->
-      F.Walkable `elem` tfeature tgt
-  , rtitle         = "Allure of the Stars"
-  , rpathsDataFile = Self.getDataFileName
-  , rpathsVersion  = Self.version
-  , ritemMelee     = "/|\\"
-  , ritemRanged    = "}{"
-  -- Wasting weapons and armour would be too cruel to the player.
-  , ritemProject   = "!?,-~}{"
-  -- The strings containing the default configuration files,
-  -- included from files config.game.default and config.ui.default.
-  -- Warning: cabal does not detect that the config files are changed,
-  -- so touching them is needed to reinclude configs and recompile.
-  -- Note: consider code.haskell.org/~dons/code/compiled-constants
-  -- as soon as the config file grows very big.
-  , rcfgRulesDefault = $(do
-      qAddDependentFile "config.rules.default"
-      x <- qRunIO (readFile "config.rules.default")
-      lift x)
-  , rcfgUIDefault = $(do
-      qAddDependentFile "config.ui.default"
-      x <- qRunIO (readFile "config.ui.default")
-      lift x)
-  -- ASCII art for the Main Menu. Only pure 7-bit ASCII characters are
-  -- allowed. The picture should be exactly 24 rows by 80 columns,
-  -- plus an extra frame (of any characters) that is ignored.
-  -- For a different screen size, the picture is centered and the outermost
-  -- rows and columns cloned. When displayed in the Main Menu screen,
-  -- it's overwritten with the game version string and keybinding strings.
-  -- The game version string begins and ends with a space and is placed
-  -- in the very bottom right corner. The keybindings overwrite places
-  -- marked with 25 left curly brace signs '{' in a row. The sign is forbidden
-  -- everywhere else. A specific number of such places with 25 left braces
-  -- are required, at most one per row, and all are overwritten
-  -- with text that is flushed left and padded with spaces.
-  -- The Main Menu is displayed dull white on black.
-  -- TODO: Show highlighted keybinding in inverse video or bright white on grey
-  -- background. The spaces that pad keybindings are not highlighted.
-  , rmainMenuArt = $(do
-      qAddDependentFile "MainMenu.ascii"
-      x <- qRunIO (readFile "MainMenu.ascii")
-      lift x)
-  }
diff --git a/src/Content/TileKind.hs b/src/Content/TileKind.hs
deleted file mode 100644
--- a/src/Content/TileKind.hs
+++ /dev/null
@@ -1,223 +0,0 @@
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | Terrain tiles for Allure of the Stars.
-module Content.TileKind ( cdefs ) where
-
-import Game.LambdaHack.Common.Color
-import Game.LambdaHack.Common.ContentDef
-import qualified Game.LambdaHack.Common.Effect as Effect
-import Game.LambdaHack.Common.Feature
-import Game.LambdaHack.Content.TileKind
-
-cdefs :: ContentDef TileKind
-cdefs = ContentDef
-  { getSymbol = tsymbol
-  , getName = tname
-  , getFreq = tfreq
-  , validate = tvalidate
-  , content =
-      [wall, wallCache, hardRock, pillar, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorCorridorDark, floorItemLit, floorItemDark, floorActorItemLit, floorActorItemDark, floorRedDark, floorBlueDark, floorGreenDark, floorRedLit, floorBlueLit, floorGreenLit]
-  }
-wall,        wallCache, hardRock, pillar, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorCorridorDark, floorItemLit, floorItemDark, floorActorItemLit, floorActorItemDark, floorRedDark, floorBlueDark, floorGreenDark, floorRedLit, floorBlueLit, floorGreenLit :: TileKind
-
-wall = TileKind
-  { tsymbol  = '#'
-  , tname    = "granite wall"
-  , tfreq    = [ ("fillerWall", 1), ("cachable", 70)
-               , ("litLegend", 100), ("darkLegend", 100)
-               , ("noiseSet", 55) ]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [HideAs "suspect wall"]
-  }
-wallCache = TileKind
-  { tsymbol  = '&'
-  , tname    = "cache"
-  , tfreq    = [ ("cachable", 30)
-               , ("litLegend", 100), ("darkLegend", 100) ]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [Cause $ Effect.CreateItem 1, ChangeTo "cachable"]
-  }
-hardRock = TileKind
-  { tsymbol  = '#'
-  , tname    = "outer hull"
-  , tfreq    = [("outer fence", 1)]
-  , tcolor   = BrBlack
-  , tcolor2  = BrBlack
-  , tfeature = [Impenetrable]
-  }
-pillar = TileKind
-  { tsymbol  = 'O'
-  , tname    = "rock"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100), ("combatSet", 3)]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = []
-  }
-tree = TileKind
-  { tsymbol  = 'O'
-  , tname    = "tree"
-  , tfreq    = [("combatSet", 8)]
-  , tcolor   = BrGreen
-  , tcolor2  = Green
-  , tfeature = []
-  }
-wallSuspect = TileKind
-  { tsymbol  = '#'
-  , tname    = "moldy wall"
-  , tfreq    = [("suspect wall", 1)]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [ Suspect
-               , RevealAs "closed door"
-               ]
-  }
-doorClosed = TileKind
-  { tsymbol  = '+'
-  , tname    = "closed door"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100), ("closed door", 1)]
-  , tcolor   = Brown
-  , tcolor2  = BrBlack
-  , tfeature = [Exit, OpenTo "open door", HideAs "suspect wall"]
-  }
-doorOpen = TileKind
-  { tsymbol  = '\''
-  , tname    = "open door"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100), ("open door", 1)]
-  , tcolor   = Brown
-  , tcolor2  = BrBlack
-  , tfeature = [Walkable, Clear, Exit, CloseTo "closed door"]
-  }
-stairsUp = TileKind
-  { tsymbol  = '<'
-  , tname    = "staircase up"
-  , tfreq    = []  -- TODO: [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause $ Effect.Ascend 1]
-  }
-stairsDown = TileKind
-  { tsymbol  = '>'
-  , tname    = "staircase down"
-  , tfreq    = []  -- TODO: [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause $ Effect.Ascend (-1)]
-  }
-escapeUp = TileKind
-  { tsymbol  = '<'
-  , tname    = "exit airlock up"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrYellow
-  , tcolor2  = BrYellow
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause Effect.Escape]
-  }
-escapeDown = TileKind
-  { tsymbol  = '>'
-  , tname    = "exit trapdoor down"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrYellow
-  , tcolor2  = BrYellow
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause Effect.Escape]
-  }
-liftUp = TileKind
-  { tsymbol  = '<'
-  , tname    = "lift up"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrCyan
-  , tcolor2  = BrCyan
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause $ Effect.Ascend 1]
-  }
-lift = TileKind
-  { tsymbol  = '<'
-  , tname    = "lift"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrBlue
-  , tcolor2  = BrBlue
-  , tfeature = [ Walkable, Clear, Lit, Exit
-               , Cause $ Effect.Ascend 1
-               , Cause $ Effect.Ascend (-1) ]
-  }
-liftDown = TileKind
-  { tsymbol  = '>'
-  , tname    = "lift down"
-  , tfreq    = [("litLegend", 100), ("darkLegend", 100)]
-  , tcolor   = BrCyan
-  , tcolor2  = BrCyan
-  , tfeature = [Walkable, Clear, Lit, Exit, Cause $ Effect.Ascend (-1)]
-  }
-unknown = TileKind
-  { tsymbol  = ' '
-  , tname    = "unknown space"
-  , tfreq    = [("unknown space", 1)]
-  , tcolor   = defFG
-  , tcolor2  = BrWhite
-  , tfeature = []
-  }
-floorCorridorLit = TileKind
-  { tsymbol  = '.'
-  , tname    = "floor"
-  , tfreq    = [ ("floorCorridorLit", 1), ("floorArenaLit", 1)
-               , ("arenaSet", 1), ("noiseSet", 100), ("combatSet", 100) ]
-  , tcolor   = BrWhite
-  , tcolor2  = defFG
-  , tfeature = [Walkable, Clear, Lit]
-  }
-floorCorridorDark = floorCorridorLit
-  { tfreq    = [ ("floorCorridorDark", 1)
-               , ("arenaSet", 1), ("noiseSet", 100), ("combatSet", 100) ]
-  , tcolor   = BrYellow
-  , tcolor2  = BrBlack
-  , tfeature = [Walkable, Clear]
-  }
-floorItemLit = floorCorridorLit
-  { tfreq    = []
-  , tfeature = CanItem : tfeature floorCorridorLit
-  }
-floorItemDark = floorCorridorDark
-  { tfreq    = []
-  , tfeature = CanItem : tfeature floorCorridorDark
-  }
-floorActorItemLit = floorItemLit
-  { tfreq    = [("litLegend", 100), ("emptySet", 1)]
-  , tfeature = CanActor : tfeature floorItemLit
-  }
-floorActorItemDark = floorItemDark
-  { tfreq    = [("darkLegend", 100), ("emptySet", 1)]
-  , tfeature = CanActor : tfeature floorItemDark
-  }
-floorRedDark = floorCorridorDark
-  { tname    = "emergency walkway"
-  , tfreq    = [("pathDark", 20)]
-  , tcolor   = BrRed
-  , tcolor2  = Red
-  , tfeature = Path : tfeature floorCorridorDark
-  }
-floorRedLit  = floorRedDark
-  { tfreq    = [("pathLit", 20)]
-  , tfeature = Lit : tfeature floorRedDark
-  }
-floorBlueDark = floorRedDark
-  { tname    = "transport route"
-  , tfreq    = [("pathDark", 100)]
-  , tcolor   = BrBlue
-  , tcolor2  = Blue
-  }
-floorBlueLit = floorBlueDark
-  { tfreq    = [("pathLit", 100)]
-  , tfeature = Lit : tfeature floorBlueDark
-  }
-floorGreenDark = floorRedDark
-  { tname    = "greenery path"
-  , tfreq    = [("pathDark", 100)]
-  , tcolor   = BrGreen
-  , tcolor2  = Green
-  }
-floorGreenLit = floorGreenDark
-  { tfreq    = [("pathLit", 100)]
-  , tfeature = Lit : tfeature floorGreenDark
-  }
diff --git a/src/Main.hs b/src/Main.hs
deleted file mode 100644
--- a/src/Main.hs
+++ /dev/null
@@ -1,55 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-orphans #-}
--- Copyright (c) 2008--2011 Andres Loeh, 2010--2012 Mikolaj Konarski
--- This file is a part of the computer game Allure of the Stars
--- and is released under the terms of the GNU Affero General Public License.
--- For license and copyright information, see the file LICENSE.
---
--- | The main source code file of Allure of the Stars. Here the knot of engine
--- code pieces and the Allure-specific content defintions is tied,
--- resulting in an executable game.
-module Main ( main ) where
-
-import qualified Content.ActorKind
-import qualified Content.CaveKind
-import qualified Content.FactionKind
-import qualified Content.ItemKind
-import qualified Content.ModeKind
-import qualified Content.PlaceKind
-import qualified Content.RuleKind
-import qualified Content.TileKind
-import Game.LambdaHack.Client
-import Game.LambdaHack.Client.Action.ActionType
-import Game.LambdaHack.Common.Action (MonadAtomic (..))
-import Game.LambdaHack.Common.AtomicCmd
-import Game.LambdaHack.Common.AtomicSem
-import qualified Game.LambdaHack.Common.Kind as Kind
-import Game.LambdaHack.Server
-import Game.LambdaHack.Server.Action.ActionType
-import Game.LambdaHack.Server.AtomicSemSer
-
--- | The game-state semantics of atomic game commands
--- as computed on the server.
-instance MonadAtomic ActionSer where
-  execAtomic = atomicSendSem
-
--- | The game-state semantics of atomic game commands
--- as computed on clients. Special effects (@SfxAtomic@) don't modify state.
-instance MonadAtomic (ActionCli c d) where
-  execAtomic (CmdAtomic cmd) = cmdAtomicSem cmd
-  execAtomic (SfxAtomic _) = return ()
-
--- | Tie the LambdaHack engine clients and server code
--- with the Allure-specific content defintions and run the game.
-main :: IO ()
-main =
-  let copsSlow = Kind.COps
-        { coactor   = Kind.createOps Content.ActorKind.cdefs
-        , cocave    = Kind.createOps Content.CaveKind.cdefs
-        , cofaction = Kind.createOps Content.FactionKind.cdefs
-        , coitem    = Kind.createOps Content.ItemKind.cdefs
-        , comode    = Kind.createOps Content.ModeKind.cdefs
-        , coplace   = Kind.createOps Content.PlaceKind.cdefs
-        , corule    = Kind.createOps Content.RuleKind.cdefs
-        , cotile    = Kind.createOps Content.TileKind.cdefs
-        }
-  in mainSer copsSlow executorSer $ exeFrontend executorCli executorCli
