packages feed

SpacePrivateers (empty) → 0.1.0.0

raw patch · 23 files changed

+2773/−0 lines, 23 filesdep +LambdaHackdep +basedep +containerssetup-changedbinary-added

Dependencies added: LambdaHack, base, containers, enummapset-th, filepath, template-haskell, text

Files

+ CREDITS view
@@ -0,0 +1,3 @@+Space Privateers use LambdaHack engine. Many thanks to all people who have+contributed on it. Space Privateers used original LambdaHack files as a +starting point for game definition.
+ GameDefinition/Client/UI/Content/KeyKind.hs view
@@ -0,0 +1,171 @@+-- | The default game key-command mapping to be used for UI. Can be overriden+-- via macros in the config file.+module Client.UI.Content.KeyKind ( standardKeys ) where++import Control.Arrow (first)++import qualified Game.LambdaHack.Client.Key as K+import Game.LambdaHack.Client.UI.Content.KeyKind+import Game.LambdaHack.Client.UI.HumanCmd+import qualified Game.LambdaHack.Common.Effect as Effect+import qualified Game.LambdaHack.Common.Feature as F+import Game.LambdaHack.Common.Misc++standardKeys :: KeyKind+standardKeys = KeyKind+  { 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-a", ([CmdMenu], GameRestart "campaign"))+      , ("CTRL-d", ([CmdMenu], GameDifficultyCycle))++      -- Movement and terrain alteration+      , ("less", ([CmdMove, CmdMinimal], TriggerTile+           [ TriggerFeature { verb = "ascend"+                            , object = "a level"+                            , feature = F.Cause (Effect.Ascend 1) }+           , TriggerFeature { verb = "escape"+                            , object = "dungeon"+                            , feature = F.Cause (Effect.Escape 1) } ]))+      , ("CTRL-less", ([CmdMove], TriggerTile+           [ TriggerFeature { verb = "ascend"+                            , object = "10 levels"+                            , feature = F.Cause (Effect.Ascend 10) } ]))+      , ("greater", ([CmdMove, CmdMinimal], TriggerTile+           [ TriggerFeature { verb = "descend"+                            , object = "a level"+                            , feature = F.Cause (Effect.Ascend (-1)) }+           , TriggerFeature { verb = "escape"+                            , object = "dungeon"+                            , feature = F.Cause (Effect.Escape (-1)) } ]))+      , ("CTRL-greater", ([CmdMove], TriggerTile+           [ TriggerFeature { verb = "descend"+                            , object = "10 levels"+                            , feature = F.Cause (Effect.Ascend (-10)) } ]))+      , ("semicolon", ([CmdMove], StepToTarget))+      , ("colon", ([CmdMove], Macro "go to target for 100 steps"+                                    ["semicolon", "V"]))+      , ("CTRL-colon", ([CmdMove], Macro "go to target for 10 steps"+                                         ["semicolon", "CTRL-V"]))+      , ("x", ([CmdMove], Macro "explore the closest unknown spot"+                                [ "BackSpace"+                                , "CTRL-question", "semicolon", "V" ]))+      , ("X", ([CmdMove], Macro "autoexplore 100 times"+                                [ "BackSpace"+                                , "'", "CTRL-question", "semicolon", "'"+                                , "V" ]))+      , ("CTRL-X", ([CmdMove], Macro "autoexplore 10 times"+                                      [ "BackSpace"+                                      , "'", "CTRL-question", "semicolon", "'"+                                      , "CTRL-V" ]))+      , ("R", ([CmdMove], Macro "rest (wait 100 times)"+                                ["KP_Begin", "V"]))+      , ("CTRL-R", ([CmdMove], Macro "rest (wait 10 times)"+                                     ["KP_Begin", "CTRL-V"]))+      , ("c", ([CmdMove], AlterDir+           [ AlterFeature { verb = "close"+                          , object = "door"+                          , feature = F.CloseTo "vertical closed door Lit" }+           , AlterFeature { verb = "close"+                          , object = "door"+                          , feature = F.CloseTo "horizontal closed door Lit" }+           , AlterFeature { verb = "close"+                          , object = "door"+                          , feature = F.CloseTo "vertical closed door Dark" }+           , AlterFeature { verb = "close"+                          , object = "door"+                          , feature = F.CloseTo "horizontal closed door Dark" }+           ]))+      , ("period", ([CmdMove], Macro "" ["KP_Begin"]))+      , ("i", ([CmdMove], Macro "" ["KP_Begin"]))++      -- Item use+      , ("E", ([CmdItem], DescribeItem CEqp))+      , ("P", ([CmdItem], DescribeItem CInv))+      , ("S", ([CmdItem], DescribeItem CSha))+      , ("G", ([CmdItem], DescribeItem CGround))+      , ("A", ([CmdItem], AllOwned))+      , ("g", ([CmdItem, CmdMinimal],+               MoveItem [CGround] CEqp "get" "an item" True))+      , ("d", ([CmdItem], MoveItem [CEqp, CInv, CSha] CGround+                                   "drop" "an item" False))+      , ("e", ([CmdItem], MoveItem [CInv, CSha] CEqp+                                   "equip" "an item" False))+      , ("p", ([CmdItem], MoveItem [CEqp, CSha] CInv+                                   "pack" "an item into inventory backpack"+                                   False))+      , ("s", ([CmdItem], MoveItem [CEqp, CInv] CSha+                                   "stash" "and share an item" False))+      , ("a", ([CmdItem, CmdMinimal], Apply+           [ ApplyItem { verb = "activate"+                       , object = "applicable item"+                       , symbol = ' ' }+           , ApplyItem { verb = "quaff"+                       , object = "potion"+                       , symbol = '!' }+           , ApplyItem { verb = "read"+                       , object = "scroll"+                       , symbol = '?' }+           ]))+      , ("q", ([CmdItem], Apply [ApplyItem { verb = "quaff"+                                           , object = "potion"+                                           , symbol = '!' }]))+      , ("r", ([CmdItem], Apply [ApplyItem { verb = "read"+                                           , object = "scroll"+                                           , symbol = '?' }]))+      , ("f", ([CmdItem, CmdMinimal], Project+           [ApplyItem { verb = "fling"+                      , object = "projectable item"+                      , symbol = ' ' }]))+      , ("t", ([CmdItem], Project [ApplyItem { verb = "throw"+                                             , object = "missile"+                                             , symbol = '|' }]))+      , ("z", ([CmdItem], Project [ApplyItem { verb = "zap"+                                             , object = "wand"+                                             , symbol = '/' }]))++      -- Targeting+      , ("KP_Multiply", ([CmdTgt, CmdMinimal], TgtEnemy))+      , ("backslash", ([CmdTgt], Macro "" ["KP_Multiply"]))+      , ("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))++      -- Automation+      , ("equal", ([CmdAuto], SelectActor))+      , ("underscore", ([CmdAuto], SelectNone))+      , ("v", ([CmdAuto], Repeat 1))+      , ("V", ([CmdAuto], Repeat 100))+      , ("CTRL-v", ([CmdAuto], Repeat 1000))+      , ("CTRL-V", ([CmdAuto], Repeat 10))+      , ("apostrophe", ([CmdAuto], Record))+      , ("CTRL-A", ([CmdAuto], Automate))++      -- Assorted+      , ("question", ([CmdMeta], Help))+      , ("D", ([CmdMeta], History))+      , ("T", ([CmdMeta], MarkSuspect))+      , ("Z", ([CmdMeta], MarkVision))+      , ("C", ([CmdMeta], MarkSmell))+      , ("Tab", ([CmdMeta], MemberCycle))+      , ("ISO_Left_Tab", ([CmdMeta], MemberBack))+      , ("space", ([CmdMeta], Clear))+      , ("Escape", ([CmdMeta, CmdMinimal], Cancel))+      , ("Return", ([CmdMeta], Accept))++      -- Debug and others not to display in help screens+      , ("CTRL-s", ([CmdDebug], GameSave))+      ]+  }
+ GameDefinition/Content/CaveKind.hs view
@@ -0,0 +1,69 @@+-- | Cave layouts for Space Privateers.+module Content.CaveKind ( cdefs ) where++import Data.Ratio++import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.CaveKind++cdefs :: ContentDef CaveKind+cdefs = ContentDef+  { getSymbol = csymbol+  , getName = cname+  , getFreq = cfreq+  , validate = validateCaveKind+  , content =+      [rogue, munitorium]+  }+rogue,        munitorium :: CaveKind++rogue = CaveKind+  { csymbol         = 'R'+  , cname           = "General quarters"+  , cfreq           = [("dng", 100), ("caveRogue", 1)]+  , cxsize          = fst normalLevelBound + 1+  , cysize          = snd normalLevelBound + 1+  , cgrid           = DiceXY (3 * d 2) (d 2 + 2)+  , cminPlaceSize   = DiceXY (2 * d 2 + 2) 4+  , cmaxPlaceSize   = DiceXY 15 10+  , cdarkChance     = d 54 + dl 20+  , cnightChance    = 51+  , cauxConnects    = 1%3+  , cmaxVoid        = 1%6+  , cminStairDist   = 30+  , cdoorChance     = 1%2+  , copenChance     = 1%10+  , chidden         = 8+  , cactorFreq      = [("merchant", 50), ("chaos", 45), ("spawn", 5)]+  , citemNum        = 10 * d 2+  , citemFreq       = [("useful", 70), ("treasure", 30)]+  , cplaceFreq      = [("rogue", 100)]+  , cpassable       = False+  , cdefTile        = "fillerWall"+  , cdarkCorTile    = "floorCorridorDark"+  , clitCorTile     = "floorCorridorLit"+  , cfillerTile     = "fillerWall"+  , couterFenceTile = "basic outer fence"+  , clegendDarkTile = "legendDark"+  , clegendLitTile  = "legendLit"+  }+munitorium = rogue+  { csymbol         = 'M'+  , cname           = "Munitorium"+  , cfreq           = [("dng", 15), ("munitorium", 1)]+  , cgrid           = DiceXY 3 3+  , cminPlaceSize   = DiceXY 15 4+  , cmaxPlaceSize   = DiceXY 25 10+  , cdarkChance     = dl 5+  , cnightChance    = d 20+  , cactorFreq      = [("merchant", 80), ("chaos", 5), ("spawn", 15)]+  , citemNum        = 8 * d 2+  , citemFreq       = [("weapon", 70), ("armour", 20), ("useful", 10)]+  , cplaceFreq      = [("rogue", 100)]+  , cpassable       = True+  , cdefTile        = "arenaSet"+  , cdarkCorTile    = "floorArenaDark"+  , clitCorTile     = "floorArenaLit"+}
+ GameDefinition/Content/FactionKind.hs view
@@ -0,0 +1,73 @@+-- | The type of kinds of game factions (heroes, enemies, NPCs, etc.)+-- for Space Privateers.+module Content.FactionKind ( cdefs ) where++import qualified Data.EnumMap.Strict as EM++import Game.LambdaHack.Common.Ability+import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Content.FactionKind++cdefs :: ContentDef FactionKind+cdefs = ContentDef+  { getSymbol = fsymbol+  , getName = fname+  , getFreq = ffreq+  , validate = validateFactionKind+  , content =+      [hero, merchant, chaos, spawn, horror]+  }+hero,        merchant, chaos, spawn, horror :: FactionKind++hero = FactionKind+  { fsymbol       = '1'+  , fname         = "hero"+  , ffreq         = [("hero", 1)]+  , fSkillsLeader = allSkills+  , fSkillsOther  = meleeAdjacent+  }++merchant = FactionKind+  { fsymbol       = '@'+  , fname         = "merchant"+  , ffreq         = [("merchant", 1)]+  , fSkillsLeader = allSkills+  , fSkillsOther  = allSkills+  }++chaos = FactionKind+  { fsymbol       = 'c'+  , fname         = "chaos"+  , ffreq         = [("chaos", 1)]+  , fSkillsLeader = allSkills+  , fSkillsOther  = allSkills+  }++spawn = FactionKind+  { fsymbol       = 's'+  , fname         = "spawn"+  , ffreq         = [("spawn", 1)]+  , fSkillsLeader = animalSkills+  , fSkillsOther  = animalSkills+  } ++horror = FactionKind+  { fsymbol       = 'h'+  , fname         = "horror"+  , ffreq         = [("horror", 1)]+  , fSkillsLeader = animalSkills+  , fSkillsOther  = animalSkills+  }+++meleeAdjacent, _meleeAndRanged, animalSkills, allSkills :: Skills++meleeAdjacent = EM.fromList $ zip [AbWait, AbMelee] [1, 1..]++-- Melee and reaction fire.+_meleeAndRanged = EM.fromList $ zip [AbWait, AbMelee, AbProject] [1, 1..]++animalSkills =+  EM.fromList $ zip [AbMove, AbMelee, AbAlter, AbWait, AbTrigger] [1, 1..]++allSkills = unitSkills
+ GameDefinition/Content/ItemKind.hs view
@@ -0,0 +1,688 @@+-- | Weapon and treasure definitions.+module Content.ItemKind ( cdefs ) where++import Data.List++import Content.ItemKindActor+import Content.ItemKindOrgan+import Content.ItemKindShrapnel+import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Effect+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.ItemKind++cdefs :: ContentDef ItemKind+cdefs = ContentDef+  { getSymbol = isymbol+  , getName = iname+  , getFreq = ifreq+  , validate = validateItemKind+  , content = items ++ organs ++ shrapnels ++ actors+  }++items :: [ItemKind]+items =+  [decipulum, brassLantern, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, oculus, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, ring1, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, armorLeather, armorMail, whetstone, grenade1, grenade2]++decipulum,    brassLantern, buckler, dart, dart200, gem1, gem2, gem3, gloveFencing, gloveGauntlet, gloveJousting, currency, gorget, harpoon, oculus, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, net, oilLamp, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, potion10, ring1, ring2, ring3, ring4, ring5, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, shield, dagger, hammer, sword, halberd, wand1, wand2, armorLeather, armorMail, whetstone, grenade1, grenade2 :: ItemKind++gem, grenade, necklace, potion, ring, scroll, wand :: ItemKind  -- generic templates++-- * Thrown weapons++dart = ItemKind+  { isymbol  = '|'+  , iname    = "dart"+  , ifreq    = [("useful", 100), ("any arrow", 100), ("weapon", 100)]+  , iflavour = zipPlain [Cyan]+  , icount   = 3 * d 3+  , irarity  = [(1, 20)]+  , iverbHit = "prick"+  , iweight  = 50+  , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]+  , ieffects = [Hurt (d 2)]+  , ifeature = []+  , idesc    = "Little, but sharp and sturdy."+  , ikit     = []+  }+dart200 = ItemKind+  { isymbol  = '|'+  , iname    = "fine dart"+  , ifreq    = [("useful", 100), ("any arrow", 50), ("weapon", 75)]+  , iflavour = zipPlain [BrRed]+  , icount   = 3 * d 3+  , irarity  = [(4, 20)]+  , iverbHit = "prick"+  , iweight  = 50+  , iaspects = [AddHurtRanged ((d 6 + dl 6) |*| 10)]+  , ieffects = [Hurt (d 2)]+  , ifeature = [toVelocity 200]+  , idesc    = "Finely balanced for throws of great speed."+  , ikit     = []+  }++-- * Exotic thrown weapons++decipulum = ItemKind+  { isymbol  = '|'+  , iname    = "decipulum majoris"+  , ifreq    = [("useful", 100), ("weapon", 50)]+  , iflavour = zipPlain [BrYellow]+  , icount   = dl 4+  , irarity  = [(5, 5), (10, 5)]+  , iverbHit = "entangle"+  , iweight  = 500+  , iaspects = []+  , ieffects = [Hurt (d 2), Paralyze (5 + d 5), ActivateInv '!']+  , ifeature = []+  , idesc    = "A web of springs in form of spheres. When thrown, this weapon can trip unwary opponents."+  , ikit     = []+  }+harpoon = ItemKind+  { isymbol  = '|'+  , iname    = "Force spear"+  , ifreq    = [("useful", 100), ("starting weapon", 100), ("weapon", 50)]+  , iflavour = zipPlain [Brown]+  , icount   = dl 5+  , irarity  = [(5, 5), (10, 20)]+  , iverbHit = "hook"+  , iweight  = 4000+  , iaspects = [AddHurtRanged ((d 2 + 2 * dl 5) |*| 10)]+  , ieffects = [Hurt (d 4), PullActor (ThrowMod 200 50)]+  , ifeature = []+  , idesc    = "The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying."+  , ikit     = []+  }+net = ItemKind+  { isymbol  = '|'+  , iname    = "net"+  , ifreq    = [("useful", 100), ("weapon", 60)]+  , iflavour = zipPlain [White]+  , icount   = dl 3+  , irarity  = [(3, 5), (10, 4)]+  , iverbHit = "entangle"+  , iweight  = 1000+  , iaspects = []+  , ieffects = [ Hurt (d 2)+               , Paralyze (5 + d 5)+               , DropBestWeapon, DropEqp ']' False ]+  , ifeature = []+  , idesc    = "A web made of monofilaments. Will both cut and entagle the prey."+  , ikit     = []+  }++-- * Lights++oilLamp = ItemKind+  { isymbol  = '('+  , iname    = "oil lamp"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(5, 4), (10, 4)]+  , iverbHit = "burn"+  , iweight  = 1000+  , iaspects = [AddLight 3, AddSight (-1)]+  , ieffects = [Burn 3, Paralyze 3, OnSmash (Explode "burning ignisium 3")]+  , ifeature = [ toVelocity 70+               , Fragile, EqpSlot EqpSlotAddLight "", Identified ]+  , idesc    = "A clay lamp filled with ignisium feeding a tiny wick."+  , ikit     = []+  }+brassLantern = ItemKind+  { isymbol  = '('+  , iname    = "brass lantern"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 1+  , irarity  = [(10, 3)]+  , iverbHit = "burn"+  , iweight  = 2400+  , iaspects = [AddLight 4, AddSight (-1)]+  , ieffects = [Burn 4, Paralyze 4, OnSmash (Explode "burning ignisium 4")]+  , ifeature = [ toVelocity 70  -- hard to throw so that it opens and burns+               , Fragile, EqpSlot EqpSlotAddLight "", Identified ]+  , idesc    = "Very bright and very heavy brass lantern."+  , ikit     = []+  }++-- * Treasure++gem = ItemKind+  { isymbol  = '*'+  , iname    = "gem"+  , ifreq    = [("treasure", 100)]+  , iflavour = zipPlain $ delete BrYellow brightCol+  , icount   = 1+  , irarity  = []+  , iverbHit = "tap"+  , iweight  = 50+  , iaspects = [AddLight 1, AddSpeed (-1)]+  , ieffects = []+  , ifeature = [ Durable+               , Precious ]+  , idesc    = "Useless, and still worth around 100 gold each. Would gems of thought and pearls of artful design be valued that much in our age of Science and Progress!"+  , ikit     = []+  }+gem1 = gem+  { irarity  = [(2, 0), (10, 10)]+  }+gem2 = gem+  { irarity  = [(5, 0), (10, 10)]+  }+gem3 = gem+  { irarity  = [(8, 0), (10, 10)]+  }+currency = ItemKind+  { isymbol  = '$'+  , iname    = "gold piece"+  , ifreq    = [("treasure", 100), ("currency", 1)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 10 + d 20 + dl 20+  , irarity  = [(1, 0), (5, 20), (10, 10)]+  , iverbHit = "tap"+  , iweight  = 31+  , iaspects = []+  , ieffects = []+  , ifeature = [Durable, Identified, Precious]+  , idesc    = "Reliably valuable in every civilized plane of existence."+  , ikit     = []+  }++-- * Periodic jewelry++gorget = ItemKind+  { isymbol  = '"'+  , iname    = "gorget"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy [BrCyan]+  , irarity  = [(4, 1), (10, 2)]+  , icount   = 1+  , iverbHit = "whip"+  , iweight  = 30+  , iaspects = [Periodic $ d 4 + dl 4, AddArmorMelee 1, AddArmorRanged 1]+  , ieffects = [RefillCalm 1]+  , ifeature = [ Precious, EqpSlot EqpSlotPeriodic "", Identified+               , toVelocity 50 ]+  , idesc    = "Highly ornamental, cold, large, steel medallion on a chain. Unlikely to offer much protection as an armor piece, but the old, worn engraving reassures you."+  , ikit     = []+  }+necklace = ItemKind+  { isymbol  = '"'+  , iname    = "necklace"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy stdCol ++ zipPlain brightCol+  , irarity  = [(4, 2), (10, 5)]+  , icount   = 1+  , iverbHit = "whip"+  , iweight  = 30+  , iaspects = []+  , ieffects = []+  , ifeature = [ Precious, EqpSlot EqpSlotPeriodic ""+               , toVelocity 50 ]+  , idesc    = "Menacing Greek symbols shimmer with increasing speeds along a chain of fine encrusted links. After a tense build-up, a prismatic arc shoots towards the ground and the iridescence subdues, becomes ordered and resembles a harmless ornament again, for a time."+  , ikit     = []+  }+necklace1 = necklace+  { iaspects = [Periodic $ d 2 + dl 2]+  , ieffects = [RefillHP 1]+  , idesc    = "A cord of dried herbs and healing berries."+  }+necklace2 = necklace+  { irarity  = [(2, 0), (10, 1)]+  , iaspects = [Periodic $ d 4 + dl 2]+  , ieffects = [ Impress+               , Summon [("summonable animal", 1)] $ 1 + dl 2, Explode "waste" ]+  }+necklace3 = necklace+  { iaspects = [Periodic $ d 4 + dl 2]+  , ieffects = [Paralyze $ 5 + d 5 + dl 5, RefillCalm 999]+  }+necklace4 = necklace+  { iaspects = [Periodic $ 2 * d 10 + dl 10]+  , ieffects = [Teleport $ 2 + d 3]+  }+necklace5 = necklace+  { iaspects = [Periodic $ d 4 + dl 2]+  , ieffects = [Teleport $ 10 + d 10]+  }+necklace6 = necklace+  { iaspects = [Periodic $ 2 * d 5 + dl 5]+  , ieffects = [PushActor (ThrowMod 100 50)]+  }+necklace7 = necklace+  { irarity  = [(4, 0), (10, 2)]+  , iaspects = [Periodic $ 2 * d 5 + dl 15]+  , ieffects = [InsertMove 1, RefillHP (-1)]+  , ifeature = ifeature necklace ++ [Durable]+      -- evil players would throw before death, to destroy+      -- TODO: teach AI to wear only for fight; prevent players from meleeing+      -- allies with that (Durable)+  }++-- * Non-periodic jewelry++oculus = ItemKind+  { isymbol  = '='+  , iname    = "oculus cursus"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [White]+  , icount   = 1+  , irarity  = [(6, 0), (10, 1)]+  , iverbHit = "rap"+  , iweight  = 50+  , iaspects = [AddSight $ dl 3]+  , ieffects = []+  , ifeature = [Precious, Identified, Durable, EqpSlot EqpSlotAddSight ""]+  , idesc    = "Arcane device to boost your sight."+  , ikit     = []+  }+ring = ItemKind+  { isymbol  = '='+  , iname    = "ring"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain stdCol ++ zipFancy darkCol+  , icount   = 1+  , irarity  = [(6, 2), (10, 5)]+  , iverbHit = "knock"+  , iweight  = 15+  , iaspects = []+  , ieffects = []+  , ifeature = [Precious, Identified]+  , idesc    = "It looks like an ordinary object, but it's in fact a generator of exceptional effects: adding to some of your natural abilities and subtracting from others. You'd profit enormously if you could find a way to multiply such generators..."+  , ikit     = []+  }+ring1 = ring+  { irarity  = [(2, 0), (10, 2)]+  , iaspects = [AddSpeed 1, AddMaxHP $ dl 3 - 5 - d 3]+  , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddSpeed ""]+  }+ring2 = ring+  { iaspects = [AddMaxHP $ 3 + dl 5, AddMaxCalm $ dl 6 - 15 - d 6]+  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxHP ""]+  }+ring3 = ring+  { iaspects = [AddMaxCalm $ 10 + dl 10]+  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxCalm ""]+  , idesc    = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words."+  }+ring4 = ring  -- TODO: move to level-ups and to timed effects+  { irarity  = [(3, 8), (10, 12)]+  , iaspects = [AddHurtMelee $ 3 * d 4 + dl 15, AddMaxHP $ dl 3 - 4 - d 2]+  , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddHurtMelee ""]+  }+ring5 = ring  -- by the time it's found, probably no space in eqp+  { irarity  = [(5, 0), (10, 1)]+  , iaspects = [AddLight $ d 2]+  , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddLight ""]+  , idesc    = "A sturdy ring with a large, shining stone."+  }++-- * Exploding consumables, often intended to be thrown++potion = ItemKind+  { isymbol  = '!'+  , iname    = "vial"+  , ifreq    = [("useful", 100), ("any vial", 100)]+  , iflavour = zipPlain stdCol ++ zipFancy brightCol+  , icount   = 1+  , irarity  = [(1, 10), (10, 8)]+  , iverbHit = "splash"+  , iweight  = 200+  , iaspects = []+  , ieffects = []+  , ifeature = [ toVelocity 50+               , Applicable, Fragile ]+  , idesc    = "A flask of bubbly, slightly oily liquid of a suspect color."+  , ikit     = []+  }+potion1 = potion+  { ieffects = [ NoEffect "of rose water", Impress+               , OnSmash (ApplyPerfume), OnSmash (Explode "fragrance") ]+  }+potion2 = potion+  { ifreq    = [("useful", 1)]+  , irarity  = [(10, 1)]+  , ieffects = [ NoEffect "of musky concoction", Impress, DropBestWeapon+               , OnSmash (Explode "pheromone")]+  }+potion3 = potion+  { ieffects = [RefillHP 5, OnSmash (Explode "healing mist")]+  }+potion4 = potion+  { irarity  = [(1, 5)]+  , ieffects = [RefillHP (-5), OnSmash (Explode "wounding mist")]+  }+potion5 = potion+  { ieffects = [ Explode "explosion blast 10", Impress+               , PushActor (ThrowMod 200 75)+               , OnSmash (Explode "explosion blast 10") ]+  }+potion6 = potion+  { irarity  = [(10, 2)]+  , ieffects = [ NoEffect "of distortion"+               , OnSmash (Explode "distortion")]+  }+potion7 = potion+  { ieffects = [ NoEffect "of bait cocktail", Impress+               , OnSmash (Summon [("summonable animal", 1)] $ 1 + dl 2)+               , OnSmash (Explode "waste") ]+  }+potion8 = potion+  { ieffects = [ OneOf [Impress, DropBestWeapon, RefillHP 5, Burn 3]+               , OnSmash (OneOf [ Explode "healing mist"+                                , Explode "wounding mist"+                                , Explode "fragrance"+                                , Explode "explosion blast 10" ]) ]+  }+potion9 = potion+  { irarity  = [(4, 1), (10, 2)]+  , ieffects = [ OneOf [ Dominate, DropBestWeapon, RefillHP 15, Burn 9+                       , InsertMove 2]+               , OnSmash (OneOf [ Explode "healing mist"+                                , Explode "healing mist"+                                , Explode "pheromone"+                                , Explode "distortion"+                                , Explode "explosion blast 20" ]) ]+  }+potion10 = potion+  { ifreq    = [("useful", 100), ("potion of glue", 1)]+  , irarity  = [(1, 1)]+  , icount   = 1 + d 2+  , ieffects = [ NoEffect "of glue", Paralyze (5 + d 5)+               , OnSmash (Explode "glue")]+  }+grenade = ItemKind+  { isymbol  = '*'+  , iname    = "grenade"+  , ifreq    = [("useful", 100), ("weapon", 25)]+  , iflavour = zipPlain stdCol ++ zipFancy brightCol+  , icount   = 1+  , irarity  = [(1, 1), (10, 3)]+  , iverbHit = "explode"+  , iweight  = 200+  , iaspects = []+  , ieffects = []+  , ifeature = [ toVelocity 200+               , Fragile +               , Identified ]+  , idesc    = "Small metal canister, with safety latch and finely engraved surface."+  , ikit     = []+  }+grenade1 = grenade+  { irarity  = [(1, 1), (10, 3)]+  , ieffects = [ NoEffect "of explosionis"+               , OnSmash (Explode "explosion blast 10") ]+  }+grenade2 = grenade+  { irarity  = [(1, 1), (10, 3)]+  , ieffects = [ NoEffect "of ignisium"+               , OnSmash (Explode "burning ignisium 2") ]+  }+-- * Non-exploding consumables, not specifically designed for throwing++scroll = ItemKind+  { isymbol  = '?'+  , iname    = "scroll"+  , ifreq    = [("useful", 100), ("any scroll", 100)]+  , iflavour = zipFancy stdCol ++ zipPlain darkCol+  , icount   = 1+  , irarity  = [(1, 10), (10, 7)]+  , iverbHit = "thump"+  , iweight  = 50+  , iaspects = []+  , ieffects = []+  , ifeature = [ toVelocity 25+               , Applicable ]+  , idesc    = "Scraps of haphazardly scribbled mysteries from beyond. Is this equation an alchemical recipe? Is this diagram an extradimensional map? Is this formula a secret call sign?"+  , ikit     = []+  }+scroll1 = scroll+  { irarity  = [(10, 2)]+  , ieffects = [CallFriend 1]+  }+scroll2 = scroll+  { irarity  = [(1, 5), (10, 3)]+  , ieffects = [NoEffect "of fireworks", Explode "firecracker 7"]+  }+scroll3 = scroll+  { irarity  = [(1, 4), (10, 2)]+  , ieffects = [Ascend (-1)]+  }+scroll4 = scroll+  { ieffects = [ OneOf [ Teleport $ 2 + d 5, RefillCalm 10, RefillCalm (-10)+                       , InsertMove 4, Paralyze 10, Identify CGround ] ]+  }+scroll5 = scroll+  { irarity  = [(1, 4), (10, 6)]+  , ieffects = [ OneOf [ Summon standardSummon $ d 2+                       , CallFriend 1, Ascend (-1), Ascend 1+                       , RefillCalm 30, RefillCalm (-30), CreateItem $ d 2+                       , PolyItem CGround ] ]+               -- TODO: ask player: Escape 1+  }+scroll6 = scroll+  { ieffects = [Teleport $ 2 + d 5]+  }+scroll7 = scroll+  { irarity  = [(10, 2)]+  , ieffects = [InsertMove $ d 2 + dl 2]+  }+scroll8 = scroll+  { irarity  = [(3, 6), (10, 3)]+  , ieffects = [Identify CGround]  -- TODO: ask player: AskPlayer cstore eff?+  }+scroll9 = scroll+  { irarity  = [(3, 3), (10, 9)]+  , ieffects = [PolyItem CGround]+  }++standardSummon :: Freqs+standardSummon = [("monster", 30), ("summonable animal", 70)]++-- * Armor++armorLeather = ItemKind+  { isymbol  = '['+  , iname    = "leather armor"+  , ifreq    = [("useful", 100), ("armour", 100)]+  , iflavour = zipPlain [Brown]+  , icount   = 1+  , irarity  = [(4, 9)]+  , iverbHit = "thud"+  , iweight  = 7000+  , iaspects = [ AddHurtMelee (-3)+               , AddArmorMelee $ (1 + dl 3) |*| 5+               , AddArmorRanged $ (1 + dl 3) |*| 5 ]+  , ieffects = []+  , ifeature = [ toVelocity 30+               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]+  , idesc    = "A stiff jacket formed from leather boiled in bee wax. Smells much better than the rest of your garment."+  , ikit     = []+  }+armorMail = armorLeather+  { iname    = "mail armor"+  , iflavour = zipPlain [Cyan]+  , irarity  = [(7, 9)]+  , iweight  = 12000+  , iaspects = [ AddHurtMelee (-3)+               , AddArmorMelee $ (2 + dl 3) |*| 5+               , AddArmorRanged $ (2 + dl 3) |*| 5 ]+  , idesc    = "A long shirt woven from iron rings. Discourages foes from attacking your torso, making it harder for them to land a blow."+  }+gloveFencing = ItemKind+  { isymbol  = '['+  , iname    = "leather gauntlet"+  , ifreq    = [("useful", 100), ("armour", 100)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(4, 6), (10, 12)]+  , iverbHit = "flap"+  , iweight  = 100+  , iaspects = [ AddHurtMelee $ 2 * (d 3 + 2 * dl 5)+               , AddArmorRanged $ d 2 + dl 2 ]+  , ieffects = []+  , ifeature = [ toVelocity 30+               , Durable, EqpSlot EqpSlotAddArmorRanged "", Identified ]+  , idesc    = "A fencing glove from rough leather ensuring a good grip. Also quite effective in deflecting or even catching slow projectiles."+  , ikit     = []+  }+gloveGauntlet = gloveFencing+  { iname    = "steel gauntlet"+  , irarity  = [(6, 12)]+  , iflavour = zipPlain [BrCyan]+  , iweight  = 300+  , iaspects = [ AddArmorMelee $ 2 * (d 2 + dl 2)+               , AddArmorRanged $ 2 * (d 2 + dl 2) ]+  , idesc    = "Long leather gauntlet covered in overlapping steel plates."+  }+gloveJousting = gloveFencing+  { iname    = "jousting gauntlet"+  , irarity  = [(6, 6)]+  , iflavour = zipFancy [BrRed]+  , iweight  = 500+  , iaspects = [ AddHurtMelee $ - 10 - d 5 + dl 5+               , AddArmorMelee $ 2 * (d 2 + dl 3)+               , AddArmorRanged $ 2 * (d 2 + dl 3) ]+  , idesc    = "Rigid, steel, jousting handgear. If only you had a lance. And a horse."+  }++buckler = ItemKind+  { isymbol  = '['+  , iname    = "buckler"+  , ifreq    = [("useful", 100), ("armour", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 1+  , irarity  = [(4, 7)]+  , iverbHit = "bash"+  , iweight  = 2000+  , iaspects = [AddArmorMelee 40, AddHurtMelee (-30)]+  , ieffects = []+  , ifeature = [ toVelocity 30+               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]+  , idesc    = "Heavy and unwieldy. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with."+  , ikit     = []+  }+shield = buckler+  { iname    = "shield"+  , irarity  = [(7, 7)]+  , iflavour = zipPlain [Green]+  , iweight  = 3000+  , iaspects = [AddArmorMelee 80, AddHurtMelee (-70)]+  , ifeature = [ toVelocity 20+               , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ]+  , idesc    = "Large and unwieldy. Absorbs a percentage of melee damage, both dealt and sustained. Too heavy to intercept projectiles with."+  }++-- * Weapons++dagger = ItemKind+  { isymbol  = ')'+  , iname    = "dagger"+  , ifreq    = [("useful", 100), ("starting weapon", 100), ("weapon", 100)]+  , iflavour = zipPlain [BrCyan]+  , icount   = 1+  , irarity  = [(1, 20), (10, 4)]+  , iverbHit = "stab"+  , iweight  = 1000+  , iaspects = [AddHurtMelee $ 2 * (d 3 + 2 * dl 5), AddArmorMelee $ d 4 + dl 4]+  , ieffects = [Hurt (d 4)]+  , ifeature = [ toVelocity 40+               , Durable, EqpSlot EqpSlotWeapon "", Identified ]+  , idesc    = "A short dagger for thrusting and parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon."+  , ikit     = []+  }+hammer = ItemKind+  { isymbol  = ')'+  , iname    = "storm hammer"+  , ifreq    = [("useful", 100), ("weapon", 60), ("starting weapon", 100)]+  , iflavour = zipPlain [BrMagenta]+  , icount   = 1+  , irarity  = [(4, 12), (10, 2)]+  , iverbHit = "club"+  , iweight  = 1500+  , iaspects = [AddHurtMelee $ d 3 + 2 * dl 5]+  , ieffects = [Hurt (d 6), PushActor (ThrowMod 200 50)]+  , ifeature = [ toVelocity 20+               , Durable, EqpSlot EqpSlotWeapon "", Identified ]+  , idesc    = "Mighty hammer that releases blast of electricity when it hits target."+  , ikit     = []+  }+sword = ItemKind+  { isymbol  = ')'+  , iname    = "sword"+  , ifreq    = [("useful", 100), ("starting weapon", 100), ("weapon", 75)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 1+  , irarity  = [(3, 1), (6, 20), (10, 10)]+  , iverbHit = "slash"+  , iweight  = 2000+  , iaspects = []+  , ieffects = [Hurt (d 8)]+  , ifeature = [ toVelocity 20+               , Durable, EqpSlot EqpSlotWeapon "", Identified ]+  , idesc    = "Common vibroblade, favoured by those who like to get close and personal."+  , ikit     = []+  }+halberd = ItemKind+  { isymbol  = ')'+  , iname    = "halberd"+  , ifreq    = [("useful", 100), ("weapon", 50)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 1+  , irarity  = [(7, 1), (10, 10)]+  , iverbHit = "impale"+  , iweight  = 3000+  , iaspects = [AddArmorMelee $ 2 * (d 4 + dl 4)]+  , ieffects = [Hurt (d 12)]+  , ifeature = [ toVelocity 20+               , Durable, EqpSlot EqpSlotWeapon "", Identified ]+  , idesc    = "Versatile, with great reach and leverage. Foes are held at a distance."+  , ikit     = []+  }++-- * Wands++wand = ItemKind+  { isymbol  = '/'+  , iname    = "wand"+  , ifreq    = [("useful", 100)]+  , iflavour = zipFancy brightCol+  , icount   = 1+  , irarity  = []  -- TODO: add charges, etc.+  , iverbHit = "club"+  , iweight  = 300+  , iaspects = [AddLight 1, AddSpeed (-1)]+  , ieffects = []+  , ifeature = [ toVelocity 125+               , Applicable, Durable ]+  , idesc    = "Buzzing with dazzling light that shines even through appendages that handle it."+  , ikit     = []+  }+wand1 = wand+  { ieffects = []+  }+wand2 = wand+  { ieffects = []+  }++-- * Assorted tools++whetstone = ItemKind+  { isymbol  = '~'+  , iname    = "whetstone"+  , ifreq    = [("useful", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 1+  , irarity  = [(5, 5)]+  , iverbHit = "smack"+  , iweight  = 400+  , iaspects = [AddHurtMelee $ 2 * (d 3 + 2 * dl 5)]+  , ieffects = []+  , ifeature = [EqpSlot EqpSlotAddHurtMelee "", Identified]+  , idesc    = "A portable sharpening stone that lets you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop."+  , ikit     = []+  }
+ GameDefinition/Content/ItemKindActor.hs view
@@ -0,0 +1,165 @@+-- | Actor (or rather actor body trunk) definitions.+module Content.ItemKindActor ( actors ) where++import qualified Data.EnumMap.Strict as EM++import Game.LambdaHack.Common.Ability+import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.Effect+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Misc+import Game.LambdaHack.Content.ItemKind++actors :: [ItemKind]+actors = privateers ++ merchants ++ forcesOfChaos ++ spawns ++ animals++privateers, merchants, forcesOfChaos, spawns, animals :: [ItemKind]++privateers    = [warrior, scout]+merchants     = [merchant, merchantSgt]+forcesOfChaos = [chaosWarrior, chaosLord]+spawns        = [warpBeast]+animals       = [ventLizard]++warrior, scout :: ItemKind+merchant, merchantSgt :: ItemKind+chaosWarrior, chaosLord :: ItemKind+warpBeast :: ItemKind+ventLizard :: ItemKind++-- * Heroes (hero)++warrior = ItemKind+  { isymbol  = '@'+  , iname    = "warrior"+  , ifreq    = [("hero", 100)]+  , iflavour = zipPlain [BrBlack]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "thud"+  , iweight  = 80000+  , iaspects = [ AddMaxHP 50, AddMaxCalm 60, AddSpeed 20+               , AddSight 3 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "PBI, ready to take the next city vessel."+  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 4", COrgan),+                ("starting weapon", CEqp)]+  }++scout = warrior+  { iname    = "scout"+  , iaspects = [ AddMaxHP 40, AddMaxCalm 60, AddSpeed 25+               , AddSight 4 ]+  , idesc    = "Fast and keen scouts are essential any fighting force."+  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 5", COrgan),+                ("any arrow", CInv), ("any vial", CInv), ("any vial", CInv)]+  }++-- * Merchant Mariners (merchant)++merchant = ItemKind+  { isymbol  = '@'+  , iname    = "merchant mariner"+  , ifreq    = [("merchant", 100)]+  , iflavour = zipPlain [Blue]+  , icount   = 1+  , irarity  = [(1, 10)]+  , iverbHit = "thud"+  , iweight  = 80000+  , iaspects = [ AddMaxHP 30, AddMaxCalm 40, AddSpeed 20+               , AddSight 3 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "Merchant mariners are operating city vessels on their endless journey to stars."+  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 4", COrgan)]+  }++merchantSgt = merchant+  { iname    = "merchant mariner sgt"+  , ifreq    = [("merchant", 100)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 1+  , irarity  = [(1, 1), (10, 3)]+  , iverbHit = "thud"+  , iweight  = 80000+  , iaspects = [ AddMaxHP 40, AddMaxCalm 60, AddSpeed 20+               , AddSight 3 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "Squad leader for merchant mariners"+  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 4", COrgan),+                ("starting weapon", CEqp)]+  }++-- * Forces of Chaos (chaos)++chaosWarrior = ItemKind+  { isymbol  = 'c'+  , iname    = "chaos warrior"+  , ifreq    = [("chaos", 100)]+  , iflavour = zipPlain [BrBlack]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "thud"+  , iweight  = 100000+  , iaspects = [ AddMaxHP 40, AddMaxCalm 70, AddSpeed 20+               , AddSight 3 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "Warrior of Chaos, ready to wreck havoc."+  , ikit     = [("fist", COrgan), ("foot", COrgan), ("eye 4", COrgan),+                ("starting weapon", CEqp)]+  }++chaosLord    = chaosWarrior+  { isymbol  = 'c'+  , iname    = "chaos lord"+  , ifreq    = [("chaos", 100)]+  , irarity  = [(5, 1), (10, 3)]+  , iflavour = zipPlain [BrRed]+  , iaspects = [ AddMaxHP 60, AddMaxCalm 70, AddSpeed 20+               , AddSight 3 ]+  , idesc    = "Lord of Chaos, leader of warriors"+  }++-- * Horrors (spawn)++warpBeast    = ItemKind+  { isymbol  = 'w'+  , iname    = "warp beast"+  , ifreq    = [("spawn", 100)]+  , iflavour = zipPlain [BrRed]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "thud"+  , iweight  = 40000+  , iaspects = [ AddMaxHP 20, AddMaxCalm 30, AddSpeed 20+               , AddSight 1 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = "Shambling beast of warp has phased into this corporeal realm."+  , ikit     = [("small claw", COrgan), ("foot", COrgan), ("eye 2", COrgan),+                ("nostril", COrgan)]+  }++-- * Animals++ventLizard = ItemKind+  { isymbol  = ':'+  , iname    = "vent lizard"+  , ifreq    = [("summonable animal", 100)]+  , iflavour = zipPlain [Green]+  , icount   = 1+  , irarity  = [(1, 5)]+  , iverbHit = "thud"+  , iweight  = 25000+  , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 18+               , AddSkills $ EM.singleton AbAlter (-1)+               , AddSight 3 ]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  , ikit     = [ ("claw", COrgan), ("snout", COrgan), ("armored skin", COrgan)+               , ("nostril", COrgan) ]+  }
+ GameDefinition/Content/ItemKindOrgan.hs view
@@ -0,0 +1,259 @@+-- | Organ definitions.+module Content.ItemKindOrgan ( organs ) where++import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Effect+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Msg+import Game.LambdaHack.Content.ItemKind++organs :: [ItemKind]+organs =+  [fist, foot, tentacle, lash, noseTip, lip, claw, smallClaw, snout, sting, venomTooth, venomFang, largeTail, jaw, largeJaw, tooth, pupil, armoredSkin, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, eye2, eye3, eye4, eye5, nostril, thorn, vent, fissure]++fist,    foot, tentacle, lash, noseTip, lip, claw, smallClaw, snout, sting, venomTooth, venomFang, largeTail, jaw, largeJaw, tooth, pupil, armoredSkin, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, eye2, eye3, eye4, eye5, nostril, thorn, vent, fissure :: ItemKind++-- * Parameterized organs++speedGland :: Int -> ItemKind+speedGland n = fist+  { iname    = "speed gland"+  , ifreq    = [("speed gland" <+> tshow n, 100)]+  , icount   = 1+  , iverbHit = "spit at"+  , iaspects = [AddSpeed $ intToDice n, Periodic $ intToDice n]+  , ieffects = [RefillHP 1]+  , ifeature = [Durable, Identified]+  , idesc    = ""+  }+speedGland2 = speedGland 2+speedGland4 = speedGland 4+speedGland6 = speedGland 6+speedGland8 = speedGland 8+speedGland10 = speedGland 10+eye :: Int -> ItemKind+eye n = fist+  { iname    = "eye"+  , ifreq    = [("eye" <+> tshow n, 100)]+  , icount   = 2+  , iverbHit = "glare at"+  , iaspects = [AddSight (intToDice n)]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  }+eye2 = eye 2+eye3 = eye 3+eye4 = eye 4+eye5 = eye 5++-- * Human weapon organs++fist = ItemKind+  { isymbol  = '%'+  , iname    = "fist"+  , ifreq    = [("fist", 100)]+  , iflavour = zipPlain [BrRed]+  , icount   = 2+  , irarity  = [(1, 1)]+  , iverbHit = "punch"+  , iweight  = 2000+  , iaspects = []+  , ieffects = [Hurt (d 2)]+  , ifeature = [Durable, EqpSlot EqpSlotWeapon "", Identified]+  , idesc    = ""+  , ikit     = []+  }+foot = fist+  { iname    = "foot"+  , ifreq    = [("foot", 50)]+  , icount   = 2+  , iverbHit = "kick"+  , ieffects = [Hurt (d 2)]+  , idesc    = ""+  }++-- * Universal weapon organs++claw = fist+  { iname    = "claw"+  , ifreq    = [("claw", 50)]+  , icount   = 2+  , iverbHit = "slash"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }+smallClaw = fist+  { iname    = "small claw"+  , ifreq    = [("small claw", 50)]+  , icount   = 2+  , iverbHit = "slash"+  , ieffects = [Hurt (d 2)]+  , idesc    = ""+  }+snout = fist+  { iname    = "snout"+  , ifreq    = [("snout", 10)]+  , iverbHit = "bite"+  , ieffects = [Hurt (d 2)]+  , idesc    = ""+  }+jaw = fist+  { iname    = "jaw"+  , ifreq    = [("jaw", 20)]+  , icount   = 1+  , iverbHit = "rip"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }+largeJaw = fist+  { iname    = "large jaw"+  , ifreq    = [("large jaw", 100)]+  , icount   = 1+  , iverbHit = "crush"+  , ieffects = [Hurt (d 6)]+  , idesc    = ""+  }+tooth = fist+  { iname    = "tooth"+  , ifreq    = [("tooth", 20)]+  , icount   = 3+  , iverbHit = "nail"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }++-- * Monster weapon organs++tentacle = fist+  { iname    = "tentacle"+  , ifreq    = [("tentacle", 50)]+  , icount   = 4+  , iverbHit = "slap"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }+lash = fist+  { iname    = "lash"+  , ifreq    = [("lash", 100)]+  , icount   = 1+  , iverbHit = "lash"+  , ieffects = [Hurt (d 6)]+  , idesc    = ""+  }+noseTip = fist+  { iname    = "tip"+  , ifreq    = [("nose tip", 50)]+  , icount   = 1+  , iverbHit = "poke"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }+lip = fist+  { iname    = "lip"+  , ifreq    = [("lip", 10)]+  , icount   = 2+  , iverbHit = "lap"+  , ieffects = [Hurt (d 2)]+  , idesc    = ""+  }++-- * Special weapon organs++thorn = fist+  { iname    = "thorn"+  , ifreq    = [("thorn", 100)]+  , icount   = 7+  , iverbHit = "impale"+  , ieffects = [Hurt (d 2)]+  , idesc    = ""+  }+fissure = fist+  { iname    = "fissure"+  , ifreq    = [("fissure", 100)]+  , icount   = 2+  , iverbHit = "hiss at"+  , ieffects = [Burn 1]+  , idesc    = ""+  }+sting = fist+  { iname    = "sting"+  , ifreq    = [("sting", 100)]+  , icount   = 1+  , iverbHit = "sting"+  , ieffects = [Burn 1, Paralyze 2]+  , idesc    = ""+  }+venomTooth = fist+  { iname    = "venom tooth"+  , ifreq    = [("venom tooth", 100)]+  , icount   = 2+  , iverbHit = "bite"+  , ieffects = [Hurt (d 2), Paralyze 3]+  , idesc    = ""+  }+venomFang = fist+  { iname    = "venom fang"+  , ifreq    = [("venom fang", 100)]+  , icount   = 2+  , iverbHit = "bite"+  , ieffects = [Hurt (d 4)]+  , idesc    = ""+  }+largeTail = fist+  { iname    = "large tail"+  , ifreq    = [("large tail", 50)]+  , icount   = 1+  , iverbHit = "knock"+  , ieffects = [Hurt (d 8), PushActor (ThrowMod 400 25)]+  , idesc    = ""+  }+pupil = fist+  { iname    = "pupil"+  , ifreq    = [("pupil", 100)]+  , icount   = 1+  , iverbHit = "gaze at"+  , iaspects = [AddSight 7]+  , ieffects = [Hurt (d 2), Paralyze 1]+  , idesc    = ""+  }++-- * Armor organs++armoredSkin = fist+  { iname    = "armored skin"+  , ifreq    = [("armored skin", 100)]+  , icount   = 1+  , iverbHit = "bash"+  , iaspects = [AddArmorMelee 33, AddArmorRanged 33]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  }++-- * Sense organs++nostril = fist+  { iname    = "nostril"+  , ifreq    = [("nostril", 100)]+  , icount   = 2+  , iverbHit = "snuff"+  , iaspects = [AddSmell 1]+  , ieffects = []+  , ifeature = [Durable, Identified]+  , idesc    = ""+  }++-- * Assorted++vent = fist+  { iname    = "vent"+  , ifreq    = [("vent", 100)]+  , icount   = 1+  , iverbHit = "menace"+  , iaspects = [Periodic $ 1 + d 2]+  , ieffects = [Explode "boiling water"]+  , ifeature = [Durable, Identified]+  , idesc    = ""+  }
+ GameDefinition/Content/ItemKindShrapnel.hs view
@@ -0,0 +1,239 @@+-- | Shrapnel definitions.+module Content.ItemKindShrapnel ( shrapnels ) where++import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.Dice+import Game.LambdaHack.Common.Effect+import Game.LambdaHack.Common.Flavour+import Game.LambdaHack.Common.Msg+import Game.LambdaHack.Content.ItemKind++shrapnels :: [ItemKind]+shrapnels =+  [fragrance, pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistWounding, distortion, waste, burningIgnisium2, burningIgnisium3, burningIgnisium4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue]++fragrance,    pheromone, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, mistHealing, mistWounding, distortion, waste, burningIgnisium2, burningIgnisium3, burningIgnisium4, explosionBlast10, explosionBlast20, glassPiece, smoke, boilingWater, glue :: ItemKind++-- * Parameterized shrapnel++burningIgnisium :: Int -> ItemKind+burningIgnisium n = ItemKind+  { isymbol  = '*'+  , iname    = "burning ignisium"+  , ifreq    = [("burning ignisium" <+> tshow n, 1)]+  , iflavour = zipFancy [BrYellow]+  , icount   = intToDice (n * 5)+  , irarity  = [(1, 1)]+  , iverbHit = "burn"+  , iweight  = 1+  , iaspects = [AddLight 3]+  , ieffects = [ Burn (n `div` 2)+               , Paralyze (intToDice $ n `div` 2) ]+  , ifeature = [ toVelocity (min 100 $ n * 7)+               , Fragile, Identified ]+  , idesc    = "Flaming ignisium, burning brightly."+  , ikit     = []+  }+burningIgnisium2 = burningIgnisium 2+burningIgnisium3 = burningIgnisium 3+burningIgnisium4 = burningIgnisium 4+explosionBlast :: Int -> ItemKind+explosionBlast n = ItemKind+  { isymbol  = '*'+  , iname    = "explosion blast"+  , ifreq    = [("explosion blast" <+> tshow n, 1)]+  , iflavour = zipPlain [BrRed]+  , icount   = 12  -- strong, but few, so not always hits target+  , irarity  = [(1, 1)]+  , iverbHit = "tear apart"+  , iweight  = 1+  , iaspects = [AddLight $ intToDice n]+  , ieffects = [RefillHP (- n `div` 2), DropBestWeapon]+  , ifeature = [Fragile, toLinger 10, Identified]+  , idesc    = ""+  , ikit     = []+  }+explosionBlast10 = explosionBlast 10+explosionBlast20 = explosionBlast 20+firecracker :: Int -> ItemKind+firecracker n = ItemKind+  { isymbol  = '*'+  , iname    = "firecracker"+  , ifreq    = [("firecracker" <+> tshow n, 1)]+  , iflavour = zipPlain [stdCol !! (n `mod` length stdCol)]+  , icount   = intToDice $ 2 * n+  , irarity  = [(1, 1)]+  , iverbHit = "crack"+  , iweight  = 1+  , iaspects = [AddLight $ intToDice $ n `div` 2]+  , ieffects = [Burn 1, Explode $ "firecracker" <+> tshow (n - 1)]+  , ifeature = [ ToThrow $ ThrowMod (n * 10) 20+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+firecracker7 = firecracker 7+firecracker6 = firecracker 6+firecracker5 = firecracker 5+firecracker4 = firecracker 4+firecracker3 = firecracker 3+firecracker2 = firecracker 2++-- * Assorted++fragrance = ItemKind+  { isymbol  = '\''+  , iname    = "fragrance"+  , ifreq    = [("fragrance", 1)]+  , iflavour = zipFancy [Magenta]+  , icount   = 15+  , irarity  = [(1, 1)]+  , iverbHit = "engulf"+  , iweight  = 1+  , iaspects = []+  , ieffects = [Impress]+  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+pheromone = ItemKind+  { isymbol  = '\''+  , iname    = "musky whiff"+  , ifreq    = [("pheromone", 1)]+  , iflavour = zipFancy [BrMagenta]+  , icount   = 8+  , irarity  = [(1, 1)]+  , iverbHit = "tempt"+  , iweight  = 1+  , iaspects = []+  , ieffects = [Dominate]+  , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+mistHealing = ItemKind+  { isymbol  = '\''+  , iname    = "mist"+  , ifreq    = [("healing mist", 1)]+  , iflavour = zipFancy [White]+  , icount   = 11+  , irarity  = [(1, 1)]+  , iverbHit = "revitalize"+  , iweight  = 1+  , iaspects = [AddLight 1]+  , ieffects = [RefillHP 2]+  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+mistWounding = ItemKind+  { isymbol  = '\''+  , iname    = "mist"+  , ifreq    = [("wounding mist", 1)]+  , iflavour = zipFancy [White]+  , icount   = 13+  , irarity  = [(1, 1)]+  , iverbHit = "devitalize"+  , iweight  = 1+  , iaspects = []+  , ieffects = [RefillHP (-2)]+  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+distortion = ItemKind+  { isymbol  = 'v'+  , iname    = "vortex"+  , ifreq    = [("distortion", 1)]+  , iflavour = zipFancy [White]+  , icount   = 4+  , irarity  = [(1, 1)]+  , iverbHit = "engulf"+  , iweight  = 1+  , iaspects = []+  , ieffects = [Teleport $ 15 + d 10]+  , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+waste = ItemKind+  { isymbol  = '*'+  , iname    = "waste"+  , ifreq    = [("waste", 1)]+  , iflavour = zipPlain [Brown]+  , icount   = 10+  , irarity  = [(1, 1)]+  , iverbHit = "splosh"+  , iweight  = 50+  , iaspects = []+  , ieffects = [RefillHP (-1)]+  , ifeature = [ ToThrow $ ThrowMod 28 50+               , Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+glassPiece = ItemKind  -- when blowing up windows+  { isymbol  = '*'+  , iname    = "glass piece"+  , ifreq    = [("glass piece", 1)]+  , iflavour = zipPlain [BrBlue]+  , icount   = 17+  , irarity  = [(1, 1)]+  , iverbHit = "cut"+  , iweight  = 10+  , iaspects = []+  , ieffects = [Hurt (1 * d 1)]+  , ifeature = [toLinger 20, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }+smoke = ItemKind  -- when stuff burns out+  { isymbol  = '\''+  , iname    = "smoke"+  , ifreq    = [("smoke", 1), ("firecracker 1", 1)]+  , iflavour = zipPlain [BrBlack]+  , icount   = 19+  , irarity  = [(1, 1)]+  , iverbHit = "choke"+  , iweight  = 1+  , iaspects = []+  , ieffects = []+  , ifeature = [ toVelocity 21, Fragile, Identified ]+  , idesc    = ""+  , ikit     = []+  }+boilingWater = ItemKind+  { isymbol  = '*'+  , iname    = "boiling water"+  , ifreq    = [("boiling water", 1)]+  , iflavour = zipPlain [BrWhite]+  , icount   = 9+  , irarity  = [(1, 1)]+  , iverbHit = "boil"+  , iweight  = 5+  , iaspects = []+  , ieffects = [Burn 1]+  , ifeature = [toVelocity 50, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }+glue = ItemKind+  { isymbol  = '*'+  , iname    = "hoof glue"+  , ifreq    = [("glue", 1)]+  , iflavour = zipPlain [BrYellow]+  , icount   = 14+  , irarity  = [(1, 1)]+  , iverbHit = "glue"+  , iweight  = 20+  , iaspects = []+  , ieffects = [Paralyze (3 + d 3)]+  , ifeature = [toVelocity 40, Fragile, Identified]+  , idesc    = ""+  , ikit     = []+  }
+ GameDefinition/Content/ModeKind.hs view
@@ -0,0 +1,113 @@+-- | The type of kinds of game modes for Space Privateers.+module Content.ModeKind ( cdefs ) where++import qualified Data.IntMap.Strict as IM++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]+  }+campaign :: ModeKind++campaign = ModeKind+  { msymbol  = 'a'+  , mname    = "campaign"+  , mfreq    = [("campaign", 1)]+  , mplayers = playersCampaign+  , mcaves   = cavesCampaign+  , mdesc    = "Get ready to assault the city vessel and plunder some loot!"+  }++playersCampaign :: Players++playersCampaign = Players+  { playersList = [ playerHero+                  , playerMerchant+                  , playerChaos+                  , playerHorror+                  , playerSpawn ]+  , playersEnemy = [ ("Space Privateers", "Merchant Mariners")+                   , ("Space Privateers", "Forces of Chaos") +                   , ("Space Privateers", "Spawns of Warp")+                   , ("Merchant Mariners", "Forces of Chaos") +                   , ("Merchant Mariners", "Spawns of Warp") ]+  , playersAlly = [("Forces of Chaos", "Spawns of Warp")] }++playerHero, playerMerchant, playerChaos, playerSpawn, playerHorror :: Player++playerHero = Player+  { playerName = "Space Privateers"+  , playerFaction = "hero"+  , playerIsSpawn = False+  , playerIsHero = True+  , playerEntry = -1+  , playerInitial = 3+  , playerLeader = True+  , playerAI = False+  , playerUI = True+  }++playerMerchant = Player+  { playerName = "Merchant Mariners"+  , playerFaction = "merchant"+  , playerIsSpawn = True+  , playerIsHero = False+  , playerEntry = -1+  , playerInitial = 3+  , playerLeader = False+  , playerAI = True+  , playerUI = False+  }++playerChaos = Player+  { playerName = "Forces of Chaos"+  , playerFaction = "chaos"+  , playerIsSpawn = True+  , playerIsHero = False+  , playerEntry = -1+  , playerInitial = 5+  , playerLeader = False+  , playerAI = True+  , playerUI = False+  }++playerHorror = Player+  { playerName = "Horrors of Warp"+  , playerFaction = "horror"+  , playerIsSpawn = True+  , playerIsHero = False+  , playerEntry = -1+  , playerInitial = 0+  , playerLeader = False+  , playerAI = True+  , playerUI = False+  }++playerSpawn = Player+  { playerName = "Spawns of Warp"+  , playerFaction = "spawn"+  , playerIsSpawn = True+  , playerIsHero = False+  , playerEntry = -1+  , playerInitial = 0+  , playerLeader = False+  , playerAI = True+  , playerUI = False+  }++cavesCampaign :: Caves++cavesCampaign = IM.fromList $ [ (-1, ("caveRogue", Just True))+                              , (-2, ("caveRogue", Nothing))+                              , (-3, ("caveRogue", Nothing)) ]+                              ++ zip [-4, -5..(-9)] (repeat ("dng", Nothing))+                              ++ [(-10, ("caveRogue", Nothing))]+
+ GameDefinition/Content/PlaceKind.hs view
@@ -0,0 +1,185 @@+-- | Rooms, halls and passages for Space Privateers.+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, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillarC, pillar3, colonnade, colonnade2, colonnade3, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3]+  }+rect,        ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillarC, pillar3, colonnade, colonnade2, colonnade3, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3 :: PlaceKind++rect = PlaceKind  -- Valid for any nonempty area, hence low frequency.+  { psymbol  = 'r'+  , pname    = "room"+  , pfreq    = [("rogue", 100), ("ambush", 8)]+  , prarity  = [(1, 1)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "--"+               , "|."+               ]+  , poverride = []+  }+ruin = PlaceKind+  { psymbol  = 'R'+  , pname    = "ruin"+  , pfreq    = [("ambush", 17), ("battle", 100)]+  , prarity  = [(1, 1)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "--"+               , "|X"+               ]+  , poverride = []+  }+collapsed = PlaceKind+  { psymbol  = 'c'+  , pname    = "collapsed cavern"+  , pfreq    = [("noise", 1)]+  , prarity  = [(1, 1)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "O"+               ]+  , poverride = []+  }+collapsed2 = collapsed+  { pfreq    = [("noise", 100), ("battle", 50)]+  , ptopLeft = [ "XXO"+               , "XOO"+               ]+  }+collapsed3 = collapsed+  { pfreq    = [("noise", 200), ("battle", 50)]+  , ptopLeft = [ "XXXO"+               , "XOOO"+               ]+  }+collapsed4 = collapsed+  { pfreq    = [("noise", 400), ("battle", 200)]+  , ptopLeft = [ "XXXO"+               , "XXXO"+               , "XOOO"+               ]+  }+pillar = PlaceKind+  { psymbol  = 'p'+  , pname    = "pillar room"+  , pfreq    = [("rogue", 1000)]  -- larger rooms require support pillars+  , prarity  = [(1, 1)]+  , pcover   = CStretch+  , pfence   = FNone+  , ptopLeft = [ "-----"+               , "|...."+               , "|.O.."+               , "|...."+               , "|...."+               ]+  , poverride = []+  }+pillarC = pillar+  { ptopLeft = [ "-----"+               , "|O..."+               , "|...."+               , "|...."+               , "|...."+               ]+  }+pillar3 = pillar+  { ptopLeft = [ "-----"+               , "|&.O."+               , "|...."+               , "|O..."+               , "|...."+               ]+  }+colonnade = PlaceKind+  { psymbol  = 'c'+  , pname    = "colonnade"+  , pfreq    = [("rogue", 60)]+  , prarity  = [(1, 1)]+  , pcover   = CAlternate+  , pfence   = FFloor+  , ptopLeft = [ "O."+               , ".O"+               ]+  , poverride = []+  }+colonnade2 = colonnade+  { ptopLeft = [ "O."+               , ".."+               ]+  }+colonnade3 = colonnade+  { pfreq    = [("rogue", 6)]+  , ptopLeft = [ ".."+               , ".O"+               ]+  }+lampPost = PlaceKind+  { psymbol  = 'l'+  , pname    = "lamp post"+  , pfreq    = [("ambush", 30), ("battle", 10)]+  , prarity  = [(1, 1)]+  , pcover   = CVerbatim+  , pfence   = FNone+  , ptopLeft = [ "X.X"+               , ".O."+               , "X.X"+               ]+  , poverride = [('O', "lampPostOver_O")]+  }+lampPost2 = lampPost+  { ptopLeft = [ "..."+               , ".O."+               , "..."+               ]+  }+lampPost3 = lampPost+  { ptopLeft = [ "XX.XX"+               , "X...X"+               , "..O.."+               , "X...X"+               , "XX.XX"+               ]+  }+lampPost4 = lampPost+  { ptopLeft = [ "X...X"+               , "....."+               , "..O.."+               , "....."+               , "X...X"+               ]+  }+treeShade = PlaceKind+  { psymbol  = 't'+  , pname    = "tree shade"+  , pfreq    = [("skirmish", 100)]+  , prarity  = [(1, 1)]+  , pcover   = CVerbatim+  , pfence   = FNone+  , ptopLeft = [ "sss"+               , "XOs"+               , "XXs"+               ]+  , poverride = [('O', "treeShadeOver_O"), ('s', "treeShadeOver_s")]+  }+treeShade2 = treeShade+  { ptopLeft = [ "sss"+               , "XOs"+               , "Xss"+               ]+  }+treeShade3 = treeShade+  { ptopLeft = [ "sss"+               , "sOs"+               , "XXs"+               ]+  }
+ GameDefinition/Content/RuleKind.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE TemplateHaskell #-}+-- | Game rules and assorted game setup data for Space Privateer.+module Content.RuleKind ( cdefs ) where++import Language.Haskell.TH.Syntax+import System.FilePath++-- Cabal+import qualified Paths_SpacePrivateers as Self (getDataFileName, version)++import Game.LambdaHack.Common.ContentDef+import Game.LambdaHack.Common.Vector+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 Space Privateers ruleset"+  , rfreq          = [("standard", 100)]+  , raccessible    = Nothing+  , raccessibleDoor =+      Just $ \spos tpos -> not $ isDiagonal $ spos `vectorToFrom` tpos+  , rtitle         = "Space Privateers"+  , rpathsDataFile = Self.getDataFileName+  , rpathsVersion  = Self.version+  , rcfgUIName = "config.ui"+  , rcfgUIDefault = $(do+      let path = "GameDefinition" </> "config.ui" <.> "default"+      qAddDependentFile path+      x <- qRunIO (readFile path)+      lift x)+  , rmainMenuArt = $(do+      let path = "GameDefinition/MainMenu.ascii"+      qAddDependentFile path+      x <- qRunIO (readFile path)+      lift x)+  , rfirstDeathEnds = False+  , rfovMode = Digital+  , rsaveBkpClips = 500+  , rleadLevelClips = 100+  , rscoresFile = "scores"+  , rsavePrefix = "save"+  , rsharedStash = True+  }
+ GameDefinition/Content/TileKind.hs view
@@ -0,0 +1,307 @@+-- | Terrain tiles for Space Privateers+module Content.TileKind ( cdefs ) where++import Control.Arrow (first)+import Data.Maybe+import Data.Text (Text)+import qualified Data.Text as T++import Game.LambdaHack.Common.Color+import Game.LambdaHack.Common.ContentDef+import qualified Game.LambdaHack.Common.Effect as Effect+import Game.LambdaHack.Common.Feature+import Game.LambdaHack.Common.Msg+import Game.LambdaHack.Content.TileKind++cdefs :: ContentDef TileKind+cdefs = ContentDef+  { getSymbol = tsymbol+  , getName = tname+  , getFreq = tfreq+  , validate = validateTileKind+  , content =+      [wall, hardRock, pillar, pillarCache, lampPost, burningBush, bush, tree, wallV, wallSuspectV, doorClosedV, doorOpenV, wallH, wallSuspectH, doorClosedH, doorOpenH, stairsUpLit, stairsLit, stairsDownLit, escapeUpLit, escapeDownLit, unknown, floorCorridorLit, floorArenaLit, floorArenaShade, floorActorLit, floorItemLit, floorActorItemLit, floorRedLit, floorBlueLit, floorGreenLit, floorBrownLit]+      ++ map makeDark [wallV, wallSuspectV, doorClosedV, doorOpenV, wallH, wallSuspectH, doorClosedH, doorOpenH, stairsLit, escapeUpLit, escapeDownLit, floorCorridorLit]+      ++ map makeDarkColor [stairsUpLit, stairsDownLit, floorArenaLit, floorActorLit, floorItemLit, floorActorItemLit]+  }+wall,        hardRock, pillar, pillarCache, lampPost, burningBush, bush, tree, wallV, wallSuspectV, doorClosedV, doorOpenV, wallH, wallSuspectH, doorClosedH, doorOpenH, stairsUpLit, stairsLit, stairsDownLit, escapeUpLit, escapeDownLit, unknown, floorCorridorLit, floorArenaLit, floorArenaShade, floorActorLit, floorItemLit, floorActorItemLit, floorRedLit, floorBlueLit, floorGreenLit, floorBrownLit :: TileKind++wall = TileKind+  { tsymbol  = ' '+  , tname    = "bedrock"+  , tfreq    = [("fillerWall", 1), ("legendLit", 100), ("legendDark", 100)]+  , tcolor   = defBG+  , tcolor2  = defBG+  , tfeature = [Dark]+      -- Bedrock being dark is bad for AI (forces it to backtrack to explore+      -- bedrock at corridor turns) and induces human micromanagement+      -- if there can be corridors joined diagonally (humans have to check+      -- with the cursor if the dark space is bedrock or unexplored).+      -- Lit bedrock would be even worse for humans, because it's harder+      -- to guess which tiles are unknown and which can be explored bedrock.+      -- The setup of Allure is ideal, with lit bedrock that is easily+      -- distinguished from an unknown tile. However, LH follows the NetHack,+      -- not the Angband, visual tradition, so we can't improve the situation,+      -- unless we turn to subtle shades of black or non-ASCII glyphs,+      -- but that is yet different aesthetics and it's inconsistent+      -- with console frontends.+  }+hardRock = TileKind+  { tsymbol  = ' '+  , tname    = "impenetrable bedrock"+  , tfreq    = [("basic outer fence", 1)]+  , tcolor   = BrWhite+  , tcolor2  = BrWhite+  , tfeature = [Dark, Impenetrable]+  }+pillar = TileKind+  { tsymbol  = 'O'+  , tname    = "rock"+  , tfreq    = [ ("cachable", 70)+               , ("legendLit", 100), ("legendDark", 100)+               , ("noiseSet", 100), ("skirmishSet", 5)+               , ("battleSet", 250) ]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = []+  }+pillarCache = TileKind+  { tsymbol  = '&'+  , tname    = "cache"+  , tfreq    = [ ("cachable", 30)+               , ("legendLit", 100), ("legendDark", 100) ]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Cause $ Effect.CreateItem 1, ChangeTo "cachable"]+  }+lampPost = TileKind+  { tsymbol  = 'O'+  , tname    = "lamp post"+  , tfreq    = [("lampPostOver_O", 90)]+  , tcolor   = BrYellow+  , tcolor2  = Brown+  , tfeature = []+  }+burningBush = TileKind+  { tsymbol  = 'O'+  , tname    = "burning bush"+  , tfreq    = [("lampPostOver_O", 10), ("ambushSet", 3), ("battleSet", 2)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , tfeature = []+  }+bush = TileKind+  { tsymbol  = 'O'+  , tname    = "bush"+  , tfreq    = [("ambushSet", 100) ]+  , tcolor   = Green+  , tcolor2  = BrBlack+  , tfeature = [Dark]+  }+tree = TileKind+  { tsymbol  = 'O'+  , tname    = "tree"+  , tfreq    = [("skirmishSet", 14), ("battleSet", 20), ("treeShadeOver_O", 1)]+  , tcolor   = BrGreen+  , tcolor2  = Green+  , tfeature = []+  }+wallV = TileKind+  { tsymbol  = '|'+  , tname    = "granite wall"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [HideAs "suspect vertical wall Lit"]+  }+wallSuspectV = TileKind+  { tsymbol  = '|'+  , tname    = "moldy wall"+  , tfreq    = [("suspect vertical wall Lit", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Suspect, RevealAs "vertical closed door Lit"]+  }+doorClosedV = TileKind+  { tsymbol  = '+'+  , tname    = "closed door"+  , tfreq    = [("vertical closed door Lit", 1)]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , tfeature = [ OpenTo "vertical open door Lit"+               , HideAs "suspect vertical wall Lit"+               ]+  }+doorOpenV = TileKind+  { tsymbol  = '-'+  , tname    = "open door"+  , tfreq    = [("vertical open door Lit", 1)]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , tfeature = [ Walkable, Clear, NoItem, NoActor+               , CloseTo "vertical closed door Lit"+               ]+  }+wallH = TileKind+  { tsymbol  = '-'+  , tname    = "granite wall"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [HideAs "suspect horizontal wall Lit"]+  }+wallSuspectH = TileKind+  { tsymbol  = '-'+  , tname    = "scratched wall"+  , tfreq    = [("suspect horizontal wall Lit", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Suspect, RevealAs "horizontal closed door Lit"]+  }+doorClosedH = TileKind+  { tsymbol  = '+'+  , tname    = "closed door"+  , tfreq    = [("horizontal closed door Lit", 1)]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , tfeature = [ OpenTo "horizontal open door Lit"+               , HideAs "suspect horizontal wall Lit"+               ]+  }+doorOpenH = TileKind+  { tsymbol  = '|'+  , tname    = "open door"+  , tfreq    = [("horizontal open door Lit", 1)]+  , tcolor   = Brown+  , tcolor2  = BrBlack+  , tfeature = [ Walkable, Clear, NoItem, NoActor+               , CloseTo "horizontal closed door Lit"+               ]+  }+stairsUpLit = TileKind+  { tsymbol  = '<'+  , tname    = "staircase up"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ Effect.Ascend 1]+  }+stairsLit = TileKind+  { tsymbol  = '>'+  , tname    = "staircase"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrCyan+  , tcolor2  = Cyan  -- TODO+  , tfeature = [ Walkable, Clear, NoItem, NoActor+               , Cause $ Effect.Ascend 1+               , Cause $ Effect.Ascend (-1) ]+  }+stairsDownLit = TileKind+  { tsymbol  = '>'+  , tname    = "staircase down"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ Effect.Ascend (-1)]+  }+escapeUpLit = TileKind+  { tsymbol  = '<'+  , tname    = "exit trapdoor up"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrYellow+  , tcolor2  = BrYellow+  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ Effect.Escape 1]+  }+escapeDownLit = TileKind+  { tsymbol  = '>'+  , tname    = "exit trapdoor down"+  , tfreq    = [("legendLit", 100)]+  , tcolor   = BrYellow+  , tcolor2  = BrYellow+  , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ Effect.Escape (-1)]+  }+unknown = TileKind+  { tsymbol  = ' '+  , tname    = "unknown space"+  , tfreq    = [("unknown space", 1)]+  , tcolor   = defFG+  , tcolor2  = defFG+  , tfeature = [Dark]+  }+floorCorridorLit = TileKind+  { tsymbol  = '#'+  , tname    = "corridor"+  , tfreq    = [("floorCorridorLit", 1)]+  , tcolor   = BrWhite+  , tcolor2  = defFG+  , tfeature = [Walkable, Clear]+  }+floorArenaLit = floorCorridorLit+  { tsymbol  = '.'+  , tname    = "stone floor"+  , tfreq    = [ ("floorArenaLit", 1)+               , ("arenaSet", 1), ("emptySet", 1), ("noiseSet", 50)+               , ("battleSet", 1000), ("skirmishSet", 100)+               , ("ambushSet", 1000) ]+  }+floorActorLit = floorArenaLit+  { tfreq    = []+  , tfeature = OftenActor : tfeature floorArenaLit+  }+floorItemLit = floorArenaLit+  { tfreq    = []+  , tfeature = OftenItem : tfeature floorArenaLit+  }+floorActorItemLit = floorItemLit+  { tfreq    = [("legendLit", 100)]  -- no OftenItem in legendDark+  , tfeature = OftenActor : tfeature floorItemLit+  }+floorArenaShade = floorActorLit+  { tname    = "stone floor"  -- TODO: "shaded ground"+  , tfreq    = [("treeShadeOver_s", 1)]+  , tcolor2  = BrBlack+  , tfeature = Dark : tfeature floorActorLit  -- no OftenItem+  }+floorRedLit = floorArenaLit+  { tname    = "brick pavement"+  , tfreq    = [("trailLit", 30)]+  , tcolor   = BrRed+  , tcolor2  = Red+  , tfeature = Trail : tfeature floorArenaLit+  }+floorBlueLit = floorRedLit+  { tname    = "granite cobblestones"+  , tfreq    = [("trailLit", 100)]+  , tcolor   = BrBlue+  , tcolor2  = Blue+  }+floorGreenLit = floorRedLit+  { tname    = "mossy stone path"+  , tfreq    = [("trailLit", 100)]+  , tcolor   = BrGreen+  , tcolor2  = Green+  }+floorBrownLit = floorRedLit+  { tname    = "rotting mahogany deck"+  , tfreq    = [("trailLit", 10)]+  , tcolor   = BrMagenta+  , tcolor2  = Magenta+  }++makeDark :: TileKind -> TileKind+makeDark k = let darkText :: Text -> Text+                 darkText t = maybe t (<> "Dark") $ T.stripSuffix "Lit" t+                 darkFrequency = map (first darkText) $ tfreq k+                 darkFeat (OpenTo t) = Just $ OpenTo $ darkText t+                 darkFeat (CloseTo t) = Just $ CloseTo $ darkText t+                 darkFeat (ChangeTo t) = Just $ ChangeTo $ darkText t+                 darkFeat (HideAs t) = Just $ HideAs $ darkText t+                 darkFeat (RevealAs t) = Just $ RevealAs $ darkText t+                 darkFeat OftenItem = Nothing+                 darkFeat feat = Just $ feat+             in k { tfreq    = darkFrequency+                  , tfeature = Dark : mapMaybe darkFeat (tfeature k)+                  }++makeDarkColor :: TileKind -> TileKind+makeDarkColor k = (makeDark k) {tcolor2 = BrBlack}
+ GameDefinition/Main.hs view
@@ -0,0 +1,13 @@+-- | The main source code file of Space Privateers the game.+module Main ( main ) where++import System.Environment (getArgs)++import TieKnot++-- | Tie the LambdaHack engine client, server and frontend code+-- with the game-specific content definitions, and run the game.+main :: IO ()+main = do+  args <- getArgs+  tieKnot args
+ GameDefinition/MainMenu.ascii view
@@ -0,0 +1,26 @@+----------------------------------------------------------------------------------+|                                                                                |+|                                                                                |+|                                                                                |+|                                                                                |+|                                                                                |+|                         >> Space Privateers <<                                 |+|                                                                                |+|                                                                                |+|                         {{{{{{{{{{{{{{{{{{{{{{{{{                              |+|                                                                                |+|                         {{{{{{{{{{{{{{{{{{{{{{{{{                              |+|                                                                                |+|                         {{{{{{{{{{{{{{{{{{{{{{{{{                              |+|                                                                                |+|                         {{{{{{{{{{{{{{{{{{{{{{{{{                              |+|                                                                                |+|                         {{{{{{{{{{{{{{{{{{{{{{{{{                              |+|                                                                                |+|                                                                                |+|                                                                                |+|                                                                                |+|                                                                                |+|                                                                                |+|                        Version X.X.X (frontend: gtk, engine: LambdaHack X.X.X) |+----------------------------------------------------------------------------------
+ GameDefinition/PLAYING.md view
@@ -0,0 +1,242 @@+Playing Space Privateers+========================++Space Privateers is a dungeon crawler set in space. Playing the game involves+exploring corridors of a city vessel and plundering as much loot as possible.++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+for this rudimentary game, but it's playable and winnable.+Contributions are welcome.++Space Privateers uses LambdaHack engine and lot of content in the game is+derived from it.++Heroes+------++The heroes are marked on the map with symbols `@` and `1` through `9`.+Their goal is to explore the city vessel, battle the horrors within,+gather as much gold and gems as possible, and escape to tell the tale.++The currently chosen party leader is highlighted on the screen+and his attributes are displayed at the bottommost status line,+which in its most complex form may look as follows.++    *@12 Captain     4d1+5% Calm: 20/60 HP: 33/50 Target: merchant  [**___]++The line starts with the list of party members (unless only one member+resides on the currently displayed level) and the shortened name of the team.+Then comes the damage of the leader's weapon (but regardless of the figures,+each attack inflicts at least 1 damage), then his current and maximum+Calm (composure, focus, attentiveness), then his current and maximum+HP (hit points, health). At the end, the personal target of the leader+is described, in this case a merchant mariner, with hit points drawn as a bar.++The other status line describes the current location in relation to the party.++    5  Lofty hall   [33% seen] Cursor: exact spot (71,12)  p15 l10++First comes the depth of the current level and its name.+Then the percentage of its explorable tiles already seen by the heroes.+The 'cursor' is the common target of the whole party,+directly manipulated with movement keys in the targeting mode.+At the end comes the length of the shortest path from the leader+to the cursor position and the straight-line distance between the two points.+++City vessel+-----------++The city vessel consists of 10 levels and each level consists of a large number+of tiles. The basic tile kinds are as follows.++               terrain type                       on-screen symbol+               ground                             .+               corridor                           #+               wall (horizontal and vertical)     - and |+               rock or tree                       O+               cache                              &+               stairs up                          <+               stairs down                        >+               open door                          | and -+               closed door                        ++               vessel hull                        blank++The game world is persistent, i.e., every time the player visits a level+during a single game, its layout is the same.+++Commands+--------++You move throughout the level using the numerical keypad (left diagram)+or its compact laptop replacement (middle) or Vi text editor keys+(right, also known as "Rogue-like keys", which have to be enabled+in config.ui.ini).++                7 8 9          7 8 9          y k u+                 \|/            \|/            \|/+                4-5-6          u-i-o          h-.-l+                 /|\            /|\            /|\+                1 2 3          j k l          b j n++In targeting mode the keys above move the targeting cursor. In normal mode,+`SHIFT` (or `CTRL`) and a movement key make the current party leader+(and currently selected party members, if any) run in the indicated+direction, until anything of interest is spotted.+The '5', 'i' and '.' keys consume a turn and make you brace for combat,+which reduces any damage taken for a turn and makes it impossible+for foes to displace you. You displace enemies or friends by bumping+into them with SHIFT (or CTRL).++Melee, searching for secret doors, looting and opening closed doors+can be done by bumping into a monster, a wall and a door, respectively.+Few commands other than movement, 'g'etting an item from the floor,+'a'pplying an item and 'f'linging an item are necessary for casual play.+Some are provided only as specialized versions of more general commands+or as building blocks for more complex convenience commands,+e.g., the autoexplore command (key `X`) could be defined+by the player as a macro using `BACKSPACE`, `CTRL-?`, `;` and `V`.++Below are the remaining keys for terrain exploration and alteration.++                keys           command+                <              ascend a level+                CTRL-<         ascend 10 levels+                >              descend a level+                CTRL->         descend 10 levels+                ;              make one step towards the target+                :              go to target for 100 steps+                CTRL-:         go to target for 10 steps+                x              explore the closest unknown spot+                X              autoexplore 100 times+                CTRL-X         autoexplore 10 times+                R              rest (wait 100 times)+                CTRL-R         rest (wait 10 times)+                c              close door++Item-use related keys are as follows.++                keys           command+                E              describe equipment of the leader+                P              describe backpack inventory of the leader+                S              describe the shared party stash+                G              describe items on the ground+                A              describe all owned items+                g and ,        get an item+                d              drop an item+                e              equip an item+                p              pack an item into inventory backpack+                s              stash and share an item+                a              activate applicable item+                q              quaff potion+                r              read scroll+                f              fling projectable item+                t              throw missile+                z              zap wand++To make a ranged attack, as in the last few commands above,+you need to set your target first (however, initial target is set+automatically as soon as a monster comes into view). Once in targeting mode,+you can move the targeting cursor with arrow keys and switch focus+among enemies with `*` (or among friends, projectiles and enemies, depending+on targeting mode 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+                KEYPAD_* and \ target enemy+                /              cycle targeting mode+                +              swerve targeting line+                -              unswerve targeting line+                BACKSPACE      clear target/cursor+                CTRL-?         target the closest unknown spot+                CTRL-I         target the closest item+                CTRL-{         target the closest stairs up+                CTRL-}         target the closest stairs down++Here are the commands for automating the actions of one or more members+of the team.++                keys           command+                =              select (or deselect) a party member+                _              deselect (or select) all on the level+                v              voice again the recorded commands+                V              voice the recorded commands 100 times+                CTRL-v         voice the recorded commands 1000 times+                CTRL-V         voice the recorded commands 10 times+                '              start recording commands+                CTRL-A         automate faction (ESC to retake control)++Assorted remaining keys and commands follow.++                keys           command+                ?              display help+                D              display player diary+                T              mark suspect terrain+                Z              mark visible zone+                C              mark smell clues+                TAB            cycle among party members on the level+                SHIFT-TAB      cycle among all party members+                SPACE          clear messages+                ESC            cancel action, open Main Menu+                RET            accept choice+                0--6           pick a new hero leader anywhere in the 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.+Game difficulty setting affects hitpoints at birth for any actors+of any UI-using faction. For a person new to roguelikes, the Duel game mode+offers a gentle introduction. The subsequent game modes gradually introduce+squad combat, stealth, asymmetric battles and more game elements.++                keys           command+                CTRL-x         save and exit+                CTRL-u         new Duel game+                CTRL-k         new Skirmish game+                CTRL-m         new Ambush game+                CTRL-b         new Battle game+                CTRL-a         new Campaign game+                CTRL-d         cycle next game difficulty++Monsters+--------++Heroes are not alone in the city vessel. Monstrosities, natural+and out of this world, roam the dark caves and crawl from damp holes+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 equipped weapon or the best fighting organ+of each opponent is taken into account for calculating damage.+The damage the current hero can potentially inflict is displayed+at the bottom of the screen, but the actual damage depends also+on the monster's armor. Heroes and monsters running into one another+(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.++Slinging a missile at a target wounds it, consuming the weapon in the process.+You may propel any item in your equipment, inventory and on the ground+(press `?` to choose an item and press it again for a non-standard choice).+Only items of a few kinds inflict any damage, but some have other effects.+Whenever the monster's or hero's hit points reach zero, the combatant dies.+When the last hero dies, the game ends in defeat.+++On Winning and Dying+--------------------++You win the game if you escape the city vessel alive. Your score is based on the+gold and precious gems you've plundered, plus a bonus based on the number of+heroes you lost.++If all your heroes fall, you are awarded a score for your valiant deeds,+but no winning bonus. When, invariably, a new overconfident party+of adventurers storms the dungeon, they start from a new entrance,+with no experience and no equipment, and new, undaunted enemies+bar their way.
+ GameDefinition/TieKnot.hs view
@@ -0,0 +1,38 @@+-- | Here the knot of engine code pieces and the game-specific+-- content definitions is tied, resulting in an executable game.+module TieKnot ( tieKnot ) where++import qualified Client.UI.Content.KeyKind as Content.KeyKind+import qualified Content.CaveKind+import qualified Content.FactionKind+import qualified Content.ItemKind+import qualified Content.ModeKind+import qualified Content.PlaceKind+import qualified Content.RuleKind+import qualified Content.TileKind+import Game.LambdaHack.Client (exeFrontend)+import qualified Game.LambdaHack.Common.Kind as Kind+import Game.LambdaHack.SampleImplementation.SampleMonadClient (executorCli)+import Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer)+import Game.LambdaHack.Server (mainSer)++-- | Tie the LambdaHack engine client, server and frontend code+-- with the game-specific content definitions, and run the game.+tieKnot :: [String] -> IO ()+tieKnot args =+  let -- Common content operations, created from content definitions.+      copsServer = Kind.COps+        { cocave    = Kind.createOps Content.CaveKind.cdefs+        , cofaction = Kind.createOps Content.FactionKind.cdefs+        , coitem    = Kind.createOps Content.ItemKind.cdefs+        , comode    = Kind.createOps Content.ModeKind.cdefs+        , coplace   = Kind.createOps Content.PlaceKind.cdefs+        , corule    = Kind.createOps Content.RuleKind.cdefs+        , cotile    = Kind.createOps Content.TileKind.cdefs+        }+      -- Client content operations.+      copsClient = Content.KeyKind.standardKeys+      -- A single frontend is currently started by the server,+      -- instead of each client starting it's own.+      startupFrontend = exeFrontend executorCli executorCli copsClient+  in mainSer args copsServer executorSer startupFrontend
+ GameDefinition/config.ui.default view
@@ -0,0 +1,28 @@+; ; 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+; ; ~/.SpacePrivateers/config.ui.ini (or a similar path, depending on the OS).+; ; Warning: options are case-sensitive and only ';' for comments is permitted.++; [extra_commands]+; ; A handy shorthand with Vi keys:+; Macro_1 = ("comma", ([CmdItem], Macro "" ["g"]))++; [hero_names]+; HeroName_0 = ("Regulus Secundinus", "he")+; HeroName_1 = ("Sabina Petronia", "she")+; HeroName_2 = ("Titus Severus", "he")+; HeroName_3 = ("Blandina Domitius", "she")+; HeroName_4 = ("Lucretius Caelius", "he")+; HeroName_5 = ("Tacita Aurelia", "she")+; HeroName_6 = ("Vitus Antoninus", "he")++; [ui]+; movementViKeys_hjklyubn = False+; movementLaptopKeys_uk8o79jl = True+; font = "Terminus,Monospace normal normal normal normal 12"+; historyMax = 5000+; maxFps = 15+; noAnim = False+; runStopMsgs = False+[dummy]
+ GameDefinition/scores view

binary file changed (absent → 701 bytes)

+ LICENSE view
@@ -0,0 +1,32 @@+Copyright (c) 2008--2014 Andres Loeh+Copyright (c) 2010--2014 Mikolaj Konarski+Copyright (c) 2014, Tuukka Turto++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Tuukka Turto nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+Space Privateers is a adventure game set in far future. Player plays a space+privateer who has recently docked with a merchant city vessel and plans to+plunder some of the loot before escaping. The task will not be easy and there+are many dangers awaiting in the deep corridors and rooms of the city vessel.++Space Privateers uses [LambdaHack] [1] engine.++[1]: https://github.com/LambdaHack/LambdaHack/
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ SpacePrivateers.cabal view
@@ -0,0 +1,56 @@+name:                 SpacePrivateers+version:              0.1.0.0+synopsis:             Simple space pirate roguelike+description:          Space Privateers is a roguelike game set in space.+homepage:             https://github.com/tuturto/space-privateers+license:              BSD3+license-file:         LICENSE+author:               Tuukka Turto+maintainer:           tuukka.turto@oktaeder.net+category:             Game+build-type:           Simple+data-files:           GameDefinition/config.ui.default,+                      GameDefinition/scores+extra-source-files:   GameDefinition/PLAYING.md, GameDefinition/MainMenu.ascii,+                      README.md, LICENSE, CREDITS, changelog+cabal-version:        >= 1.10+source-repository head+  type:               git+  location:           git://github.com/tuturto/space-privateers.git++executable SpacePrivateers+  hs-source-dirs:     GameDefinition+  main-is:            Main.hs+  other-modules:      Client.UI.Content.KeyKind,+                      Content.CaveKind,+                      Content.FactionKind,+                      Content.ItemKind,+                      Content.ItemKindActor,+                      Content.ItemKindOrgan,+                      Content.ItemKindShrapnel,+                      Content.ModeKind,+                      Content.PlaceKind,+                      Content.RuleKind,+                      Content.TileKind,+                      TieKnot,+                      Paths_SpacePrivateers++  build-depends:      base              >=4.7       && <4.8,+                      LambdaHack        >= 0.2.14   && < 0.2.15,+                      containers        >= 0.5      && < 1,+                      enummapset-th     >= 0.6.0.0  && < 1,+                      filepath          >= 1.2.0.1  && < 2,+                      template-haskell  >= 2.6      && < 3,+                      text              >= 0.11.2.3 && < 2+  default-language:   Haskell2010++  default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings+                      BangPatterns, RecordWildCards, NamedFieldPuns+  other-extensions:   TemplateHaskell+  ghc-options: -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns+  ghc-options: -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction+  ghc-options: -fwarn-unrecognised-pragmas+  ghc-options: -fno-warn-auto-orphans -fno-warn-implicit-prelude+  ghc-options: -fno-ignore-asserts -funbox-strict-fields+  ghc-options: -threaded -with-rtsopts=-C0.005+
+ changelog view
@@ -0,0 +1,2 @@+v0.1.0+        * Initial version