-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A roguelike game engine in early and active development -- -- This is an alpha release of LambdaHack, a game engine library for -- roguelike games of arbitrary theme, size and complexity, packaged -- together with a small example dungeon crawler. When completed, the -- engine will let you specify content to be procedurally generated, -- define the AI behaviour on top of the generic content-independent -- rules and compile a ready-to-play game binary, using either the -- supplied or a custom-made main loop. Several frontends are available -- (GTK is the default) and many other generic engine components are -- easily overridden, but the fundamental source of flexibility lies in -- the strict and type-safe separation of code and content and of clients -- (human and AI-controlled) and server. -- -- New, in this release, is cooperative and competitive multiplayer -- (shared-screen only in this version) and overhauled searching. The -- code has been rewritten to have a single server that sends restricted -- game state updates to many fat clients, while a thin frontend layer -- multiplexes visuals from a subset of the clients. Upcoming features: -- new and improved frontends, improved AI (better leader switching and -- ranged combat), dynamic light sources, explosions, player action -- undo/redo, completely redesigned UI. Long term goals are focused on -- procedural content generation and include in-game content creation, -- auto-balancing and persistent content modification based on player -- behaviour. -- -- A larger game that depends on the LambdaHack library is Allure of the -- Stars, available from -- http://hackage.haskell.org/package/Allure. -- -- Note: All modules in this library are kept visible, to let games -- override and reuse them. OTOH, to reflect that some modules are -- implementation details relative to others, the source code adheres to -- the following convention. If a module has the same name as a -- directory, the module is the exclusive interface to the directory. No -- references to the modules in the directory are allowed except from the -- interface module. This policy is only binding inside the library --- -- users are free to do whatever they please, since the library authors -- are in no position to guess their particular needs. @package LambdaHack @version 0.2.8 -- | Queues implemented with two stacks to ensure fast writes. module Game.LambdaHack.Utils.LQueue -- | Queues implemented with two stacks. type LQueue a = ([a], [a]) -- | Create a new empty mutable queue. newLQueue :: LQueue a -- | Check if the queue is empty. nullLQueue :: LQueue a -> Bool -- | The length of the queue. lengthLQueue :: LQueue a -> Int -- | Try reading a queue. Return Nothing if empty. tryReadLQueue :: LQueue a -> Maybe (a, LQueue a) -- | Write to the queue. Faster than reading. writeLQueue :: LQueue a -> a -> LQueue a -- | Remove all but the last written non-Nothing element of the -- queue. trimLQueue :: LQueue (Maybe a) -> LQueue (Maybe a) -- | Remove frames up to and including the first segment of -- Nothing frames. | If the resulting queue is empty, apply -- trimLQueue instead. dropStartLQueue :: LQueue (Maybe a) -> LQueue (Maybe a) -- | Dump all but the last written non-Nothing element of the -- queue, if any. lastLQueue :: LQueue (Maybe a) -> Maybe a toListLQueue :: LQueue a -> [a] -- | Hacks that haven't found their home yet. module Game.LambdaHack.Common.Misc -- | Level bounds. TODO: query terminal size instead and scroll view. normalLevelBound :: (Int, Int) -- | Maximal supported level X and Y dimension (32768). Not checked -- anywhere. The value is chosen to support architectures with 32-bit -- ints. maxLevelDim :: Int -- | Integer division, rounding up. divUp :: Int -> Int -> Int -- | For each group that the kind belongs to, denoted by a Text -- name in the first component of a pair, the second component of a pair -- shows how common the kind is within the group. type Freqs = [(Text, Int)] -- |
-- breturn b a = [a | b] --breturn :: MonadPlus m => Bool -> a -> m a -- | A unique identifier of a faction in a game. data FactionId -- | Abstract level identifiers. data LevelId instance Show FactionId instance Eq FactionId instance Ord FactionId instance Enum FactionId instance Show LevelId instance Eq LevelId instance Ord LevelId instance Enum LevelId instance Read LevelId instance Binary LevelId instance Binary FactionId instance Enum k => Adjustable (EnumMap k) instance Enum k => Lookup (EnumMap k) instance Enum k => Indexable (EnumMap k) instance Enum k => TraversableWithKey (EnumMap k) instance Enum k => FoldableWithKey (EnumMap k) instance Enum k => Keyed (EnumMap k) instance Enum k => ZipWithKey (EnumMap k) instance Zip (EnumMap k) instance (Enum k, Binary k) => Binary (EnumSet k) instance (Enum k, Binary k, Binary e) => Binary (EnumMap k e) -- | A game requires the engine provided by the library, perhaps -- customized, and game content, defined completely afresh for the -- particular game. The general type of the content is -- ContentDef and it has instances for all content kinds, such -- as items kinds (Game.LambdaHack.Content.ItemKind). The -- possible kinds are fixed in the library and all defined in the same -- directory. On the other hand, game content, that is all elements of -- ContentDef instances, are defined in a directory of the game -- code proper, with names corresponding to their kinds. module Game.LambdaHack.Common.ContentDef -- | The general type of a particular game content, e.g., item kinds. data ContentDef a ContentDef :: (a -> Char) -> (a -> Text) -> (a -> Freqs) -> ([a] -> [a]) -> [a] -> ContentDef a -- | symbol, e.g., to print on the map getSymbol :: ContentDef a -> a -> Char -- | name, e.g., to show to the player getName :: ContentDef a -> a -> Text -- | frequency within groups getFreq :: ContentDef a -> a -> Freqs -- | validate and catch some offenders, if any validate :: ContentDef a -> [a] -> [a] -- | all the defined content of this type content :: ContentDef a -> [a] -- | The type of kinds of game factions (heroes, enemies, NPCs, etc.). module Game.LambdaHack.Content.FactionKind -- | Faction properties that are fixed for a given kind of factions. data FactionKind FactionKind :: !Char -> !Text -> !Freqs -> !Text -> !Text -> FactionKind -- | a symbol fsymbol :: FactionKind -> !Char -- | short description fname :: FactionKind -> !Text -- | frequency within groups ffreq :: FactionKind -> !Freqs -- | AI to use for the selected actor fAiLeader :: FactionKind -> !Text -- | AI to use for idle actors fAiMember :: FactionKind -> !Text -- | No specific possible problems for the content of this kind, so far, so -- the validation function always returns the empty list of offending -- kinds. fvalidate :: [FactionKind] -> [FactionKind] instance Show FactionKind -- | The type of kinds of rooms, halls and passages. module Game.LambdaHack.Content.PlaceKind -- | Parameters for the generation of small areas within a dungeon level. data PlaceKind PlaceKind :: Char -> Text -> Freqs -> Cover -> Fence -> [Text] -> PlaceKind -- | a symbol psymbol :: PlaceKind -> Char -- | short description pname :: PlaceKind -> Text -- | frequency within groups pfreq :: PlaceKind -> Freqs -- | how to fill whole place based on the corner pcover :: PlaceKind -> Cover -- | whether to fence the place with solid border pfence :: PlaceKind -> Fence -- | plan of the top-left corner of the place ptopLeft :: PlaceKind -> [Text] -- | A method of filling the whole area by transforming a given corner. data Cover -- | reflect every other corner, overlapping 1 row and column CAlternate :: Cover -- | fill symmetrically 4 corners and stretch their borders CStretch :: Cover -- | tile separately and symmetrically quarters of the place CReflect :: Cover -- | The choice of a fence type for the place. data Fence -- | put a solid wall fence around the place FWall :: Fence -- | leave an empty floor space around the place FFloor :: Fence -- | skip the fence and fill all with the place proper FNone :: Fence -- | Filter a list of kinds, passing through only the incorrect ones, if -- any. -- -- Verify that the top-left corner map is rectangular and not empty. pvalidate :: [PlaceKind] -> [PlaceKind] instance Show Cover instance Eq Cover instance Show Fence instance Eq Fence instance Show PlaceKind -- | AI strategy abilities. module Game.LambdaHack.Common.Ability -- | All possible AI actor abilities. AI chooses among these when -- considering the next action to perform. The ability descriptions refer -- to the target that any actor picks each turn, depending on the actor's -- characteristics and his environment. data Ability -- | move along a set path, if any, meleeing any opponents Track :: Ability -- | heal if almost dead Heal :: Ability -- | flee if almost dead Flee :: Ability -- | melee target Melee :: Ability -- | gather items, if no foes visible Pickup :: Ability -- | attack the visible target opponent at range, some of the time Ranged :: Ability -- | use items, if target opponent visible, some of the time Tools :: Ability -- | chase the target, ignoring any actors on the way Chase :: Ability -- | wander around, meleeing any opponents on the way Wander :: Ability instance Show Ability instance Eq Ability instance Ord Ability instance Enum Ability instance Bounded Ability -- | The type of kinds of AI strategies. module Game.LambdaHack.Content.StrategyKind -- | Strategy properties that are fixed for a given kind of strategies. data StrategyKind StrategyKind :: !Char -> !Text -> !Freqs -> ![Ability] -> StrategyKind -- | a symbol ssymbol :: StrategyKind -> !Char -- | short description sname :: StrategyKind -> !Text -- | frequency within groups sfreq :: StrategyKind -> !Freqs -- | abilities to pick from in roughly that order sabilities :: StrategyKind -> ![Ability] -- | No specific possible problems for the content of this kind, so far, so -- the validation function always returns the empty list of offending -- kinds. svalidate :: [StrategyKind] -> [StrategyKind] instance Show StrategyKind -- | Game time and speed. module Game.LambdaHack.Common.Time -- | Game time in ticks. The time dimension. One tick is 1 microsecond (one -- millionth of a second), one turn is 0.5 s. data Time -- | Start of the game time, or zero lenght time interval. timeZero :: Time -- | At least once per clip all moves are resolved and a frame or a frame -- delay is generated. Currently one clip is 0.1 s, but it may change, -- and the code should not depend on this fixed value. timeClip :: Time -- | One turn is 0.5 s. The code may depend on that. Actors at normal speed -- (2 m/s) take one turn to move one tile (1 m by 1 m). timeTurn :: Time -- | Time addition. timeAdd :: Time -> Time -> Time -- | How many time intervals of the latter kind fits in an interval of the -- former kind. timeFit :: Time -> Time -> Int -- | Negate a time interval. Can be used to subtract from a time or to -- reverse the ordering on time. timeNegate :: Time -> Time -- | Scale time by an Int scalar value. timeScale :: Time -> Int -> Time -- | An infinitesimal time period. timeEpsilon :: Time -- | Represent the main 10 thresholds of a time range by digits, given the -- total length of the time range. timeToDigit :: Time -> Time -> Char -- | Speed in meters per 1 million seconds (m/Ms). Actors at normal speed -- (2 m/s) take one time turn (0.5 s) to move one tile (1 m by 1 m). data Speed -- | Constructor for content definitions. toSpeed :: Double -> Speed -- | No movement possible at that speed. speedZero :: Speed -- | Normal speed (2 m/s) that suffices to move one tile in one turn. speedNormal :: Speed -- | Scale speed by an Int scalar value. speedScale :: Rational -> Speed -> Speed -- | Speed addition. speedAdd :: Speed -> Speed -> Speed -- | Speed negation. speedNegate :: Speed -> Speed -- | The number of time ticks it takes to walk 1 meter at the given speed. ticksPerMeter :: Speed -> Time -- | Distance in meters (so also in tiles, given the chess metric) traveled -- in a given time by a body with a given speed. traveled :: Speed -> Time -> Int -- | Calculate projectile speed from item weight in grams and speed bonus -- in percents. See -- https://github.com/kosmikus/LambdaHack/wiki/Item-statistics. speedFromWeight :: Int -> Int -> Speed -- | Calculate maximum range in meters of a projectile from its speed. See -- https://github.com/kosmikus/LambdaHack/wiki/Item-statistics. -- With this formula, each projectile flies for exactly one second, that -- is 2 turns, and then drops to the ground. Dividing and multiplying by -- 2 ensures both turns of flight cover the same distance. rangeFromSpeed :: Speed -> Int instance Show Time instance Eq Time instance Ord Time instance Enum Time instance Show Speed instance Eq Speed instance Ord Speed instance Binary Speed instance Binary Time -- | Colours and text attributes. module Game.LambdaHack.Common.Color -- | Colours supported by the major frontends. data Color Black :: Color Red :: Color Green :: Color Brown :: Color Blue :: Color Magenta :: Color Cyan :: Color White :: Color BrBlack :: Color BrRed :: Color BrGreen :: Color BrYellow :: Color BrBlue :: Color BrMagenta :: Color BrCyan :: Color BrWhite :: Color -- | The default colours, to optimize attribute setting. defBG :: Color -- | The default colours, to optimize attribute setting. defFG :: Color -- | A helper for the terminal frontends that display bright via bold. isBright :: Color -> Bool -- | Due to the limitation of the curses library used in the curses -- frontend, only these are legal backgrounds. legalBG :: [Color] -- | Colour sets. darkCol :: [Color] -- | Colour sets. brightCol :: [Color] -- | Colour sets. stdCol :: [Color] -- | Translationg to heavily modified Linux console color RGB values. colorToRGB :: Color -> String -- | Text attributes: foreground and backgroud colors. data Attr Attr :: !Color -> !Color -> Attr -- | foreground colour fg :: Attr -> !Color -- | backgroud color bg :: Attr -> !Color -- | The default attribute, to optimize attribute setting. defAttr :: Attr data AttrChar AttrChar :: !Attr -> !Char -> AttrChar acAttr :: AttrChar -> !Attr acChar :: AttrChar -> !Char instance Show Color instance Eq Color instance Ord Color instance Enum Color instance Bounded Color instance Generic Color instance Show Attr instance Eq Attr instance Ord Attr instance Show AttrChar instance Eq AttrChar instance Datatype D1Color instance Constructor C1_0Color instance Constructor C1_1Color instance Constructor C1_2Color instance Constructor C1_3Color instance Constructor C1_4Color instance Constructor C1_5Color instance Constructor C1_6Color instance Constructor C1_7Color instance Constructor C1_8Color instance Constructor C1_9Color instance Constructor C1_10Color instance Constructor C1_11Color instance Constructor C1_12Color instance Constructor C1_13Color instance Constructor C1_14Color instance Constructor C1_15Color instance Binary AttrChar instance Binary Attr instance Binary Color instance Hashable Color -- | The appearance of in-game items, as communicated to the player. module Game.LambdaHack.Common.Flavour -- | The type of item flavours. data Flavour -- | Turn a colour set into a flavour set. zipPlain :: [Color] -> [Flavour] -- | Turn a colour set into a flavour set. zipFancy :: [Color] -> [Flavour] -- | The standard full set of flavours. stdFlav :: [Flavour] -- | Get the underlying base colour of a flavour. flavourToColor :: Flavour -> Color -- | Construct the full name of a flavour. flavourToName :: Flavour -> Text -- | Simple names for team colors (bright colours preferred). colorToTeamName :: Color -> Text -- | Human-readable names, for item colors. The simple set. colorToPlainName :: Color -> Text -- | Human-readable names, for item colors. The fancy set. colorToFancyName :: Color -> Text instance Show Flavour instance Eq Flavour instance Ord Flavour instance Generic Flavour instance Datatype D1Flavour instance Constructor C1_0Flavour instance Selector S1_0_0Flavour instance Selector S1_0_1Flavour instance Binary Flavour instance Hashable Flavour -- | Saving/loading with serialization and compression. module Game.LambdaHack.Utils.File -- | Serialize, compress and save data with an EOF marker. The OK -- is used as an EOF marker to ensure any apparent problems with -- corrupted files are reported to the user ASAP. encodeEOF :: Binary a => FilePath -> a -> IO () -- | Read, decompress and deserialize data with an EOF marker. The -- OK EOF marker ensures any easily detectable file corruption -- is discovered and reported before the function returns. strictDecodeEOF :: Binary a => FilePath -> IO a -- | Try to create a directory, if it doesn't exist. Terminate the program -- with an exception if the directory does not exist, but can't be -- created. tryCreateDir :: FilePath -> IO () -- | Try to copy over data files, if not already there. tryCopyDataFiles :: (FilePath -> IO FilePath) -> [(FilePath, FilePath)] -> IO () -- | Tools for specifying assertions. A step towards contracts. Actually, a -- bunch of hacks wrapping the original assert function, which -- is the only easy way of obtaining source positions. module Game.LambdaHack.Utils.Assert -- | If the first argument evaluates to True, then the result is the -- second argument. Otherwise an AssertionFailed exception is -- raised, containing a String with the source file and line -- number of the call to assert. -- -- Assertions can normally be turned on or off with a compiler flag (for -- GHC, assertions are normally on unless optimisation is turned on with -- -O or the -fignore-asserts option is given). When -- assertions are turned off, the first argument to assert is -- ignored, and the second argument is returned as the result. assert :: Bool -> a -> a -- | If the condition fails, display the value blamed for the failure. Used -- as in -- --
-- assert (c /= 0 `blame` c) $ 10 / c --blame :: Show a => Bool -> a -> Bool -- | Like error, but shows the source position and also the value to -- blame for the failure. To be used as in: -- --
-- assert `failure` ((x1, y1), (x2, y2), "designate a vertical line") --failure :: Show a => (Bool -> b -> b) -> a -> b -- | Like all, but if the predicate fails, blame all the list -- elements and especially those for which it fails. To be used as in: -- --
-- assert (allB (>= 0) [yf, xf, y1, x1, y2, x2]) --allB :: Show a => (a -> Bool) -> [a] -> Bool -- | To be used in place of the verbose skip, as in: -- --
-- do b <- getB a -- assert (b `blame` a) skip --skip :: Monad m => m () -- | Basic cartesian geometry operations on 2D points. module Game.LambdaHack.Common.PointXY -- | Spacial dimension for points and vectors. type X = Int -- | Spacial dimension for points and vectors. type Y = Int -- | 2D points in cartesian representation. newtype PointXY PointXY :: (X, Y) -> PointXY -- | A list of all points on a straight vertical or straight horizontal -- line between two points. Fails if no such line exists. fromTo :: PointXY -> PointXY -> [PointXY] -- | Sort the sequence of two points, in the derived lexicographic order. sortPointXY :: (PointXY, PointXY) -> (PointXY, PointXY) -- | Bresenham's line algorithm generalized to arbitrary starting -- eps (eps value of 0 gives the standard BLA). -- Includes the source point and goes through the target point to -- infinity. blaXY :: Int -> PointXY -> PointXY -> [PointXY] instance Eq PointXY instance Ord PointXY instance Enum PointXY instance Show PointXY -- | Game messages displayed on top of the screen for the player to read. module Game.LambdaHack.Common.Msg -- | Re-exported English phrase creation functions, applied to default -- irregular word sets. makePhrase :: [Part] -> Text -- | Re-exported English phrase creation functions, applied to default -- irregular word sets. makeSentence :: [Part] -> Text -- | The type of a single message. type Msg = Text -- | Identical to append. (<>) :: Text -> Text -> Text -- | Separated by space unless one of them is empty (in which case just the -- non-empty one). (<+>) :: Text -> Text -> Text -- | Show a value in Text format. showT :: Show a => a -> Text -- | The "press something to see more" mark. moreMsg :: Msg -- | The confirmation request message. yesnoMsg :: Msg -- | Add a space at the message end, for display overlayed over the level -- map. Also trims (does not wrap!) too long lines. In case of newlines, -- displays only the first line, but marks the message as partial. truncateMsg :: X -> Text -> Text -- | The type of a set of messages to show at the screen at once. data Report -- | Empty set of messages. emptyReport :: Report -- | Test if the set of messages is empty. nullReport :: Report -> Bool -- | Construct a singleton set of messages. singletonReport :: Msg -> Report -- | Add message to the end of report. addMsg :: Report -> Msg -> Report -- | Split a messages into chunks that fit in one line. We assume the width -- of the messages line is the same as of level map. splitReport :: Report -> [Text] -- | Render a report as a (possibly very long) string. renderReport :: Report -> Text findInReport :: (ByteString -> Bool) -> Report -> Maybe ByteString -- | The history of reports. data History -- | Empty history of reports. emptyHistory :: History -- | Construct a singleton history of reports. singletonHistory :: Report -> History mergeHistory :: [(Msg, History)] -> History -- | Add a report to history, handling repetitions. addReport :: Report -> History -> History -- | Render history as many lines of text, wrapping if necessary. renderHistory :: History -> Overlay -- | Take the given prefix of reports from a history. takeHistory :: Int -> History -> History -- | A series of screen lines that may or may not fit the width nor height -- of the screen. An overlay may be transformed by adding the first line -- and/or by splitting into a slideshow of smaller overlays. type Overlay = [Text] -- | Returns a function that looks up the characters in the string by -- position. Takes the width and height of the display plus the string. -- Returns also the message to print at the top and bottom. stringByLocation :: X -> Y -> Overlay -> (Text, PointXY -> Maybe Char, Maybe Text) -- | A few overlays, displayed one by one upon keypress. When displayed, -- they are trimmed, not wrapped and any lines below the lower screen -- edge are not visible. data Slideshow -- | Split an overlay into a slideshow in which each overlay, prefixed by -- msg and postfixed by moreMsg except for the last -- one, fits on the screen wrt height (but lines may still be too wide). splitOverlay :: Y -> Overlay -> Overlay -> Slideshow -- | Declare the list of overlays to be fit for display on the screen. In -- particular, current Report is eiter empty or unimportant or -- contained in the overlays and if any vertical or horizontal trimming -- of the overlays happens, this is intended. toSlideshow :: [Overlay] -> Slideshow instance Show Report instance Show History instance Monoid Slideshow instance Show Slideshow instance Binary History instance Binary Report -- | A list of items with relative frequencies of appearance. module Game.LambdaHack.Utils.Frequency -- | The frequency distribution type. data Frequency a -- | Uniform discrete frequency distribution. uniformFreq :: Text -> [a] -> Frequency a -- | Takes a name and a list of frequencies and items into the frequency -- distribution. toFreq :: Text -> [(Int, a)] -> Frequency a -- | Scale frequecy distribution, multiplying it by a positive integer -- constant. scaleFreq :: Show a => Int -> Frequency a -> Frequency a -- | Change the description of the frequency. renameFreq :: Text -> Frequency a -> Frequency a -- | Randomly choose an item according to the distribution. rollFreq :: Show a => Frequency a -> StdGen -> (a, StdGen) -- | Test if the frequency distribution is empty. nullFreq :: Frequency a -> Bool -- | give acces to raw frequency values runFrequency :: Frequency a -> [(Int, a)] -- | short description for debug, etc. nameFrequency :: Frequency a -> Text instance Show a => Show (Frequency a) instance Functor Frequency instance MonadPlus Frequency instance Monad Frequency -- | Representation of probabilities and random computations. module Game.LambdaHack.Common.Random -- | The monad of computations with random generator state. The lazy state -- monad is OK here: the state is small and regularly forced. type Rnd a = State StdGen a -- | Get a random object within a range with a uniform distribution. randomR :: Random a => (a, a) -> Rnd a -- | Get a random object of a given type with a uniform distribution. random :: Random a => Rnd a -- | Get any element of a list with equal probability. oneOf :: [a] -> Rnd a -- | Gen an element according to a frequency distribution. frequency :: Show a => Frequency a -> Rnd a -- | Roll a single die. roll :: Int -> Rnd Int -- | Dice: 1d7, 3d3, 1d0, etc. RollDice a b represents a -- rolls of b-sided die. data RollDice RollDice :: Word8 -> Word8 -> RollDice -- | Roll dice and sum the results. rollDice :: RollDice -> Rnd Int -- | Maximal value of dice. maxDice :: RollDice -> Int -- | Minimal value of dice. minDice :: RollDice -> Int -- | Mean value of dice. meanDice :: RollDice -> Rational -- | Dice for rolling a pair of integer parameters pertaining to, -- respectively, the X and Y cartesian 2D coordinates. data RollDiceXY RollDiceXY :: (RollDice, RollDice) -> RollDiceXY -- | Roll the two sets of dice. rollDiceXY :: RollDiceXY -> Rnd (Int, Int) -- | Dice for parameters scaled with current level depth. To the result of -- rolling the first set of dice we add the second, scaled in proportion -- to current depth divided by maximal dungeon depth. type RollDeep = (RollDice, RollDice) -- | Roll dice scaled with current level depth. Note that at the first -- level, the scaled dice are always ignored. rollDeep :: Int -> Int -> RollDeep -> Rnd Int -- | Roll dice scaled with current level depth and return True if -- the results if greater than 50. chanceDeep :: Int -> Int -> RollDeep -> Rnd Bool -- | Generate a RollDeep that always gives a constant integer. intToDeep :: Int -> RollDeep -- | Maximal value of scaled dice. maxDeep :: RollDeep -> Int -- | Fractional chance. type Chance = Rational -- | Give True, with probability determined by the fraction. chance :: Chance -> Rnd Bool rndToIO :: Rnd a -> IO a instance Eq RollDice instance Ord RollDice instance Generic RollDice instance Show RollDiceXY instance Datatype D1RollDice instance Constructor C1_0RollDice instance Binary RollDice instance Hashable RollDice instance Read RollDice instance Show RollDice -- | Effects of content on other content. No operation in this module -- involves the State or Action type. module Game.LambdaHack.Common.Effect data Effect a NoEffect :: Effect a Heal :: Int -> Effect a Hurt :: !RollDice -> a -> Effect a Mindprobe :: Int -> Effect a Dominate :: Effect a CallFriend :: Int -> Effect a Summon :: Int -> Effect a CreateItem :: Int -> Effect a ApplyPerfume :: Effect a Regeneration :: a -> Effect a Searching :: a -> Effect a Ascend :: Int -> Effect a Descend :: Int -> Effect a Escape :: Effect a -- | Transform an effect using a stateful function. effectTrav :: Effect a -> (a -> State s b) -> State s (Effect b) effectToSuffix :: Effect Int -> Text -- | How much AI benefits from applying the effect. Multipllied by item p. -- Negative means harm to the enemy when thrown at him. Effects with zero -- benefit won't ever be used, neither actively nor passively. effectToBenefit :: Effect Int -> Int instance Show a => Show (Effect a) instance Read a => Read (Effect a) instance Eq a => Eq (Effect a) instance Ord a => Ord (Effect a) instance Generic (Effect a) instance Functor Effect instance Datatype D1Effect instance Constructor C1_0Effect instance Constructor C1_1Effect instance Constructor C1_2Effect instance Constructor C1_3Effect instance Constructor C1_4Effect instance Constructor C1_5Effect instance Constructor C1_6Effect instance Constructor C1_7Effect instance Constructor C1_8Effect instance Constructor C1_9Effect instance Constructor C1_10Effect instance Constructor C1_11Effect instance Constructor C1_12Effect instance Constructor C1_13Effect instance Binary a => Binary (Effect a) instance Hashable a => Hashable (Effect a) -- | Terrain tile features. module Game.LambdaHack.Common.Feature -- | All possible terrain tile features, some of them parameterized or -- dependent on outside coefficients, e.g., on the tile secrecy value. data Feature -- | triggered by ascending Ascendable :: Feature -- | triggered by descending Descendable :: Feature -- | triggered by escaping Escapable :: Feature -- | triggered by opening Openable :: Feature -- | triggered by closing Closable :: Feature -- | causes the effect when triggered Cause :: !(Effect Int) -> Feature -- | transitions to a tile of the group when triggered ChangeTo :: !Text -> Feature -- | actors can walk through Walkable :: Feature -- | actors can see through Clear :: Feature -- | is lit with an ambient shine Lit :: Feature -- | may not be what it seems (clients only) Suspect :: Feature -- | sustains the effect continuously, TODO Aura :: !(Effect Int) -> Feature -- | can never be excavated nor seen through Impenetrable :: Feature -- | items can be generated there CanItem :: Feature -- | actors and stairs can be generated there CanActor :: Feature -- | is a (not hidden) door, stair, etc. Exit :: Feature -- | used for visible paths throughout the level Path :: Feature -- | when hidden, looks as a tile of the group HiddenAs :: !Text -> Feature instance Show Feature instance Read Feature instance Eq Feature instance Ord Feature instance Generic Feature instance Datatype D1Feature instance Constructor C1_0Feature instance Constructor C1_1Feature instance Constructor C1_2Feature instance Constructor C1_3Feature instance Constructor C1_4Feature instance Constructor C1_5Feature instance Constructor C1_6Feature instance Constructor C1_7Feature instance Constructor C1_8Feature instance Constructor C1_9Feature instance Constructor C1_10Feature instance Constructor C1_11Feature instance Constructor C1_12Feature instance Constructor C1_13Feature instance Constructor C1_14Feature instance Constructor C1_15Feature instance Constructor C1_16Feature instance Constructor C1_17Feature instance Binary Feature -- | The type of kinds of weapons and treasure. module Game.LambdaHack.Content.ItemKind -- | Item properties that are fixed for a given kind of items. data ItemKind ItemKind :: !Char -> !Text -> !Freqs -> ![Flavour] -> !(Effect RollDeep) -> !RollDeep -> !Part -> !Part -> !Int -> !Int -> ItemKind -- | map symbol isymbol :: ItemKind -> !Char -- | generic name iname :: ItemKind -> !Text -- | frequency within groups ifreq :: ItemKind -> !Freqs -- | possible flavours iflavour :: ItemKind -> ![Flavour] -- | the effect when activated ieffect :: ItemKind -> !(Effect RollDeep) -- | created in that quantify icount :: ItemKind -> !RollDeep -- | the verb for applying and possibly combat iverbApply :: ItemKind -> !Part -- | the verb for projecting iverbProject :: ItemKind -> !Part -- | weight in grams iweight :: ItemKind -> !Int -- | percentage bonus or malus to throw speed itoThrow :: ItemKind -> !Int -- | No specific possible problems for the content of this kind, so far, so -- the validation function always returns the empty list of offending -- kinds. ivalidate :: [ItemKind] -> [ItemKind] instance Show ItemKind -- | The type of kinds of monsters and heroes. module Game.LambdaHack.Content.ActorKind -- | Actor properties that are fixed for a given kind of actors. data ActorKind ActorKind :: !Char -> !Text -> !Freqs -> !Color -> !Speed -> !RollDice -> !Bool -> !Bool -> !Int -> !Int -> ![Ability] -> ActorKind -- | map symbol asymbol :: ActorKind -> !Char -- | short description aname :: ActorKind -> !Text -- | frequency within groups afreq :: ActorKind -> !Freqs -- | map color acolor :: ActorKind -> !Color -- | natural speed in m/s aspeed :: ActorKind -> !Speed -- | encodes initial and maximal hp ahp :: ActorKind -> !RollDice -- | can it see? asight :: ActorKind -> !Bool -- | can it smell? asmell :: ActorKind -> !Bool -- | intelligence aiq :: ActorKind -> !Int -- | number of turns to regenerate 1 HP aregen :: ActorKind -> !Int -- | the set of supported abilities acanDo :: ActorKind -> ![Ability] -- | Filter a list of kinds, passing through only the incorrect ones, if -- any. -- -- Make sure actor kinds can be told apart on the level map. avalidate :: [ActorKind] -> [ActorKind] instance Show ActorKind -- | AI strategies to direct actors not controlled directly by human -- players. No operation in this module involves the State or -- Action type. module Game.LambdaHack.Client.Strategy -- | A strategy is a choice of (non-empty) frequency tables of possible -- actions. data Strategy a nullStrategy :: Strategy a -> Bool -- | Strategy where only the actions from the given single frequency table -- can be picked. liftFrequency :: Frequency a -> Strategy a -- | Strategy with the actions from both argument strategies, with original -- frequencies. (.|) :: Strategy a -> Strategy a -> Strategy a -- | Strategy with no actions at all. reject :: Strategy a -- | Conditionally accepted strategy. (.=>) :: Bool -> Strategy a -> Strategy a -- | Strategy with all actions not satisfying the predicate removed. The -- remaining actions keep their original relative frequency values. only :: (a -> Bool) -> Strategy a -> Strategy a -- | When better choices are towards the start of the list, this is the -- best frequency of the strategy. bestVariant :: Strategy a -> Frequency a -- | Overwrite the description of all frequencies within the strategy. renameStrategy :: Text -> Strategy a -> Strategy a -- | Like return, but pick a name of the single frequency. returN :: Text -> a -> Strategy a instance Show a => Show (Strategy a) instance MonadPlus Strategy instance Monad Strategy -- | Basic cartesian geometry operations on 2D vectors. module Game.LambdaHack.Common.VectorXY -- | 2D vectors in cartesian representation. newtype VectorXY VectorXY :: (X, Y) -> VectorXY -- | Shift a point by a vector. shiftXY :: PointXY -> VectorXY -> PointXY -- | Vectors of all unit moves in the chessboard metric, clockwise, -- starting north-west. movesXY :: [VectorXY] -- | Vectors of all cardinal direction unit moves, clockwise, starting -- north. movesCardinalXY :: [VectorXY] -- | The lenght of a vector in the chessboard metric, where diagonal moves -- cost 1. chessDistXY :: VectorXY -> Int -- | Squared euclidean length of a vector. euclidDistSqXY :: VectorXY -> Int -- | Reverse an arbirary vector. negXY :: VectorXY -> VectorXY instance Eq VectorXY instance Ord VectorXY instance Show VectorXY instance Read VectorXY instance Binary VectorXY -- | Abstract syntax human player commands. module Game.LambdaHack.Client.HumanCmd -- | Abstract syntax of player commands. data HumanCmd Move :: VectorXY -> HumanCmd Run :: VectorXY -> HumanCmd Wait :: HumanCmd Pickup :: HumanCmd Drop :: HumanCmd Project :: [Trigger] -> HumanCmd Apply :: [Trigger] -> HumanCmd TriggerDir :: [Trigger] -> HumanCmd TriggerTile :: [Trigger] -> HumanCmd GameRestart :: Text -> HumanCmd GameExit :: HumanCmd GameSave :: HumanCmd CfgDump :: HumanCmd SelectHero :: Int -> HumanCmd MemberCycle :: HumanCmd MemberBack :: HumanCmd Inventory :: HumanCmd TgtFloor :: HumanCmd TgtEnemy :: HumanCmd TgtAscend :: Int -> HumanCmd EpsIncr :: Bool -> HumanCmd Cancel :: HumanCmd Accept :: HumanCmd Clear :: HumanCmd History :: HumanCmd MarkVision :: HumanCmd MarkSmell :: HumanCmd MarkSuspect :: HumanCmd Help :: HumanCmd data Trigger ApplyItem :: Part -> Part -> Char -> Trigger verb :: Trigger -> Part object :: Trigger -> Part symbol :: Trigger -> Char BumpFeature :: Part -> Part -> Feature -> Trigger verb :: Trigger -> Part object :: Trigger -> Part feature :: Trigger -> Feature -- | Major commands land on the first page of command help. majorHumanCmd :: HumanCmd -> Bool -- | Minor commands land on the second page of command help. minorHumanCmd :: HumanCmd -> Bool -- | Commands that are forbidden on a remote level, because they would -- usually take time when invoked on one. Not that movement commands are -- not included, because they take time on normal levels, but don't take -- time on remote levels, that is, in targeting mode. noRemoteHumanCmd :: HumanCmd -> Bool -- | Description of player commands. cmdDescription :: HumanCmd -> Text instance Show Trigger instance Read Trigger instance Eq Trigger instance Ord Trigger instance Generic Trigger instance Show HumanCmd instance Read HumanCmd instance Eq HumanCmd instance Ord HumanCmd instance Generic HumanCmd instance Datatype D1Trigger instance Constructor C1_0Trigger instance Constructor C1_1Trigger instance Selector S1_0_0Trigger instance Selector S1_0_1Trigger instance Selector S1_0_2Trigger instance Selector S1_1_0Trigger instance Selector S1_1_1Trigger instance Selector S1_1_2Trigger instance Datatype D1HumanCmd instance Constructor C1_0HumanCmd instance Constructor C1_1HumanCmd instance Constructor C1_2HumanCmd instance Constructor C1_3HumanCmd instance Constructor C1_4HumanCmd instance Constructor C1_5HumanCmd instance Constructor C1_6HumanCmd instance Constructor C1_7HumanCmd instance Constructor C1_8HumanCmd instance Constructor C1_9HumanCmd instance Constructor C1_10HumanCmd instance Constructor C1_11HumanCmd instance Constructor C1_12HumanCmd instance Constructor C1_13HumanCmd instance Constructor C1_14HumanCmd instance Constructor C1_15HumanCmd instance Constructor C1_16HumanCmd instance Constructor C1_17HumanCmd instance Constructor C1_18HumanCmd instance Constructor C1_19HumanCmd instance Constructor C1_20HumanCmd instance Constructor C1_21HumanCmd instance Constructor C1_22HumanCmd instance Constructor C1_23HumanCmd instance Constructor C1_24HumanCmd instance Constructor C1_25HumanCmd instance Constructor C1_26HumanCmd instance Constructor C1_27HumanCmd instance Constructor C1_28HumanCmd instance Binary Trigger instance Binary HumanCmd -- | Rectangular areas of levels and their basic operations. module Game.LambdaHack.Common.Area -- | The type of areas. The bottom left and the top right points. type Area = (X, Y, X, Y) -- | All (8 at most) closest neighbours of a point within an area. vicinityXY :: Area -> PointXY -> [PointXY] -- | All (4 at most) cardinal direction neighbours of a point within an -- area. vicinityCardinalXY :: Area -> PointXY -> [PointXY] -- | Checks that a point belongs to an area. insideXY :: PointXY -> Area -> Bool -- | Sort the corners of an area so that the bottom left is the first -- point. normalizeArea :: Area -> Area -- | Divide uniformly a larger area into the given number of smaller areas. grid :: (X, Y) -> Area -> [(PointXY, Area)] -- | Checks if it's an area with at least one field. validArea :: Area -> Bool -- | Checks if it's an area with exactly one field. trivialArea :: Area -> Bool -- | Enlarge (or shrink) the given area on all fours sides by the amount. expand :: Area -> Int -> Area -- | Basic operations on 2D points represented as linear offsets. module Game.LambdaHack.Common.Point -- | The type of positions on the 2D level map, heavily optimized. -- -- We represent the (level map on the) screen as a linear framebuffer, -- where Point is an Int offset counted from the first -- cell. We do bounds check for the X size whenever we convert between -- representations and each subsequent array access performs another -- check, effectively for Y size. After dungeon is generated (using -- PointXY, not Point), and converted to the -- Point representation, points are used mainly as keys and not -- constructed often, so the performance will improve due to smaller save -- files, the use of EnumMap and cheaper array indexing, -- including cheaper bounds checks. data Point -- | Conversion from cartesian coordinates to Point. toPoint :: X -> PointXY -> Point -- | Print a point as a tuple of cartesian coordinates. showPoint :: X -> Point -> Text -- | The top-left corner position of the level. origin :: Point -- | The distance between two points in the chessboard metric. chessDist :: X -> Point -> Point -> Int -- | Checks whether two points are adjacent on the map (horizontally, -- vertically or diagonally). adjacent :: X -> Point -> Point -> Bool -- | Returns the 8, or less, surrounding positions of a given position. vicinity :: X -> Y -> Point -> [Point] -- | Returns the 4, or less, surrounding positions in cardinal directions -- from a given position. vicinityCardinal :: X -> Y -> Point -> [Point] -- | Checks that a point belongs to an area. inside :: X -> Point -> Area -> Bool -- | Calculate the displacement vector from a position to another. displacementXYZ :: X -> Point -> Point -> VectorXY -- | Bresenham's line algorithm generalized to arbitrary starting -- eps (eps value of 0 gives the standard BLA). Skips -- the source point and goes through the second point to the edge of the -- level. GIves Nothing if the points are equal. bla :: X -> Y -> Int -> Point -> Point -> Maybe [Point] instance Eq Point instance Ord Point instance Ix Point instance Enum Point instance Random Point instance Show Point instance Binary Point -- | Screen frames and animations. module Game.LambdaHack.Common.Animation -- | Text attributes: foreground and backgroud colors. data Attr Attr :: !Color -> !Color -> Attr -- | foreground colour fg :: Attr -> !Color -- | backgroud color bg :: Attr -> !Color -- | The default attribute, to optimize attribute setting. defAttr :: Attr data AttrChar AttrChar :: !Attr -> !Char -> AttrChar acAttr :: AttrChar -> !Attr acChar :: AttrChar -> !Char -- | The data sufficent to draw a single game screen frame. data SingleFrame SingleFrame :: [[AttrChar]] -> Text -> Text -> SingleFrame -- | content of the screen, line by line sfLevel :: SingleFrame -> [[AttrChar]] -- | an extra line to show at the top sfTop :: SingleFrame -> Text -- | an extra line to show at the bottom sfBottom :: SingleFrame -> Text emptySingleFrame :: SingleFrame xsizeSingleFrame :: SingleFrame -> X ysizeSingleFrame :: SingleFrame -> X -- | Animation is a list of frame modifications to play one by one, where -- each modification if a map from positions to level map symbols. data Animation -- | Sequences of screen frames, including delays. type Frames = [Maybe SingleFrame] -- | Render animations on top of a screen frame. renderAnim :: X -> Y -> SingleFrame -> Animation -> Frames restrictAnim :: EnumSet Point -> Animation -> Animation -- | Attack animation. A part of it also reused for self-damage and -- healing. twirlSplash :: (Point, Point) -> Color -> Color -> Animation -- | Attack that hits through a block. blockHit :: (Point, Point) -> Color -> Color -> Animation -- | Attack that is blocked. blockMiss :: (Point, Point) -> Animation -- | Death animation for an organic body. deathBody :: Point -> Animation -- | Swap-places animation, both hostile and friendly. swapPlaces :: (Point, Point) -> Animation fadeout :: Bool -> Bool -> X -> Y -> Rnd Animation data AcFrame AcConfirm :: SingleFrame -> AcFrame AcRunning :: SingleFrame -> AcFrame AcNormal :: SingleFrame -> AcFrame AcDelay :: AcFrame instance Eq SingleFrame instance Show SingleFrame instance Eq Animation instance Show Animation instance Monoid Animation instance Show AcFrame instance Eq AcFrame instance Binary AcFrame instance Binary SingleFrame -- | Basic operations on 2D vectors represented in an efficient, but not -- unique, way. module Game.LambdaHack.Common.Vector -- | 2D vectors represented as offsets in the linear framebuffer indexed by -- Point. -- -- A newtype is used to prevent mixing up the type with Point -- itself. Note that the offset representations of a vector is usually -- not unique. E.g., for vectors of length 1 in the chessboard metric, -- used to denote geographical directions, the representations are -- pairwise distinct if and only if the level width and height are at -- least 3. data Vector -- | Converts a vector in cartesian representation into Vector. toVector :: X -> VectorXY -> Vector -- | Converts a unit vector in cartesian representation into -- Vector. toDir :: X -> VectorXY -> Vector -- | Translate a point by a vector. -- -- Particularly simple and fast implementation in the linear -- representation. shift :: Point -> Vector -> Point -- | Translate a point by a vector, but only if the result fits in an area. shiftBounded :: X -> Area -> Point -> Vector -> Point -- | Vectors of all unit moves, clockwise, starting north-west. moves :: X -> [Vector] -- | Tells if a vector has length 1 in the chessboard metric. isUnit :: X -> Vector -> Bool -- | Squared euclidean distance between two unit vectors. euclidDistSq :: X -> Vector -> Vector -> Int -- | Checks whether a unit vector is a diagonal direction, as opposed to -- cardinal. If the vector is not unit, it reject horizontal and vertical -- vectors. diagonal :: X -> Vector -> Bool -- | Reverse an arbirary vector. neg :: Vector -> Vector -- | Given two distinct positions, determine the direction (a unit vector) -- in which one should move from the first in order to get closer to the -- second. Ignores obstacles. Of several equally good directions (in the -- chessboard metric) it picks one of those that visually (in the -- euclidean metric) maximally align with the vector between the two -- points. towards :: X -> Point -> Point -> Vector -- | A vector from a point to another. We have -- --
-- shift pos1 (displacement pos1 pos2) == pos2 ---- -- Particularly simple and fast implementation in the linear -- representation. displacement :: Point -> Point -> Vector -- | A list of vectors between a list of points. displacePath :: [Point] -> [Vector] -- | A list of points that a list of vectors leads to. shiftPath :: Point -> [Vector] -> [Point] instance Eq Vector instance Ord Vector instance Read Vector instance Show Vector instance Binary Vector -- | Frontend-independent keyboard input operations. module Game.LambdaHack.Common.Key -- | Frontend-independent datatype to represent keys. data Key Esc :: Key Return :: Key Space :: Key Tab :: Key BackTab :: Key PgUp :: Key PgDn :: Key Left :: Key Right :: Key Up :: Key Down :: Key End :: Key Begin :: Key Home :: Key -- | a keypad key for a character (digits and operators) KP :: !Char -> Key -- | a single printable character Char :: !Char -> Key -- | an unknown key, registered to warn the user Unknown :: !String -> Key -- | Configurable event handler for the direction keys. Used for directed -- commands such as close door. handleDir :: X -> KM -> (Vector -> a) -> a -> a dirAllMoveKey :: [Key] -- | Binding of both sets of movement keys. moveBinding :: (VectorXY -> a) -> (VectorXY -> a) -> [(KM, a)] -- | Translate key from a GTK string description to our internal key type. -- To be used, in particular, for the command bindings and macros in the -- config file. keyTranslate :: String -> Key -- | Our own encoding of modifiers. Incomplete. data Modifier NoModifier :: Modifier Control :: Modifier data KM KM :: !Modifier -> !Key -> KM modifier :: KM -> !Modifier key :: KM -> !Key -- | Show a key with a modifier, if any. showKM :: KM -> Text instance Ord Key instance Eq Key instance Ord Modifier instance Eq Modifier instance Ord KM instance Eq KM instance Binary KM instance Show KM instance Binary Modifier instance Binary Key -- | The type of cave layout kinds. module Game.LambdaHack.Content.CaveKind -- | Parameters for the generation of dungeon levels. data CaveKind CaveKind :: Char -> Text -> Freqs -> X -> Y -> RollDiceXY -> RollDiceXY -> RollDeep -> Rational -> Chance -> Int -> Int -> Chance -> Chance -> Int -> RollDice -> Text -> Text -> Text -> Text -> Text -> CaveKind -- | a symbol csymbol :: CaveKind -> Char -- | short description cname :: CaveKind -> Text -- | frequency within groups cfreq :: CaveKind -> Freqs -- | X size of the whole cave cxsize :: CaveKind -> X -- | Y size of the whole cave cysize :: CaveKind -> Y -- | the dimensions of the grid of places cgrid :: CaveKind -> RollDiceXY -- | minimal size of places cminPlaceSize :: CaveKind -> RollDiceXY -- | the chance a place is dark cdarkChance :: CaveKind -> RollDeep -- | a proportion of extra connections cauxConnects :: CaveKind -> Rational -- | the chance of not creating a place cvoidChance :: CaveKind -> Chance -- | extra places, may overlap except two cnonVoidMin :: CaveKind -> Int -- | minimal distance between stairs cminStairDist :: CaveKind -> Int -- | the chance of a door in an opening cdoorChance :: CaveKind -> Chance -- | if there's a door, is it open? copenChance :: CaveKind -> Chance -- | if not open, hidden one in n times chidden :: CaveKind -> Int -- | the number of items in the cave citemNum :: CaveKind -> RollDice -- | the default cave tile group name cdefTile :: CaveKind -> Text -- | the cave corridor tile group name ccorridorTile :: CaveKind -> Text -- | the filler wall group name cfillerTile :: CaveKind -> Text -- | the dark place plan legend ground name cdarkLegendTile :: CaveKind -> Text -- | the lit place plan legend ground name clitLegendTile :: CaveKind -> Text -- | Filter a list of kinds, passing through only the incorrect ones, if -- any. -- -- Catch caves with not enough space for all the places. Check the size -- of the cave descriptions to make sure they fit on screen. cvalidate :: [CaveKind] -> [CaveKind] instance Show CaveKind -- | Common definitions for the Field of View algorithms. See -- https://github.com/kosmikus/LambdaHack/wiki/Fov-and-los for -- some more context and references. module Game.LambdaHack.Server.Fov.Common -- | Distance from the (0, 0) point where FOV originates. type Distance = Int -- | Progress along an arc with a constant distance from (0, 0). type Progress = Int -- | Rotated and translated coordinates of 2D points, so that the points -- fit in a single quadrant area (e, g., quadrant I for Permissive FOV, -- hence both coordinates positive; adjacent diagonal halves of quadrant -- I and II for Digital FOV, hence y positive). The special coordinates -- are written using the standard mathematical coordinate setup, where -- quadrant I, with x and y positive, is on the upper right. newtype Bump B :: (X, Y) -> Bump -- | Straight line between points. type Line = (Bump, Bump) -- | Convex hull represented as a list of points. type ConvexHull = [Bump] -- | An edge (comprising of a line and a convex hull) of the area to be -- scanned. type Edge = (Line, ConvexHull) -- | The area left to be scanned, delimited by edges. type EdgeInterval = (Edge, Edge) -- | Maximal element of a non-empty list. Prefers elements from the rear, -- which is essential for PFOV, to avoid ill-defined lines. maximal :: (a -> a -> Bool) -> [a] -> a -- | Check if the line from the second point to the first is more steep -- than the line from the third point to the first. This is related to -- the formal notion of gradient (or angle), but hacked wrt signs to work -- fast in this particular setup. Returns True for ill-defined lines. steeper :: Bump -> Bump -> Bump -> Bool -- | Extends a convex hull of bumps with a new bump. Nothing needs to be -- done if the new bump already lies within the hull. The first argument -- is typically steeper, optionally negated, applied to the second -- argument. addHull :: (Bump -> Bump -> Bool) -> Bump -> ConvexHull -> ConvexHull instance Show Bump -- | The type of kinds of terrain tiles. module Game.LambdaHack.Content.TileKind -- | The type of kinds of terrain tiles. See Tile.hs for -- explanation of the absence of a corresponding type Tile that -- would hold particular concrete tiles in the dungeon. data TileKind TileKind :: !Char -> !Text -> !Freqs -> !Color -> !Color -> ![Feature] -> TileKind -- | map symbol tsymbol :: TileKind -> !Char -- | short description tname :: TileKind -> !Text -- | frequency within groups tfreq :: TileKind -> !Freqs -- | map color tcolor :: TileKind -> !Color -- | map color when not in FOV tcolor2 :: TileKind -> !Color -- | properties tfeature :: TileKind -> ![Feature] -- | Filter a list of kinds, passing through only the incorrect ones, if -- any. -- -- If tiles look the same on the map, the description should be the same, -- too. Otherwise, the player has to inspect manually all the tiles of -- that kind to see if any is special. This is a part of a stronger but -- less precise property that tiles that look the same can't be -- distinguished by player actions (but may behave differently wrt -- dungeon generation, AI preferences, etc.). tvalidate :: [TileKind] -> [TileKind] instance Show TileKind -- | The type of game rule sets and assorted game data. module Game.LambdaHack.Content.RuleKind -- | The type of game rule sets and assorted game data. -- -- For now the rules are immutable througout the game, so there is no -- type Rule to hold any changing parameters, just -- RuleKind for the fixed set. However, in the future, if the -- rules can get changed during gameplay based on data mining of player -- behaviour, we may add such a type and then RuleKind will -- become just a starting template, analogously as for the other content. -- -- The raccessible field holds a predicate that tells whether -- one position is accessible from another. Precondition: the two -- positions are next to each other. data RuleKind RuleKind :: Char -> Text -> Freqs -> (X -> Point -> TileKind -> Point -> TileKind -> Bool) -> Text -> (FilePath -> IO FilePath) -> Version -> [Char] -> [Char] -> String -> String -> Text -> RuleKind -- | a symbol rsymbol :: RuleKind -> Char -- | short description rname :: RuleKind -> Text -- | frequency within groups rfreq :: RuleKind -> Freqs raccessible :: RuleKind -> X -> Point -> TileKind -> Point -> TileKind -> Bool -- | the title of the game rtitle :: RuleKind -> Text -- | the path to data files rpathsDataFile :: RuleKind -> FilePath -> IO FilePath -- | the version of the game rpathsVersion :: RuleKind -> Version -- | symbols of melee weapons ritemMelee :: RuleKind -> [Char] -- | symbols of items AI can project ritemProject :: RuleKind -> [Char] -- | the default game rules config file rcfgRulesDefault :: RuleKind -> String -- | the default UI settings config file rcfgUIDefault :: RuleKind -> String -- | the ASCII art for the Main Menu rmainMenuArt :: RuleKind -> Text -- | Validates the ASCII art format (TODO). ruvalidate :: [RuleKind] -> [RuleKind] instance Show RuleKind -- | Re-export the operations of the chosen raw frontend (determined at -- compile time with cabal flags). module Game.LambdaHack.Frontend.Chosen -- | Session data maintained by the frontend. data FrontendSession -- | Starts GTK. The other threads have to be spawned after gtk is -- initialized, because they call postGUIAsync, and need -- sview and stags. Because of Windows, GTK needs to be -- on a bound thread, so we can't avoid the communication overhead of -- bound threads, so there's no point spawning a separate thread for GTK. startup :: String -> (FrontendSession -> IO ()) -> IO () -- | The name of the frontend. frontendName :: String -- | Display a prompt, wait for any key. Starts in Push or None mode, stop -- in None mode. promptGetAnyKey :: FrontendSession -> SingleFrame -> IO KM -- | Add a frame to be drawn. display :: FrontendSession -> Bool -> Maybe SingleFrame -> IO () -- | Operations on the Area type that involve random numbers. module Game.LambdaHack.Server.DungeonGen.AreaRnd -- | Pick a random point within an area. xyInArea :: Area -> Rnd PointXY -- | Create a random room according to given parameters. mkRoom :: (X, Y) -> Area -> Rnd Area -- | Create a void room, i.e., a single point area. mkVoidRoom :: Area -> Rnd Area -- | Pick a subset of connections between adjacent areas within a grid -- until there is only one connected component in the graph of all areas. connectGrid :: (X, Y) -> Rnd [(PointXY, PointXY)] -- | Pick a single random connection between adjacent areas within a grid. randomConnection :: (X, Y) -> Rnd (PointXY, PointXY) -- | The coordinates of consecutive fields of a corridor. type Corridor = [PointXY] -- | Try to connect two places with a corridor. Choose entrances at least 4 -- or 3 tiles distant from the edges, if the place is big enough. Note -- that with pfence == FNone, the area considered is the -- interior of the place, without the outermost tiles. connectPlaces :: Area -> Area -> Rnd Corridor -- | DFOV (Digital Field of View) implemented according to specification at -- http://roguebasin.roguelikedevelopment.org/index.php?title=Digital_field_of_view_implementation. -- This fast version of the algorithm, based on PFOV, has AFAIK -- never been described nor implemented before. module Game.LambdaHack.Server.Fov.Digital -- | Calculates the list of tiles, in Bump coordinates, visible -- from (0, 0), within the given sight range. scan :: Distance -> (Bump -> Bool) -> [Bump] -- | Create a line from two points. Debug: check if well-defined. dline :: Bump -> Bump -> Line -- | Compare steepness of (p1, f) and (p2, f). Debug: -- Verify that the results of 2 independent checks are equal. dsteeper :: Bump -> Bump -> Bump -> Bool -- | The X coordinate, represented as a fraction, of the intersection of a -- given line and the line of diagonals of diamonds at distance -- d from (0, 0). intersect :: Line -> Distance -> (Int, Int) -- | Debug functions for DFOV: -- -- Debug: calculate steeper for DFOV in another way and compare results. debugSteeper :: Bump -> Bump -> Bump -> Bool -- | Debug: check is a view border line for DFOV is legal. debugLine :: Line -> (Bool, String) -- | PFOV (Permissive Field of View) clean-room reimplemented based on the -- algorithm described in -- http://roguebasin.roguelikedevelopment.org/index.php?title=Precise_Permissive_Field_of_View, -- though the general structure is more influenced by recursive shadow -- casting, as implemented in Shadow.hs. In the result, this algorithm is -- much faster than the original algorithm on dense maps, since it does -- not scan areas blocked by shadows. module Game.LambdaHack.Server.Fov.Permissive -- | Calculates the list of tiles, in Bump coordinates, visible -- from (0, 0). scan :: (Bump -> Bool) -> [Bump] -- | Create a line from two points. Debug: check if well-defined. dline :: Bump -> Bump -> Line -- | Compare steepness of (p1, f) and (p2, f). Debug: -- Verify that the results of 2 independent checks are equal. dsteeper :: Bump -> Bump -> Bump -> Bool -- | The Y coordinate, represented as a fraction, of the intersection of a -- given line and the line of diagonals of squares at distance d -- from (0, 0). intersect :: Line -> Distance -> (Int, Int) -- | Debug functions for PFOV: -- -- Debug: calculate steeper for PFOV in another way and compare results. debugSteeper :: Bump -> Bump -> Bump -> Bool -- | Debug: checks postconditions of borderLine. debugLine :: Line -> (Bool, String) -- | A restrictive variant of Recursive Shadow Casting FOV with infinite -- range. It's not designed for dungeons with diagonal walls and so here -- they block visibility, though they don't block movement. The main -- advantage of the algorithm is that it's very simple and fast. module Game.LambdaHack.Server.Fov.Shadow -- | Rotated and translated coordinates of 2D points, so that they fit in -- the same single octant area. type SBump = (Progress, Distance) -- | The area left to be scanned, delimited by fractions of the original -- arc. Interval (0, 1) means the whole 45 degrees arc of the -- processed octant is to be scanned. type Interval = (Rational, Rational) -- | Calculates the list of tiles, in SBump coordinates, visible -- from (0, 0). scan :: (SBump -> Bool) -> Distance -> Interval -> [SBump] -- | General content types and operations. module Game.LambdaHack.Common.Kind -- | Content identifiers for the content type c. data Id c sentinelId :: Id c -- | Type family for auxiliary data structures for speeding up content -- operations. -- | Content operations for the content of type a. data Ops a Ops :: (Id a -> Char) -> (Id a -> Text) -> (Id a -> a) -> (Text -> Id a) -> (Text -> (a -> Bool) -> Rnd (Id a)) -> (forall b. (Id a -> a -> b -> b) -> b -> b) -> (Id a, Id a) -> Speedup a -> Ops a -- | the symbol of a content element at id osymbol :: Ops a -> Id a -> Char -- | the name of a content element at id oname :: Ops a -> Id a -> Text -- | the content element at given id okind :: Ops a -> Id a -> a -- | the id of the unique member of a singleton content group ouniqGroup :: Ops a -> Text -> Id a -- | pick a random id belonging to a group and satisfying a predicate opick :: Ops a -> Text -> (a -> Bool) -> Rnd (Id a) -- | fold over all content elements of a ofoldrWithKey :: Ops a -> forall b. (Id a -> a -> b -> b) -> b -> b -- | bounds of identifiers of content a obounds :: Ops a -> (Id a, Id a) -- | auxiliary speedup components ospeedup :: Ops a -> Speedup a -- | Operations for all content types, gathered together. data COps COps :: !(Ops ActorKind) -> !(Ops CaveKind) -> !(Ops FactionKind) -> !(Ops ItemKind) -> !(Ops PlaceKind) -> !(Ops RuleKind) -> !(Ops StrategyKind) -> !(Ops TileKind) -> COps coactor :: COps -> !(Ops ActorKind) cocave :: COps -> !(Ops CaveKind) cofact :: COps -> !(Ops FactionKind) coitem :: COps -> !(Ops ItemKind) coplace :: COps -> !(Ops PlaceKind) corule :: COps -> !(Ops RuleKind) costrat :: COps -> !(Ops StrategyKind) cotile :: COps -> !(Ops TileKind) -- | Create content operations for type a from definition of -- content of type a. createOps :: Show a => ContentDef a -> Ops a -- | The standard ruleset used for level operations. stdRuleset :: Ops RuleKind -> RuleKind -- | Arrays of content identifiers pointing to the content type c, -- where the identifiers are represented as Word8 (and so -- content of type c can have at most 256 elements). The arrays -- are indexed by type i, e.g., a dungeon tile position. data Array i c -- | Content identifiers array lookup. (!) :: Ix i => Array i c -> i -> Id c -- | Construct a content identifiers array updated with the association -- list. (//) :: Ix i => Array i c -> [(i, Id c)] -> Array i c -- | Create a content identifiers array from a list of elements. listArray :: Ix i => (i, i) -> [Id c] -> Array i c -- | Create a content identifiers array from an association list. array :: Ix i => (i, i) -> [(i, Id c)] -> Array i c -- | Content identifiers array bounds. bounds :: Ix i => Array i c -> (i, i) -- | Fold left strictly over an array. foldlArray :: Ix i => (a -> Id c -> a) -> a -> Array i c -> a instance Show (Id c) instance Eq (Id c) instance Ord (Id c) instance Ix (Id c) instance Enum (Id c) instance Ix i => Eq (Array i c) instance (Ix i, Show i) => Show (Array i c) instance (Ix i, Binary i) => Binary (Array i c) instance Eq COps instance Show COps instance Binary (Id c) -- | Weapons, treasure and all the other items in the game. No operation in -- this module involves the State or Action type. TODO: -- Document after it's rethought and rewritten wrt separating inventory -- manangement and items proper. module Game.LambdaHack.Common.Item -- | A unique identifier of an item in the dungeon. data ItemId -- | Game items in inventories or strewn around the dungeon. The fields -- jsymbol, jname and jflavour make it -- possible to refer to and draw an unidentified item. Full information -- about item is available through the jkindIx index as soon as -- the item is identified. data Item Item :: !ItemKindIx -> !Char -> !Text -> !Flavour -> !(Effect Int) -> Item -- | index pointing to the kind of the item jkindIx :: Item -> !ItemKindIx -- | individual map symbol jsymbol :: Item -> !Char -- | individual generic name jname :: Item -> !Text -- | individual flavour jflavour :: Item -> !Flavour -- | the effect when activated jeffect :: Item -> !(Effect Int) -- | Recover a kind id of an item, if identified. jkind :: Discovery -> Item -> Maybe (Id ItemKind) -- | Build an item with the given stats. buildItem :: FlavourMap -> DiscoRev -> Id ItemKind -> ItemKind -> Effect Int -> Item -- | Generate an item based on level. newItem :: Ops ItemKind -> FlavourMap -> DiscoRev -> Int -> Int -> Rnd (Item, Int, ItemKind) -- | Represent an item on the map. viewItem :: Item -> (Char, Color) strongestSearch :: [(ItemId, Item)] -> Maybe (Int, (ItemId, Item)) strongestSword :: COps -> [(ItemId, Item)] -> Maybe (Int, (ItemId, Item)) strongestRegen :: [(ItemId, Item)] -> Maybe (Int, (ItemId, Item)) -- | An index of the kind id of an item. Clients have partial knowledge how -- these idexes map to kind ids. They gain knowledge by identifying -- items. data ItemKindIx -- | The map of item kind indexes to item kind ids. The full map, as known -- by the server, is a bijection. type Discovery = EnumMap ItemKindIx (Id ItemKind) -- | The reverse map to Discovery, needed for item creation. type DiscoRev = EnumMap (Id ItemKind) ItemKindIx serverDiscos :: Ops ItemKind -> Rnd (Discovery, DiscoRev) -- | Flavours assigned by the server to item kinds, in this particular -- game. data FlavourMap emptyFlavourMap :: FlavourMap -- | Randomly chooses flavour for all item kinds for this game. dungeonFlavourMap :: Ops ItemKind -> Rnd FlavourMap -- | The part of speech describing the item. partItem :: Ops ItemKind -> Discovery -> Item -> (Part, Part) partItemWs :: Ops ItemKind -> Discovery -> Int -> Item -> Part partItemAW :: Ops ItemKind -> Discovery -> Item -> Part instance Show ItemId instance Eq ItemId instance Ord ItemId instance Enum ItemId instance Binary ItemId instance Show ItemKindIx instance Eq ItemKindIx instance Ord ItemKindIx instance Enum ItemKindIx instance Ix ItemKindIx instance Hashable ItemKindIx instance Binary ItemKindIx instance Show Item instance Eq Item instance Ord Item instance Generic Item instance Show FlavourMap instance Binary FlavourMap instance Datatype D1Item instance Constructor C1_0Item instance Selector S1_0_0Item instance Selector S1_0_1Item instance Selector S1_0_2Item instance Selector S1_0_3Item instance Selector S1_0_4Item instance Binary Item instance Hashable Item -- | Actors in the game: heroes, monsters, etc. No operation in this module -- involves the State or Action type. module Game.LambdaHack.Common.Actor -- | A unique identifier of an actor in the dungeon. data ActorId -- | Chance that a new monster is generated. Currently depends on the -- number of monsters already present, and on the level. In the future, -- the strength of the character and the strength of the monsters present -- could further influence the chance, and the chance could also affect -- which monster is generated. How many and which monsters are generated -- will also depend on the cave kind used to build the level. monsterGenChance :: Int -> Int -> Int -> Rnd Bool -- | The part of speech describing the actor. partActor :: Ops ActorKind -> Actor -> Part -- | Actor properties that are changing throughout the game. If they are -- dublets of properties from ActorKind, they are usually -- modified temporarily, but tend to return to the original value from -- ActorKind over time. E.g., HP. data Actor Actor :: !(Id ActorKind) -> !(Maybe Char) -> !(Maybe Text) -> !(Maybe Color) -> !(Maybe Speed) -> !Int -> !(Maybe [Vector]) -> !Point -> !Point -> !LevelId -> !ItemBag -> !ItemInv -> !InvChar -> !Time -> !Time -> !FactionId -> !Bool -> Actor -- | the kind of the actor bkind :: Actor -> !(Id ActorKind) -- | individual map symbol bsymbol :: Actor -> !(Maybe Char) -- | individual name _bname :: Actor -> !(Maybe Text) -- | individual map color bcolor :: Actor -> !(Maybe Color) -- | individual speed bspeed :: Actor -> !(Maybe Speed) -- | current hit points bhp :: Actor -> !Int -- | path the actor is forced to travel bpath :: Actor -> !(Maybe [Vector]) -- | current position bpos :: Actor -> !Point -- | previous position boldpos :: Actor -> !Point -- | current level blid :: Actor -> !LevelId -- | items carried bbag :: Actor -> !ItemBag -- | map from letters to items binv :: Actor -> !ItemInv -- | next inventory letter bletter :: Actor -> !InvChar -- | absolute time of next action btime :: Actor -> !Time -- | last bracing expires at this time bwait :: Actor -> !Time -- | to which faction the actor belongs bfid :: Actor -> !FactionId -- | is a projectile? (shorthand only, this can be deduced from bkind) bproj :: Actor -> !Bool -- | A template for a new non-projectile actor. actorTemplate :: Id ActorKind -> Maybe Char -> Maybe Text -> Maybe Color -> Maybe Speed -> Int -> Maybe [Vector] -> Point -> LevelId -> Time -> FactionId -> Bool -> Actor -- | Add time taken by a single step at the actor's current speed. timeAddFromSpeed :: Ops ActorKind -> Actor -> Time -> Time -- | Whether an actor is braced for combat this turn. braced :: Actor -> Time -> Bool -- | Checks for the presence of actors in a position. Does not check if the -- tile is walkable. unoccupied :: [Actor] -> Point -> Bool -- | The unique kind of heroes. heroKindId :: Ops ActorKind -> Id ActorKind -- | The unique kind of projectiles. projectileKindId :: Ops ActorKind -> Id ActorKind -- | Access actor speed, individual or, otherwise, stock. actorSpeed :: Ops ActorKind -> Actor -> Speed type ItemBag = EnumMap ItemId Int type ItemInv = EnumMap InvChar ItemId newtype InvChar InvChar :: Char -> InvChar invChar :: InvChar -> Char -- | All items in the dungeon (including in actor inventories), indexed by -- item identifier. type ItemDict = EnumMap ItemId Item -- | Reverse item map, for item creation, to keep items and item -- identifiers in bijection. type ItemRev = HashMap Item ItemId allLetters :: [InvChar] -- | Assigns a letter to an item, for inclusion in the inventory of a hero. -- Tries to to use the requested letter, if any. assignLetter :: ItemId -> Maybe InvChar -> Actor -> Maybe InvChar letterLabel :: InvChar -> Part letterRange :: [InvChar] -> Text rmFromBag :: Int -> ItemId -> ItemBag -> ItemBag -- | All actors on the level, indexed by actor identifier. type ActorDict = EnumMap ActorId Actor -- | How long until an actor's smell vanishes from a tile. smellTimeout :: Time mapActorItems_ :: Monad m => (ItemId -> Int -> m a) -> Actor -> m () instance Show ActorId instance Eq ActorId instance Ord ActorId instance Enum ActorId instance Show InvChar instance Eq InvChar instance Enum InvChar instance Show Actor instance Eq Actor instance Ord Actor instance Binary Actor instance (Binary k, Binary v, Eq k, Hashable k) => Binary (HashMap k v) instance Binary InvChar instance Ord InvChar instance Binary ActorId -- | Operations concerning dungeon level tiles. -- -- Unlike for many other content types, there is no type Tile, -- of particular concrete tiles in the dungeon, corresponding to -- TileKind (the type of kinds of terrain tiles). This is because -- the tiles are too numerous and there's not enough storage space for a -- well-rounded Tile type, on one hand, and on the other hand, -- tiles are accessed too often in performance critical code to try to -- compress their representation and/or recompute them. Instead, of -- defining a Tile type, we express various properties of -- concrete tiles by arrays or sparse EnumMaps, as appropriate. -- -- Actors at normal speed (2 m/s) take one turn to move one tile (1 m by -- 1 m). module Game.LambdaHack.Common.Tile -- | The last time a hero left a smell in a given tile. To be used by -- monsters that hunt by smell. type SmellTime = Time -- | Whether a tile kind has the given feature. kindHasFeature :: Feature -> TileKind -> Bool -- | Whether a tile kind has all features of the first set and no features -- of the second. kindHas :: [Feature] -> [Feature] -> TileKind -> Bool -- | Whether a tile kind (specified by its id) has the given feature. hasFeature :: Ops TileKind -> Feature -> Id TileKind -> Bool -- | Whether a tile does not block vision. Essential for efficiency of -- FOV, hence tabulated. isClear :: Ops TileKind -> Id TileKind -> Bool -- | Whether a tile is lit on its own. Essential for efficiency of -- Perception, hence tabulated. isLit :: Ops TileKind -> Id TileKind -> Bool -- | Whether a tile can be explored, possibly yielding a treasure or a -- hidden message. We exclude doors and hidden features. isExplorable :: Ops TileKind -> Id TileKind -> Bool -- | The player can't tell one tile from the other. similar :: TileKind -> TileKind -> Bool speedup :: Bool -> Ops TileKind -> Speedup TileKind changeTo :: Ops TileKind -> Id TileKind -> Rnd (Id TileKind) hiddenAs :: Ops TileKind -> Id TileKind -> Id TileKind -- | Inhabited dungeon levels and the operations to query and change them -- as the game progresses. module Game.LambdaHack.Common.Level -- | Abstract level identifiers. data LevelId -- | The complete dungeon is a map from level names to levels. type Dungeon = EnumMap LevelId Level -- | Levels in the current branch, k levels shallower than the -- current. ascendInBranch :: Dungeon -> LevelId -> Int -> [LevelId] -- | Item container type. data Container CFloor :: LevelId -> Point -> Container CActor :: ActorId -> InvChar -> Container -- | Current smell on map tiles. type SmellMap = EnumMap Point SmellTime -- | Items located on map tiles. type ItemFloor = EnumMap Point ItemBag -- | Tile kinds on the map. type TileMap = Array Point TileKind -- | A view on single, inhabited dungeon level. Remembered fields -- carry a subset of the info in the client copies of levels. data Level Level :: !Int -> !ActorPrio -> !ItemFloor -> !TileMap -> !X -> !Y -> !SmellMap -> !Text -> !(Point, Point) -> !Int -> !Int -> !Time -> !Int -> !Int -> !Int -> Level -- | depth of the level ldepth :: Level -> !Int -- | remembered actor times on the level lprio :: Level -> !ActorPrio -- | remembered items lying on the floor lfloor :: Level -> !ItemFloor -- | remembered level map ltile :: Level -> !TileMap -- | width of the level lxsize :: Level -> !X -- | height of the level lysize :: Level -> !Y -- | remembered smells on the level lsmell :: Level -> !SmellMap -- | level description ldesc :: Level -> !Text -- | destination of (up, down) stairs lstair :: Level -> !(Point, Point) -- | currently remembered clear tiles lseen :: Level -> !Int -- | total number of initially clear tiles lclear :: Level -> !Int -- | date of the last activity on the level ltime :: Level -> !Time -- | number of initial items, 0 for clients litemNum :: Level -> !Int -- | secret level seed, unknown by clients lsecret :: Level -> !Int -- | secret tile density, unknown by clients lhidden :: Level -> !Int -- | Update the actor time priority queue. updatePrio :: (ActorPrio -> ActorPrio) -> Level -> Level -- | Update the smell map. updateSmell :: (SmellMap -> SmellMap) -> Level -> Level -- | Update the items on the ground map. updateFloor :: (ItemFloor -> ItemFloor) -> Level -> Level -- | Update the tile map. updateTile :: (TileMap -> TileMap) -> Level -> Level -- | Query for tile kinds on the map. at :: Level -> Point -> Id TileKind -- | Query for items on the ground. atI :: Level -> Point -> ItemBag -- | Check whether one position is accessible from another, using the -- formula from the standard ruleset. Precondition: the two positions are -- next to each other. accessible :: COps -> Level -> Point -> Point -> Bool -- | Check whether actors can move from a position along a unit vector, -- using the formula from the standard ruleset. accessibleDir :: COps -> Level -> Point -> Vector -> Bool hideTile :: Ops TileKind -> Point -> Level -> Id TileKind -- | Find a random position on the map satisfying a predicate. findPos :: TileMap -> (Point -> Id TileKind -> Bool) -> Rnd Point -- | Try to find a random position on the map satisfying the conjunction of -- the list of predicates. If the permitted number of attempts is not -- enough, try again the same number of times without the first -- predicate, then without the first two, etc., until only one predicate -- remains, at which point try as many times, as needed. findPosTry :: Int -> TileMap -> [Point -> Id TileKind -> Bool] -> Rnd Point mapLevelActors_ :: Monad m => (ActorId -> m a) -> Level -> m () mapDungeonActors_ :: Monad m => (ActorId -> m a) -> Dungeon -> m () instance Show Container instance Eq Container instance Ord Container instance Generic Container instance Show Level instance Eq Level instance Datatype D1Container instance Constructor C1_0Container instance Constructor C1_1Container instance Binary Level instance Binary Container -- | Abstract syntax of server commands. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Common.ServerCmd -- | Abstract syntax of server commands. data CmdSer MoveSer :: ActorId -> Vector -> CmdSer ExploreSer :: ActorId -> Vector -> CmdSer RunSer :: ActorId -> Vector -> CmdSer WaitSer :: ActorId -> CmdSer PickupSer :: ActorId -> ItemId -> Int -> InvChar -> CmdSer DropSer :: ActorId -> ItemId -> CmdSer ProjectSer :: ActorId -> Point -> Int -> ItemId -> Container -> CmdSer ApplySer :: ActorId -> ItemId -> Container -> CmdSer TriggerSer :: ActorId -> Point -> CmdSer SetPathSer :: ActorId -> [Vector] -> CmdSer GameRestartSer :: ActorId -> Text -> CmdSer GameExitSer :: ActorId -> CmdSer GameSaveSer :: ActorId -> CmdSer CfgDumpSer :: ActorId -> CmdSer -- | The actor performing the command, if still alive afterwards. aidCmdSer :: CmdSer -> ActorId instance Show CmdSer -- | Generation of places from place kinds. module Game.LambdaHack.Server.DungeonGen.Place -- | The map of tile kinds in a place (and generally anywhere in a cave). -- The map is sparse. The default tile that eventually fills the empty -- spaces is specified in the cave kind specification with -- cdefTile. type TileMapXY = EnumMap PointXY (Id TileKind) -- | The parameters of a place. Most are immutable and set at the time when -- a place is generated. data Place Place :: !(Id PlaceKind) -> !Area -> !Bool -> !Text -> !(Id TileKind) -> !(Id TileKind) -> Place qkind :: Place -> !(Id PlaceKind) qarea :: Place -> !Area qseen :: Place -> !Bool qlegend :: Place -> !Text qsolidFence :: Place -> !(Id TileKind) qhollowFence :: Place -> !(Id TileKind) -- | For CAlternate tiling, require the place be comprised of an -- even number of whole corners, with exactly one square overlap between -- consecutive coners and no trimming. For other tiling methods, check -- that the area is large enough for tiling the corner twice in each -- direction, with a possible one row/column overlap. placeValid :: Area -> PlaceKind -> Bool -- | Construct a fence around an area, with the given tile kind. buildFence :: Id TileKind -> Area -> TileMapXY -- | Given a few parameters, roll and construct a Place -- datastructure and fill a cave section acccording to it. buildPlace :: COps -> CaveKind -> Id TileKind -> Int -> Int -> Area -> Rnd (TileMapXY, Place) instance Show Place instance Binary Place -- | Generation of caves (not yet inhabited dungeon levels) from cave -- kinds. module Game.LambdaHack.Server.DungeonGen.Cave -- | The map of tile kinds in a cave. The map is sparse. The default tile -- that eventually fills the empty spaces is specified in the cave kind -- specification with cdefTile. type TileMapXY = TileMapXY -- | The map of starting items in tiles of a cave. The map is sparse. -- Unspecified tiles have no starting items. type ItemFloorXY = EnumMap PointXY (Item, Int) -- | The type of caves (not yet inhabited dungeon levels). data Cave Cave :: !(Id CaveKind) -> TileMapXY -> ItemFloorXY -> [Place] -> Cave -- | the kind of the cave dkind :: Cave -> !(Id CaveKind) -- | tile kinds in the cave dmap :: Cave -> TileMapXY -- | starting items in the cave ditem :: Cave -> ItemFloorXY -- | places generated in the cave dplaces :: Cave -> [Place] -- | Cave generation by an algorithm inspired by the original Rogue, buildCave :: COps -> Int -> Int -> Id CaveKind -> Rnd Cave instance Show Cave -- | Factions taking part in the game: e.g., two human players controlling -- the hero faction battling the monster and the animal factions. module Game.LambdaHack.Common.Faction -- | A unique identifier of a faction in a game. data FactionId -- | All factions in the game, indexed by faction identifier. type FactionDict = EnumMap FactionId Faction data Faction Faction :: !(Id FactionKind) -> !Text -> !Text -> !(Maybe (Id StrategyKind)) -> !(Maybe (Id StrategyKind)) -> !Dipl -> !(Maybe Status) -> !(Maybe ActorId) -> !Color -> !Int -> !LevelId -> Faction -- | the kind of the faction gkind :: Faction -> !(Id FactionKind) -- | individual name gname :: Faction -> !Text -- | raw name specified in config gconfig :: Faction -> !Text -- | AI for the leaders; Nothing means human-controlled gAiLeader :: Faction -> !(Maybe (Id StrategyKind)) -- | AI to use for other actors; Nothing means human-controlled gAiMember :: Faction -> !(Maybe (Id StrategyKind)) -- | diplomatic mode gdipl :: Faction -> !Dipl -- | cause of game end/exit gquit :: Faction -> !(Maybe Status) gleader :: Faction -> !(Maybe ActorId) -- | color of actors or their frames gcolor :: Faction -> !Color -- | number of initial actors ginitial :: Faction -> !Int -- | level where initial actors start gentry :: Faction -> !LevelId -- | Diplomacy states. Higher overwrite lower in case of assymetric -- content. data Diplomacy Unknown :: Diplomacy Neutral :: Diplomacy Alliance :: Diplomacy War :: Diplomacy -- | Outcome of a game. data Outcome -- | the faction was eliminated Killed :: Outcome -- | the faction lost the game in another way Defeated :: Outcome -- | game is supended Camping :: Outcome -- | the player won by eliminating all rivals Conquer :: Outcome -- | the player escaped the dungeon alive Escape :: Outcome -- | game is restarted Restart :: Outcome -- | Current game status. data Status Status :: Outcome -> Int -> Text -> Status -- | current game outcome stOutcome :: Status -> Outcome -- | depth of the final encounter stDepth :: Status -> Int -- | extra information stInfo :: Status -> Text -- | Tell whether the faction is controlled (at least partially) by a -- human. isHumanFact :: Faction -> Bool -- | Tell whether the faction uses AI to control any of its actors. usesAIFact :: Faction -> Bool -- | Tell whether the faction can spawn actors. isSpawnFact :: COps -> Faction -> Bool -- | Tell whether actors of the faction can be summoned by items, etc.. isSummonFact :: COps -> Faction -> Bool -- | Check if factions are at war. Assumes symmetry. isAtWar :: Faction -> FactionId -> Bool -- | Check if factions are allied. Assumes symmetry. isAllied :: Faction -> FactionId -> Bool instance Show Diplomacy instance Eq Diplomacy instance Ord Diplomacy instance Show Outcome instance Eq Outcome instance Ord Outcome instance Show Status instance Eq Status instance Ord Status instance Show Faction instance Eq Faction instance Binary Status instance Binary Outcome instance Binary Diplomacy instance Binary Faction -- | Display game data on the screen and receive user input using one of -- the available raw frontends and derived operations. module Game.LambdaHack.Frontend -- | The name of the frontend. frontendName :: String startupF :: String -> IO () -> IO () -- | Augment a function that takes and returns keys. getConfirmGeneric :: Monad m => ([KM] -> a -> m KM) -> [KM] -> a -> m Bool type ChanFrontend = TQueue KM data FrontReq -- | show a frame, if the fid acitve, or save it to the client's queue FrontFrame :: !AcFrame -> FrontReq frontAc :: FrontReq -> !AcFrame -- | flush frames, possibly show fadeout/fadein and ask for a keypress FrontKey :: ![KM] -> !SingleFrame -> FrontReq frontKM :: FrontReq -> ![KM] frontFr :: FrontReq -> !SingleFrame -- | show a whole slideshow without interleaving with other clients FrontSlides :: [KM] -> [SingleFrame] -> FrontReq frontClear :: FrontReq -> [KM] frontSlides :: FrontReq -> [SingleFrame] -- | Multiplex connection channels, for the case of a frontend shared among -- clients. This is transparent to the clients themselves. data ConnMulti ConnMulti :: FromMulti -> ToMulti -> ConnMulti fromMulti :: ConnMulti -> FromMulti toMulti :: ConnMulti -> ToMulti connMulti :: ConnMulti loopFrontend :: FrontendSession -> ConnMulti -> IO () -- | High score table operations. module Game.LambdaHack.Common.HighScore -- | The list of scores, in decreasing order. data ScoreTable -- | Empty score table empty :: ScoreTable -- | Register a new score in a score table. register :: ScoreTable -> Int -> Time -> Status -> ClockTime -> Maybe (ScoreTable, Int) -- | Generate a slideshow with the current and previous scores. slideshow :: ScoreTable -> Int -> Status -> Slideshow instance Eq ScoreRecord instance Ord ScoreRecord instance Eq ScoreTable instance Binary ScoreTable instance Binary ScoreRecord instance Show ScoreTable -- | Server and client game state types and operations. module Game.LambdaHack.Common.State -- | View on game state. Remembered fields carry a subset of the -- info in the client copies of the state. Clients never directly change -- their State, but apply atomic actions sent by the server to -- do so. data State sdungeon :: State -> Dungeon sdepth :: State -> Int sactorD :: State -> ActorDict sitemD :: State -> ItemDict sfactionD :: State -> FactionDict stime :: State -> Time scops :: State -> COps shigh :: State -> ScoreTable -- | Initial complete global game state. defStateGlobal :: Dungeon -> Int -> FactionDict -> COps -> ScoreTable -> State -- | Initial empty state. emptyState :: State -- | Local state created by removing secret information from global state -- components. localFromGlobal :: State -> State -- | Update dungeon data within state. updateDungeon :: (Dungeon -> Dungeon) -> State -> State -- | Update dungeon depth. updateDepth :: (Int -> Int) -> State -> State -- | Update the actor dictionary. updateActorD :: (ActorDict -> ActorDict) -> State -> State -- | Update the item dictionary. updateItemD :: (ItemDict -> ItemDict) -> State -> State -- | Update faction data within state. updateFaction :: (FactionDict -> FactionDict) -> State -> State -- | Update global time within state. updateTime :: (Time -> Time) -> State -> State -- | Update content data within state. updateCOps :: (COps -> COps) -> State -> State -- | Get current time from the dungeon data. getLocalTime :: LevelId -> State -> Time -- | Tell whether the faction is controlled (at least partially) by a -- human. isHumanFaction :: FactionId -> State -> Bool -- | Tell whether the faction uses AI to control any of its actors. usesAIFaction :: FactionId -> State -> Bool -- | Tell whether the faction can spawn actors. isSpawnFaction :: FactionId -> State -> Bool -- | Tell whether actors of the faction can be summoned by items, etc.. isSummonFaction :: FactionId -> State -> Bool instance Show State instance Eq State instance Binary State -- | Operations on the Actor type that need the State type, -- but not the Action type. TODO: Document an export list after -- it's rewritten according to #17. module Game.LambdaHack.Common.ActorState actorAssocs :: (FactionId -> Bool) -> LevelId -> State -> [(ActorId, Actor)] actorList :: (FactionId -> Bool) -> LevelId -> State -> [Actor] actorNotProjAssocs :: (FactionId -> Bool) -> LevelId -> State -> [(ActorId, Actor)] actorNotProjList :: (FactionId -> Bool) -> LevelId -> State -> [Actor] -- | Calculate loot's worth for heroes on the current level. -- -- Warning: scores are shown during the game, so when the server -- calculates then, we should be careful not to leak secret information -- (e.g., the nature of the items through the total worth of inventory). calculateTotal :: Actor -> State -> (ItemBag, Int) nearbyFreePoints :: Ops TileKind -> (Id TileKind -> Bool) -> Point -> LevelId -> State -> [Point] -- | Compute the level identifier and starting position on the level, after -- a level change. whereTo :: State -> LevelId -> Int -> Maybe (LevelId, Point) -- | Finds an actor at a position on the current level. Perception -- irrelevant. posToActor :: Point -> LevelId -> State -> Maybe ActorId getItemBody :: ItemId -> State -> Item -- | Checks if the actor is present on the current level. The order of -- argument here and in other functions is set to allow -- --
-- b <- getsState (memActor a) --memActor :: ActorId -> LevelId -> State -> Bool -- | Gets actor body from the current level. Error if not found. getActorBody :: ActorId -> State -> Actor updateActorBody :: ActorId -> (Actor -> Actor) -> State -> State -- | Gets actor's items from the current level. Warning: this does not work -- for viewing items of actors from remote level. getActorItem :: ActorId -> State -> [(ItemId, Item)] getActorBag :: ActorId -> State -> ItemBag actorContainer :: ActorId -> ItemInv -> ItemId -> Container getActorInv :: ActorId -> State -> ItemInv tryFindHeroK :: State -> FactionId -> Int -> Maybe (ActorId, Actor) foesAdjacent :: X -> Y -> Point -> [Actor] -> Bool -- | Actors perceiving other actors and the dungeon level. module Game.LambdaHack.Common.Perception -- | The type representing the perception of a faction on a level. The -- total visibility holds the sum of FOVs of all actors of a given -- faction on the level and serves only as a speedup. The fields are not -- strict because often not all are used. data Perception Perception :: PerActor -> PerceptionVisible -> PerceptionVisible -> Perception -- | visible points for each actor perActor :: Perception -> PerActor -- | sum over all actors ptotal :: Perception -> PerceptionVisible -- | sum over actors that can smell psmell :: Perception -> PerceptionVisible newtype PerceptionVisible PerceptionVisible :: EnumSet Point -> PerceptionVisible pvisible :: PerceptionVisible -> EnumSet Point type PerActor = EnumMap ActorId PerceptionVisible -- | The set of tiles visible by at least one hero. totalVisible :: Perception -> EnumSet Point -- | The set of tiles smelled by at least one hero. smellVisible :: Perception -> EnumSet Point -- | Whether an actor can see a position. actorSeesLoc :: Perception -> ActorId -> Point -> Bool nullPer :: Perception -> Bool addPer :: Perception -> Perception -> Perception diffPer :: Perception -> Perception -> Perception smellFromActors :: COps -> State -> PerActor -> PerceptionVisible -- | Perception of a single faction, indexed by level identifier. type FactionPers = EnumMap LevelId Perception -- | Perception indexed by faction identifier. This can't be added to -- FactionDict, because clients can't see it. type Pers = EnumMap FactionId FactionPers instance Show PerceptionVisible instance Eq PerceptionVisible instance Binary PerceptionVisible instance Show Perception instance Eq Perception instance Generic Perception instance Datatype D1Perception instance Constructor C1_0Perception instance Selector S1_0_0Perception instance Selector S1_0_1Perception instance Selector S1_0_2Perception instance Binary Perception -- | Field Of View scanning with a variety of algorithms. See -- https://github.com/kosmikus/LambdaHack/wiki/Fov-and-los for -- discussion. module Game.LambdaHack.Server.Fov -- | Calculate the perception of the whole dungeon. dungeonPerception :: COps -> FovMode -> State -> Pers -- | Calculate perception of the level. levelPerception :: COps -> State -> FovMode -> FactionId -> LevelId -> Level -> Perception -- | Perform a full scan for a given position. Returns the positions that -- are currently in the field of view. The Field of View algorithm to -- use, passed in the second argument, is set in the config file. The -- actor's own position is considred reachable by him. fullscan :: Ops TileKind -> FovMode -> Point -> Level -> [Point] -- | Field Of View scanning mode. data FovMode -- | restrictive shadow casting Shadow :: FovMode -- | permissive FOV Permissive :: FovMode -- | digital FOV with the given radius Digital :: Int -> FovMode -- | only feeling out adjacent tiles by touch Blind :: FovMode instance Show PerceptionReachable instance Show FovMode instance Read FovMode instance Binary FovMode -- | Personal game configuration file type definitions. module Game.LambdaHack.Server.Config -- | Fully typed contents of the rules config file. This config is a part -- of the game server. data Config Config :: !String -> !(Map Text Caves) -> !Bool -> !FovMode -> !Int -> !FilePath -> !FilePath -> !FilePath -> ![(Int, Text)] -> !(Map Text Players) -> !(Map Text Scenario) -> Config configSelfString :: Config -> !String configCaves :: Config -> !(Map Text Caves) configFirstDeathEnds :: Config -> !Bool configFovMode :: Config -> !FovMode configSaveBkpClips :: Config -> !Int configAppDataDir :: Config -> !FilePath configScoresFile :: Config -> !FilePath configRulesCfgFile :: Config -> !FilePath configHeroNames :: Config -> ![(Int, Text)] configPlayers :: Config -> !(Map Text Players) configScenario :: Config -> !(Map Text Scenario) type Caves = EnumMap LevelId (Text, Bool) data Players Players :: [Player] -> [Player] -> [(Text, Text)] -> [(Text, Text)] -> Players playersHuman :: Players -> [Player] playersComputer :: Players -> [Player] playersEnemy :: Players -> [(Text, Text)] playersAlly :: Players -> [(Text, Text)] data Player Player :: Text -> Text -> Int -> LevelId -> Player playerName :: Player -> Text playerKind :: Player -> Text playerInitial :: Player -> Int playerEntry :: Player -> LevelId data Scenario Scenario :: Text -> Text -> Scenario scenarioPlayers :: Scenario -> Text scenarioDungeon :: Scenario -> Text instance Show Player instance Read Player instance Show Players instance Read Players instance Show Scenario instance Read Scenario instance Show Config instance Binary Config instance NFData Config instance Binary Scenario instance NFData Scenario instance Binary Players instance NFData Players instance Binary Player instance NFData Player -- | Personal game configuration file support. module Game.LambdaHack.Server.Action.ConfigIO -- | Read and parse rules config file and supplement it with random seeds. mkConfigRules :: Ops RuleKind -> IO (Config, StdGen, StdGen) -- | Dumps the current configuration to a file. dump :: Config -> FilePath -> IO () instance Show CP -- | The main dungeon generation routine. module Game.LambdaHack.Server.DungeonGen -- | Freshly generated and not yet populated dungeon. data FreshDungeon FreshDungeon :: !Dungeon -> !Int -> FreshDungeon -- | maps for all levels freshDungeon :: FreshDungeon -> !Dungeon -- | dungeon depth (can be different than size) freshDepth :: FreshDungeon -> !Int -- | Generate the dungeon for a new game. dungeonGen :: COps -> Caves -> Rnd FreshDungeon -- | A set of atomic commands shared by client and server. These are the -- largest building blocks that have no components that can be observed -- in isolation. -- -- We try to make atomic commands respect the laws of energy and mass -- conservation, unless they really can't, e.g., monster spawning. For -- example item removal from inventory is not an atomic command, but item -- dropped from the inventory to the ground is. This makes it easier to -- undo the commands. In principle, the commands are the only way to -- affect the basic game state (State). -- -- See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Common.AtomicCmd data Atomic CmdAtomic :: CmdAtomic -> Atomic SfxAtomic :: SfxAtomic -> Atomic -- | Abstract syntax of atomic commands. data CmdAtomic CreateActorA :: ActorId -> Actor -> [(ItemId, Item)] -> CmdAtomic DestroyActorA :: ActorId -> Actor -> [(ItemId, Item)] -> CmdAtomic CreateItemA :: ItemId -> Item -> Int -> Container -> CmdAtomic DestroyItemA :: ItemId -> Item -> Int -> Container -> CmdAtomic SpotActorA :: ActorId -> Actor -> [(ItemId, Item)] -> CmdAtomic LoseActorA :: ActorId -> Actor -> [(ItemId, Item)] -> CmdAtomic SpotItemA :: ItemId -> Item -> Int -> Container -> CmdAtomic LoseItemA :: ItemId -> Item -> Int -> Container -> CmdAtomic MoveActorA :: ActorId -> Point -> Point -> CmdAtomic WaitActorA :: ActorId -> Time -> Time -> CmdAtomic DisplaceActorA :: ActorId -> ActorId -> CmdAtomic MoveItemA :: ItemId -> Int -> Container -> Container -> CmdAtomic AgeActorA :: ActorId -> Time -> CmdAtomic HealActorA :: ActorId -> Int -> CmdAtomic HasteActorA :: ActorId -> Speed -> CmdAtomic PathActorA :: ActorId -> (Maybe [Vector]) -> (Maybe [Vector]) -> CmdAtomic ColorActorA :: ActorId -> (Maybe Color) -> (Maybe Color) -> CmdAtomic QuitFactionA :: FactionId -> (Maybe Actor) -> (Maybe Status) -> (Maybe Status) -> CmdAtomic LeadFactionA :: FactionId -> (Maybe ActorId) -> (Maybe ActorId) -> CmdAtomic DiplFactionA :: FactionId -> FactionId -> Diplomacy -> Diplomacy -> CmdAtomic AlterTileA :: LevelId -> Point -> (Id TileKind) -> (Id TileKind) -> CmdAtomic SearchTileA :: ActorId -> Point -> (Id TileKind) -> (Id TileKind) -> CmdAtomic SpotTileA :: LevelId -> [(Point, Id TileKind)] -> CmdAtomic LoseTileA :: LevelId -> [(Point, Id TileKind)] -> CmdAtomic AlterSmellA :: LevelId -> Point -> (Maybe Time) -> (Maybe Time) -> CmdAtomic SpotSmellA :: LevelId -> [(Point, Time)] -> CmdAtomic LoseSmellA :: LevelId -> [(Point, Time)] -> CmdAtomic AgeLevelA :: LevelId -> Time -> CmdAtomic AgeGameA :: Time -> CmdAtomic DiscoverA :: LevelId -> Point -> ItemId -> (Id ItemKind) -> CmdAtomic CoverA :: LevelId -> Point -> ItemId -> (Id ItemKind) -> CmdAtomic PerceptionA :: LevelId -> PerActor -> PerActor -> CmdAtomic RestartA :: FactionId -> Discovery -> FactionPers -> State -> Bool -> Text -> CmdAtomic RestartServerA :: State -> CmdAtomic ResumeA :: FactionId -> FactionPers -> CmdAtomic ResumeServerA :: State -> CmdAtomic KillExitA :: FactionId -> CmdAtomic SaveExitA :: CmdAtomic SaveBkpA :: CmdAtomic MsgAllA :: Msg -> CmdAtomic data SfxAtomic StrikeD :: ActorId -> ActorId -> Item -> HitAtomic -> SfxAtomic RecoilD :: ActorId -> ActorId -> Item -> HitAtomic -> SfxAtomic ProjectD :: ActorId -> ItemId -> SfxAtomic CatchD :: ActorId -> ItemId -> SfxAtomic ActivateD :: ActorId -> ItemId -> SfxAtomic CheckD :: ActorId -> ItemId -> SfxAtomic TriggerD :: ActorId -> Point -> Feature -> Bool -> SfxAtomic ShunD :: ActorId -> Point -> Feature -> Bool -> SfxAtomic EffectD :: ActorId -> (Effect Int) -> SfxAtomic MsgFidD :: FactionId -> Msg -> SfxAtomic MsgAllD :: Msg -> SfxAtomic DisplayPushD :: FactionId -> SfxAtomic DisplayDelayD :: FactionId -> SfxAtomic data HitAtomic HitD :: HitAtomic HitBlockD :: HitAtomic MissBlockD :: HitAtomic undoCmdAtomic :: CmdAtomic -> Maybe CmdAtomic undoSfxAtomic :: SfxAtomic -> SfxAtomic undoAtomic :: Atomic -> Maybe Atomic instance Show CmdAtomic instance Eq CmdAtomic instance Generic CmdAtomic instance Show HitAtomic instance Eq HitAtomic instance Generic HitAtomic instance Show SfxAtomic instance Eq SfxAtomic instance Generic SfxAtomic instance Show Atomic instance Eq Atomic instance Generic Atomic instance Datatype D1CmdAtomic instance Constructor C1_0CmdAtomic instance Constructor C1_1CmdAtomic instance Constructor C1_2CmdAtomic instance Constructor C1_3CmdAtomic instance Constructor C1_4CmdAtomic instance Constructor C1_5CmdAtomic instance Constructor C1_6CmdAtomic instance Constructor C1_7CmdAtomic instance Constructor C1_8CmdAtomic instance Constructor C1_9CmdAtomic instance Constructor C1_10CmdAtomic instance Constructor C1_11CmdAtomic instance Constructor C1_12CmdAtomic instance Constructor C1_13CmdAtomic instance Constructor C1_14CmdAtomic instance Constructor C1_15CmdAtomic instance Constructor C1_16CmdAtomic instance Constructor C1_17CmdAtomic instance Constructor C1_18CmdAtomic instance Constructor C1_19CmdAtomic instance Constructor C1_20CmdAtomic instance Constructor C1_21CmdAtomic instance Constructor C1_22CmdAtomic instance Constructor C1_23CmdAtomic instance Constructor C1_24CmdAtomic instance Constructor C1_25CmdAtomic instance Constructor C1_26CmdAtomic instance Constructor C1_27CmdAtomic instance Constructor C1_28CmdAtomic instance Constructor C1_29CmdAtomic instance Constructor C1_30CmdAtomic instance Constructor C1_31CmdAtomic instance Constructor C1_32CmdAtomic instance Constructor C1_33CmdAtomic instance Constructor C1_34CmdAtomic instance Constructor C1_35CmdAtomic instance Constructor C1_36CmdAtomic instance Constructor C1_37CmdAtomic instance Constructor C1_38CmdAtomic instance Constructor C1_39CmdAtomic instance Datatype D1HitAtomic instance Constructor C1_0HitAtomic instance Constructor C1_1HitAtomic instance Constructor C1_2HitAtomic instance Datatype D1SfxAtomic instance Constructor C1_0SfxAtomic instance Constructor C1_1SfxAtomic instance Constructor C1_2SfxAtomic instance Constructor C1_3SfxAtomic instance Constructor C1_4SfxAtomic instance Constructor C1_5SfxAtomic instance Constructor C1_6SfxAtomic instance Constructor C1_7SfxAtomic instance Constructor C1_8SfxAtomic instance Constructor C1_9SfxAtomic instance Constructor C1_10SfxAtomic instance Constructor C1_11SfxAtomic instance Constructor C1_12SfxAtomic instance Datatype D1Atomic instance Constructor C1_0Atomic instance Constructor C1_1Atomic instance Binary HitAtomic instance Binary SfxAtomic instance Binary CmdAtomic instance Binary Atomic -- | Server and client game state types and operations. module Game.LambdaHack.Server.State -- | Global, server state. data StateServer StateServer :: !Discovery -> !DiscoRev -> !ItemRev -> !FlavourMap -> !ActorId -> !ItemId -> ![Atomic] -> !Pers -> !StdGen -> !Text -> Config -> !Bool -> !Bool -> !DebugModeSer -> !DebugModeSer -> StateServer -- | full item discoveries data sdisco :: StateServer -> !Discovery -- | reverse disco map, used for item creation sdiscoRev :: StateServer -> !DiscoRev -- | reverse id map, used for item creation sitemRev :: StateServer -> !ItemRev -- | association of flavour to items sflavour :: StateServer -> !FlavourMap -- | stores next actor index sacounter :: StateServer -> !ActorId -- | stores next item index sicounter :: StateServer -> !ItemId -- | atomic commands performed to date sundo :: StateServer -> ![Atomic] -- | perception of all factions sper :: StateServer -> !Pers -- | current random generator srandom :: StateServer -> !StdGen -- | current game mode scenario :: StateServer -> !Text -- | this game's config (including initial RNG) sconfig :: StateServer -> Config -- | exit the game loop squit :: StateServer -> !Bool -- | make backup savefile now sbkpSave :: StateServer -> !Bool -- | current debugging mode sdebugSer :: StateServer -> !DebugModeSer -- | debugging mode for the next game sdebugNxt :: StateServer -> !DebugModeSer -- | Initial, empty game server state. emptyStateServer :: StateServer data DebugModeSer DebugModeSer :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !(Maybe FovMode) -> !Bool -> DebugModeSer sknowMap :: DebugModeSer -> !Bool sknowEvents :: DebugModeSer -> !Bool sniffIn :: DebugModeSer -> !Bool sniffOut :: DebugModeSer -> !Bool sallClear :: DebugModeSer -> !Bool stryFov :: DebugModeSer -> !(Maybe FovMode) sdebugCli :: DebugModeSer -> !Bool defDebugModeSer :: DebugModeSer instance Show DebugModeSer instance Show StateServer instance Binary DebugModeSer instance Binary StateServer -- | Saving and restoring server game state. module Game.LambdaHack.Server.Action.Save -- | Save game to the backup savefile, in case of crashes. This is only a -- backup, so no problem is the game is shut down before saving finishes, -- so we don't wait on the mvar. However, if a previous save is already -- in progress, we skip this save. saveGameBkpSer :: Config -> State -> StateServer -> IO () -- | Save a simple serialized version of the current state. Protected by a -- lock to avoid corrupting the file. saveGameSer :: Config -> State -> StateServer -> IO () -- | Restore a saved game, if it exists. Initialize directory structure and -- cope over data files, if needed. restoreGameSer :: Config -> (FilePath -> IO FilePath) -> IO (Maybe (State, StateServer)) -- | Game action monads and basic building blocks for human and computer -- player actions. Has no access to the the main action type. module Game.LambdaHack.Common.Action class (Monad m, Functor m) => MonadActionRO m getState :: MonadActionRO m => m State getsState :: MonadActionRO m => (State -> a) -> m a class MonadActionRO m => MonadAction m modifyState :: MonadAction m => (State -> State) -> m () putState :: MonadAction m => State -> m () class MonadActionRO m => MonadAtomic m where execCmdAtomic = execAtomic . CmdAtomic execSfxAtomic = execAtomic . SfxAtomic execAtomic :: MonadAtomic m => Atomic -> m () execCmdAtomic :: MonadAtomic m => CmdAtomic -> m () execSfxAtomic :: MonadAtomic m => SfxAtomic -> m () getsLevel :: MonadActionRO m => LevelId -> (Level -> a) -> m a nHumans :: MonadActionRO m => m Int instance MonadActionRO m => Show (WriterT a m b) instance (Monoid a, MonadActionRO m) => MonadActionRO (WriterT a m) -- | Semantics of atomic commands shared by client and server. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Common.AtomicSem cmdAtomicSem :: MonadAction m => CmdAtomic -> m () posOfAid :: MonadActionRO m => ActorId -> m (LevelId, Point) posOfContainer :: MonadActionRO m => Container -> m (LevelId, Point) -- | Semantics of atomic commands shared by client and server. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Common.AtomicPos -- | The type representing visibility of actions to factions, based on the -- position of the action, etc. data PosAtomic -- | whomever sees all the positions, notices PosSight :: LevelId -> [Point] -> PosAtomic -- | observers and the faction notice PosFidAndSight :: FactionId -> LevelId -> [Point] -> PosAtomic -- | whomever smells all the positions, notices PosSmell :: LevelId -> [Point] -> PosAtomic -- | only the faction notices PosFid :: FactionId -> PosAtomic -- | faction and server notices PosFidAndSer :: FactionId -> PosAtomic -- | only the server notices PosSer :: PosAtomic -- | everybody notices PosAll :: PosAtomic -- | never broadcasted, but sent manually PosNone :: PosAtomic -- | Produces the positions where the action takes place. If a faction is -- returned, the action is visible only for that faction, if Nothing is -- returned, it's never visible. Empty list of positions implies the -- action is visible always. -- -- The goal of the mechanics: client should not get significantly more -- information by looking at the atomic commands he is able to see than -- by looking at the state changes they enact. E.g., -- DisplaceActorA in a black room, with one actor carrying a -- 0-radius light would not be distinguishable by looking at the state -- (or the screen) from MoveActorA of the illuminated actor, -- hence such DisplaceActorA should not be observable, but -- MoveActorA should be (or the former should be perceived as -- the latter). However, to simplify, we assing as strict visibility -- requirements to MoveActorA as to DisplaceActorA and -- fall back to SpotActorA (which provides minimal information -- that does not contradict state) if the visibility is lower. posCmdAtomic :: MonadActionRO m => CmdAtomic -> m PosAtomic posSfxAtomic :: MonadActionRO m => SfxAtomic -> m PosAtomic resetsFovAtomic :: MonadActionRO m => CmdAtomic -> m (Maybe [FactionId]) -- | Decompose an atomic action. The original action is visible if it's -- positions are visible both before and after the action (in between the -- FOV might have changed). The decomposed actions are only tested vs the -- FOV after the action and they give reduced information that still -- modifies client's state to match the server state wrt the current FOV -- and the subset of posCmdAtomic that is visible. The original -- actions give more information not only due to spanning potentially -- more positions than those visible. E.g., MoveActorA informs -- about the continued existence of the actor between moves, v.s., -- popping out of existence and then back in. breakCmdAtomic :: MonadActionRO m => CmdAtomic -> m [CmdAtomic] loudCmdAtomic :: FactionId -> CmdAtomic -> Bool seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool seenAtomicSer :: PosAtomic -> Bool instance Show PosAtomic instance Eq PosAtomic -- | Abstract syntax of client commands. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Common.ClientCmd -- | Abstract syntax of client commands that don't use the UI. data CmdClientAI CmdAtomicAI :: CmdAtomic -> CmdClientAI CmdQueryAI :: ActorId -> CmdClientAI -- | Abstract syntax of client commands that use the UI. data CmdClientUI CmdAtomicUI :: CmdAtomic -> CmdClientUI SfxAtomicUI :: SfxAtomic -> CmdClientUI CmdQueryUI :: ActorId -> CmdClientUI debugCmdClientAI :: MonadActionRO m => CmdClientAI -> m Text debugCmdClientUI :: MonadActionRO m => CmdClientUI -> m Text debugAid :: MonadActionRO m => ActorId -> Text -> m Text -- | Connection channels between the server and a single client. data ChanServer c ChanServer :: TQueue c -> TQueue CmdSer -> ChanServer c fromServer :: ChanServer c -> TQueue c toServer :: ChanServer c -> TQueue CmdSer -- | Connection to the human-controlled client of a faction and/or to the -- AI client for the same faction. type ConnServerFaction = ((ChanFrontend, ChanServer CmdClientUI), ChanServer CmdClientAI) -- | Connection information for all factions, indexed by faction -- identifier. type ConnServerDict = EnumMap FactionId ConnServerFaction instance Show CmdClientAI instance Show CmdClientUI instance Show (ChanServer c) -- | Basic type classes for server game actions. This module should not be -- imported anywhere except in Action and TypeAction. module Game.LambdaHack.Server.Action.ActionClass class MonadActionRO m => MonadServer m getServer :: MonadServer m => m StateServer getsServer :: MonadServer m => (StateServer -> a) -> m a modifyServer :: MonadServer m => (StateServer -> StateServer) -> m () putServer :: MonadServer m => StateServer -> m () liftIO :: MonadServer m => IO a -> m a class MonadServer m => MonadConnServer m getDict :: MonadConnServer m => m ConnServerDict getsDict :: MonadConnServer m => (ConnServerDict -> a) -> m a modifyDict :: MonadConnServer m => (ConnServerDict -> ConnServerDict) -> m () putDict :: MonadConnServer m => ConnServerDict -> m () -- | Game action monads and basic building blocks for human and computer -- player actions. Has no access to the the main action type. Does not -- export the liftIO operation nor a few other implementation -- details. module Game.LambdaHack.Server.Action class MonadActionRO m => MonadServer m getServer :: MonadServer m => m StateServer getsServer :: MonadServer m => (StateServer -> a) -> m a modifyServer :: MonadServer m => (StateServer -> StateServer) -> m () putServer :: MonadServer m => StateServer -> m () class MonadServer m => MonadConnServer m tryRestore :: MonadServer m => COps -> m (Maybe (State, StateServer)) -- | Update connections to the new definition of factions. Connect to -- clients in old or newly spawned threads that read and write directly -- to the channels. updateConn :: (MonadAtomic m, MonadConnServer m) => (FactionId -> ChanFrontend -> ChanServer CmdClientUI -> IO ()) -> (FactionId -> ChanServer CmdClientAI -> IO ()) -> m () killAllClients :: (MonadAtomic m, MonadConnServer m) => m () waitForChildren :: IO () -- | Compute and insert auxiliary optimized components into game content, -- to be used in time-critical sections of the code. speedupCOps :: Bool -> COps -> COps sendUpdateUI :: MonadConnServer m => FactionId -> CmdClientUI -> m () sendQueryUI :: MonadConnServer m => FactionId -> ActorId -> m CmdSer sendUpdateAI :: MonadConnServer m => FactionId -> CmdClientAI -> m () sendQueryAI :: MonadConnServer m => FactionId -> ActorId -> m CmdSer saveGameSer :: MonadServer m => m () -- | Save a backup of the save game file, in case of crashes. -- -- See saveGameBkp. saveGameBkp :: MonadServer m => m () -- | Dumps the current game rules configuration to a file. dumpCfg :: MonadServer m => FilePath -> m () -- | Create a server config file. Warning: when it's used, the game state -- may still be undefined, hence the content ops are given as an -- argument. mkConfigRules :: MonadServer m => Ops RuleKind -> m (Config, StdGen, StdGen) -- | Read the high scores table. Return the empty table if no file. -- Warning: when it's used, the game state may still be undefined, hence -- the config is given as an argument. restoreScore :: MonadServer m => Config -> m ScoreTable revealItems :: (MonadAtomic m, MonadServer m) => Maybe FactionId -> Maybe Actor -> m () deduceQuits :: (MonadAtomic m, MonadServer m) => Actor -> Status -> m () -- | Invoke pseudo-random computation with the generator kept in the state. rndToAction :: MonadServer m => Rnd a -> m a fovMode :: MonadServer m => m FovMode -- | Update the cached perception for the selected level, for a faction. -- The assumption is the level, and only the level, has changed since the -- previous perception calculation. resetFidPerception :: MonadServer m => FactionId -> LevelId -> m () getPerFid :: MonadServer m => FactionId -> LevelId -> m Perception -- | The main game action monad type implementation. Just as any other -- component of the library, this implementation can be substituted. This -- module should not be imported anywhere except in Action to -- expose the executor to any code using the library. module Game.LambdaHack.Server.Action.ActionType -- | Server state transformation monad. data ActionSer a -- | Run an action in the IO monad, with undefined state. executorSer :: ActionSer () -> IO () instance Monad ActionSer instance Functor ActionSer instance MonadConnServer ActionSer instance MonadServer ActionSer instance MonadAction ActionSer instance MonadActionRO ActionSer -- | Sending atomic commands to clients and executing them on the server. -- See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Server.AtomicSemSer -- | Send an atomic action to all clients that can see it. atomicSendSem :: (MonadAction m, MonadConnServer m) => Atomic -> m () -- | Effect semantics. TODO: document module Game.LambdaHack.Server.EffectSem -- | The source actor affects the target actor, with a given item. If the -- event is seen, the item may get identified. This function is mutually -- recursive with effect and so it's a part of Effect -- semantics. itemEffect :: (MonadAtomic m, MonadServer m) => ActorId -> ActorId -> Maybe ItemId -> Item -> m () -- | The source actor affects the target actor, with a given effect and -- power. Both actors are on the current level and can be the same actor. -- The boolean result indicates if the effect was spectacular enough for -- the actors to identify it (and the item that caused it, if any). effectSem :: (MonadAtomic m, MonadServer m) => Effect Int -> ActorId -> ActorId -> m Bool createItems :: (MonadAtomic m, MonadServer m) => Int -> Point -> LevelId -> m () -- | Create a new hero on the current level, close to the given position. addHero :: (MonadAtomic m, MonadServer m) => FactionId -> Point -> LevelId -> [(Int, Text)] -> Maybe Int -> Time -> m ActorId -- | Spawn monsters of any spawn or summon faction, friendly or not. To be -- used for spontaneous spawning of monsters and for the summon effect. spawnMonsters :: (MonadAtomic m, MonadServer m) => [Point] -> LevelId -> ((FactionId, Faction) -> Bool) -> Time -> Text -> m () electLeader :: MonadAtomic m => FactionId -> LevelId -> ActorId -> m () deduceKilled :: (MonadAtomic m, MonadServer m) => Actor -> m () -- | Semantics of CmdSer server commands. A couple of them do not -- take time, the rest does. Note that since the results are atomic -- commands, which are executed only later (on the server and some of the -- clients), all condition are checkd by the semantic functions in the -- context of the state before the server command. Even if one or more -- atomic actions are already issued by the point an expression is -- evaluated, they do not influence the outcome of the evaluation. TODO: -- document module Game.LambdaHack.Server.ServerSem execFailure :: MonadAtomic m => FactionId -> Msg -> m Bool broadcastCmdAtomic :: MonadAtomic m => (FactionId -> CmdAtomic) -> m () broadcastSfxAtomic :: MonadAtomic m => (FactionId -> SfxAtomic) -> m () -- | Actor moves or attacks or searches or opens doors. Note that client -- can't determine which of these actions is chosen, because foes can be -- invisible, doors hidden, clients can move simultaneously during the -- same turn, etc. Also, only the server is authorized to check if a move -- is legal and it needs full context for that, e.g., the initial actor -- position to check if melee attack does not try to reach to a distant -- tile. moveSer :: (MonadAtomic m, MonadServer m) => ActorId -> Vector -> Bool -> m Bool -- | Add a smell trace for the actor to the level. For now, all and only -- actors from non-spawning factions leave smell. addSmell :: MonadAtomic m => ActorId -> m () -- | Resolves the result of an actor moving into another. Actors on blocked -- positions can be attacked without any restrictions. For instance, an -- actor embedded in a wall can be attacked from an adjacent position. -- This function is analogous to projectGroupItem, but for melee and not -- using up the weapon. actorAttackActor :: (MonadAtomic m, MonadServer m) => ActorId -> ActorId -> m () -- | An actor opens a door. actorOpenDoor :: (MonadAtomic m, MonadServer m) => ActorId -> Vector -> Bool -> m Bool -- | Actor moves or swaps position with others or opens doors. runSer :: (MonadAtomic m, MonadServer m) => ActorId -> Vector -> m Bool -- | When an actor runs (not walks) into another, they switch positions. displaceActor :: MonadAtomic m => ActorId -> ActorId -> m () -- | Update the wait/block count. Uses local, per-level time, to remain -- correct even if the level is frozen for some global time turns. waitSer :: MonadAtomic m => ActorId -> m () pickupSer :: MonadAtomic m => ActorId -> ItemId -> Int -> InvChar -> m () dropSer :: MonadAtomic m => ActorId -> ItemId -> m () projectSer :: (MonadAtomic m, MonadServer m) => ActorId -> Point -> Int -> ItemId -> Container -> m Bool -- | Create a projectile actor containing the given missile. addProjectile :: (MonadAtomic m, MonadServer m) => ItemId -> Point -> LevelId -> FactionId -> [Point] -> Time -> m ActorId applySer :: (MonadAtomic m, MonadServer m) => ActorId -> ItemId -> Container -> m () -- | Perform the action specified for the tile in case it's triggered. triggerSer :: (MonadAtomic m, MonadServer m) => ActorId -> Point -> m Bool setPathSer :: (MonadAtomic m, MonadServer m) => ActorId -> [Vector] -> m () gameRestartSer :: (MonadAtomic m, MonadServer m) => ActorId -> Text -> m () gameExitSer :: (MonadAtomic m, MonadServer m) => ActorId -> m () gameSaveSer :: MonadServer m => m () cfgDumpSer :: (MonadAtomic m, MonadServer m) => ActorId -> m () -- | Operations for starting and restarting the game. module Game.LambdaHack.Server.StartAction -- | Apply debug options that don't need a new game. applyDebug :: MonadServer m => DebugModeSer -> m () gameReset :: MonadServer m => COps -> m State reinitGame :: (MonadAtomic m, MonadServer m) => m () initPer :: MonadServer m => m () -- | The main loop of the server, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Server.LoopAction -- | Start a clip (a part of a turn for which one or more frames will be -- generated). Do whatever has to be done every fixed number of time -- units, e.g., monster generation. Run the leader and other actors -- moves. Eventually advance the time and repeat. loopSer :: (MonadAtomic m, MonadConnServer m) => DebugModeSer -> (CmdSer -> m Bool) -> (FactionId -> ChanFrontend -> ChanServer CmdClientUI -> IO ()) -> (FactionId -> ChanServer CmdClientAI -> IO ()) -> COps -> m () -- | Semantics of server commands. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Server -- | Fire up the frontend with the engine fueled by content. The action -- monad types to be used are determined by the exeSer and -- executorCli calls. If other functions are used in their place -- the types are different and so the whole pattern of computation is -- different. Which of the frontends is run depends on the flags supplied -- when compiling the engine library. mainSer :: (MonadAtomic m, MonadConnServer m) => COps -> (m () -> IO ()) -> (COps -> ((FactionId -> ChanFrontend -> ChanServer CmdClientUI -> IO ()) -> (FactionId -> ChanServer CmdClientAI -> IO ()) -> IO ()) -> IO ()) -> IO () -- | Personal game configuration file type definitions. module Game.LambdaHack.Client.Config -- | Fully typed contents of the UI config file. This config is a part of a -- game client. data ConfigUI ConfigUI :: ![(KM, HumanCmd)] -> !FilePath -> !FilePath -> ![(KM, KM)] -> !String -> !Int -> ConfigUI configCommands :: ConfigUI -> ![(KM, HumanCmd)] configAppDataDirUI :: ConfigUI -> !FilePath configUICfgFile :: ConfigUI -> !FilePath configMacros :: ConfigUI -> ![(KM, KM)] configFont :: ConfigUI -> !String configHistoryMax :: ConfigUI -> !Int instance Show ConfigUI instance Binary ConfigUI instance NFData ConfigUI -- | Server and client game state types and operations. module Game.LambdaHack.Client.State -- | Client state, belonging to a single faction. Some of the data, e.g, -- the history, carries over from game to game, even across playing -- sessions. Data invariant: if _sleader is Nothing -- then so is srunning. data StateClient StateClient :: !(Maybe TgtMode) -> !(Maybe Point) -> !Int -> !(EnumMap ActorId Target) -> !(Maybe (Vector, Int)) -> !Report -> !History -> ![Atomic] -> !Discovery -> !FactionPers -> !StdGen -> !ConfigUI -> !(Maybe KM) -> !(Maybe ActorId) -> !FactionId -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> StateClient -- | targeting mode stgtMode :: StateClient -> !(Maybe TgtMode) -- | cursor coordinates scursor :: StateClient -> !(Maybe Point) -- | a parameter of the tgt digital line seps :: StateClient -> !Int -- | targets of our actors in the dungeon stargetD :: StateClient -> !(EnumMap ActorId Target) -- | direction and distance of running srunning :: StateClient -> !(Maybe (Vector, Int)) -- | current messages sreport :: StateClient -> !Report -- | history of messages shistory :: StateClient -> !History -- | atomic commands performed to date sundo :: StateClient -> ![Atomic] -- | remembered item discoveries sdisco :: StateClient -> !Discovery -- | faction perception indexed by levels sfper :: StateClient -> !FactionPers -- | current random generator srandom :: StateClient -> !StdGen -- | client config (including initial RNG) sconfigUI :: StateClient -> !ConfigUI -- | last command key pressed slastKey :: StateClient -> !(Maybe KM) -- | selected actor _sleader :: StateClient -> !(Maybe ActorId) -- | faction controlled by the client _sside :: StateClient -> !FactionId -- | exit the game loop squit :: StateClient -> !Bool -- | whether it's an AI client sisAI :: StateClient -> !Bool -- | mark leader and party FOV smarkVision :: StateClient -> !Bool -- | mark smell, if the leader can smell smarkSmell :: StateClient -> !Bool -- | mark suspect features smarkSuspect :: StateClient -> !Bool -- | show client debug messages sdebugCli :: StateClient -> !Bool -- | Initial game client state. defStateClient :: History -> ConfigUI -> FactionId -> Bool -> StateClient defHistory :: IO History -- | Update target parameters within client state. updateTarget :: ActorId -> (Maybe Target -> Maybe Target) -> StateClient -> StateClient -- | Get target parameters from client state. getTarget :: ActorId -> StateClient -> Maybe Target -- | Update selected actor within state. Verify actor's faction. updateLeader :: ActorId -> State -> StateClient -> StateClient sside :: StateClient -> FactionId -- | Current targeting mode of a client. data TgtMode -- | the player requested targeting mode explicitly TgtExplicit :: !LevelId -> TgtMode tgtLevelId :: TgtMode -> !LevelId -- | the mode was entered (and will be exited) automatically TgtAuto :: !LevelId -> TgtMode tgtLevelId :: TgtMode -> !LevelId -- | The type of na actor target. data Target -- | target an actor with its last seen position TEnemy :: ActorId -> Point -> Target -- | target a given position TPos :: Point -> Target toggleMarkVision :: StateClient -> StateClient toggleMarkSmell :: StateClient -> StateClient toggleMarkSuspect :: StateClient -> StateClient instance Show TgtMode instance Eq TgtMode instance Show Target instance Eq Target instance Show StateClient instance Binary Target instance Binary TgtMode instance Binary StateClient -- | Display game data on the screen using one of the available frontends -- (determined at compile time with cabal flags). module Game.LambdaHack.Client.Draw -- | Color mode for the display. data ColorMode -- | normal, with full colours ColorFull :: ColorMode -- | black+white only ColorBW :: ColorMode -- | Draw the whole screen: level map, status area and, at most, a single -- page overlay of text divided into lines. draw :: ColorMode -> COps -> Perception -> LevelId -> Maybe ActorId -> StateClient -> State -> Overlay -> SingleFrame -- | Personal game configuration file support. module Game.LambdaHack.Client.Action.ConfigIO -- | Read and parse UI config file. mkConfigUI :: Ops RuleKind -> IO ConfigUI instance Show CP -- | Saving and restoring client game state. module Game.LambdaHack.Client.Action.Save -- | Save a simple serialized version of the current state. Protected by a -- lock to avoid corrupting the file. saveGameCli :: String -> Bool -> ConfigUI -> State -> StateClient -> IO () -- | Restore a saved game, if it exists. Initialize directory structure, if -- needed. restoreGameCli :: String -> ConfigUI -> (FilePath -> IO FilePath) -> Text -> IO (Either (State, StateClient, Msg) Msg) -- | Generic binding of keys to commands, procesing macros, printing -- command help. No operation in this module involves the State -- or Action type. module Game.LambdaHack.Client.Binding -- | Bindings and other information about human player commands. data Binding Binding :: Map KM (Text, Bool, HumanCmd) -> Map KM KM -> [KM] -> [KM] -> Map HumanCmd KM -> Binding -- | binding keys to commands kcmd :: Binding -> Map KM (Text, Bool, HumanCmd) -- | macro map kmacro :: Binding -> Map KM KM -- | major commands kmajor :: Binding -> [KM] -- | minor commands kminor :: Binding -> [KM] -- | from cmds to their main keys krevMap :: Binding -> Map HumanCmd KM -- | Binding of keys to movement and other standard commands, as well as -- commands defined in the config file. stdBinding :: ConfigUI -> Binding -- | Produce a set of help screens from the key bindings. keyHelp :: Binding -> Slideshow -- | Basic type classes for game actions. This module should not be -- imported anywhere except in Action and TypeAction. module Game.LambdaHack.Client.Action.ActionClass -- | The information that is constant across a client playing session, -- including many consecutive games in a single session, but is -- completely disregarded and reset when a new playing session starts. -- Auxiliary AI and computer player clients have no sfs nor -- sbinding. data SessionUI SessionUI :: !ConnFrontend -> !Binding -> SessionUI -- | connection with the frontend sfconn :: SessionUI -> !ConnFrontend -- | binding of keys to commands sbinding :: SessionUI -> !Binding -- | Connection method between a client and a frontend. data ConnFrontend ConnFrontend :: (forall m. MonadClientUI m => m KM) -> (forall m. MonadClientUI m => FrontReq -> m ()) -> ConnFrontend -- | read a keystroke received from the frontend readConnFrontend :: ConnFrontend -> forall m. MonadClientUI m => m KM -- | write a UI request to the frontend writeConnFrontend :: ConnFrontend -> forall m. MonadClientUI m => FrontReq -> m () data ConnServer c ConnServer :: (forall m. MonadConnClient c m => m c) -> (forall m. MonadConnClient c m => CmdSer -> m ()) -> ConnServer c readConnServer :: ConnServer c -> forall m. MonadConnClient c m => m c writeConnServer :: ConnServer c -> forall m. MonadConnClient c m => CmdSer -> m () class MonadActionRO m => MonadClient m getClient :: MonadClient m => m StateClient getsClient :: MonadClient m => (StateClient -> a) -> m a modifyClient :: MonadClient m => (StateClient -> StateClient) -> m () putClient :: MonadClient m => StateClient -> m () liftIO :: MonadClient m => IO a -> m a class MonadClient m => MonadClientUI m getsSession :: MonadClientUI m => (SessionUI -> a) -> m a class MonadClient m => MonadConnClient c m | m -> c getConn :: MonadConnClient c m => m (ConnServer c) -- | The bottom of the action monads class semilattice. class MonadClient m => MonadClientAbort m tryWith :: MonadClientAbort m => (Msg -> m a) -> m a -> m a abortWith :: MonadClientAbort m => Msg -> m a instance (Monoid a, MonadClientAbort m) => MonadClientAbort (WriterT a m) instance (Monoid a, MonadClientUI m) => MonadClientUI (WriterT a m) instance (Monoid a, MonadClient m) => MonadClient (WriterT a m) -- | The main game action monad type implementation. Just as any other -- component of the library, this implementation can be substituted. This -- module should not be imported anywhere except in Action to -- expose the executor to any code using the library. module Game.LambdaHack.Client.Action.ActionType -- | The type of the function inside any client action. type FunActionCli c a = SessionUI -> ConnServer c -> (State -> StateClient -> a -> IO ()) -> (StdGen -> Msg -> IO ()) -> State -> StateClient -> IO () -- | Client parts of actions of human and computer player characters. data ActionCli c a -- | Run an action, with a given session, state and history, in the -- IO monad. executorCli :: ActionCli c () -> SessionUI -> State -> StateClient -> ConnServer c -> IO () instance MonadConnClient c (ActionCli c) instance MonadClientUI (ActionCli c) instance MonadClient (ActionCli c) instance MonadAction (ActionCli c) instance MonadActionRO (ActionCli c) instance MonadClientAbort (ActionCli c) instance Show (ActionCli c a) instance Functor (ActionCli c) instance Monad (ActionCli c) -- | Game action monads and basic building blocks for human and computer -- player actions. Has no access to the the main action type. Does not -- export the liftIO operation nor a few other implementation -- details. module Game.LambdaHack.Client.Action class MonadActionRO m => MonadClient m getClient :: MonadClient m => m StateClient getsClient :: MonadClient m => (StateClient -> a) -> m a modifyClient :: MonadClient m => (StateClient -> StateClient) -> m () putClient :: MonadClient m => StateClient -> m () class MonadClient m => MonadClientUI m class MonadClient m => MonadConnClient c m | m -> c getConn :: MonadConnClient c m => m (ConnServer c) -- | The bottom of the action monads class semilattice. class MonadClient m => MonadClientAbort m tryWith :: MonadClientAbort m => (Msg -> m a) -> m a -> m a abortWith :: MonadClientAbort m => Msg -> m a -- | The information that is constant across a client playing session, -- including many consecutive games in a single session, but is -- completely disregarded and reset when a new playing session starts. -- Auxiliary AI and computer player clients have no sfs nor -- sbinding. data SessionUI SessionUI :: !ConnFrontend -> !Binding -> SessionUI -- | connection with the frontend sfconn :: SessionUI -> !ConnFrontend -- | binding of keys to commands sbinding :: SessionUI -> !Binding -- | Connection method between a client and a frontend. data ConnFrontend ConnFrontend :: (forall m. MonadClientUI m => m KM) -> (forall m. MonadClientUI m => FrontReq -> m ()) -> ConnFrontend -- | read a keystroke received from the frontend readConnFrontend :: ConnFrontend -> forall m. MonadClientUI m => m KM -- | write a UI request to the frontend writeConnFrontend :: ConnFrontend -> forall m. MonadClientUI m => FrontReq -> m () connFrontend :: FactionId -> ChanFrontend -> ConnFrontend data ConnServer c ConnServer :: (forall m. MonadConnClient c m => m c) -> (forall m. MonadConnClient c m => CmdSer -> m ()) -> ConnServer c readConnServer :: ConnServer c -> forall m. MonadConnClient c m => m c writeConnServer :: ConnServer c -> forall m. MonadConnClient c m => CmdSer -> m () connServer :: ChanServer c -> ConnServer c -- | Reset the state and resume from the last backup point, i.e., invoke -- the failure continuation. abort :: MonadClientAbort m => m a -- | Abort and print the given msg if the condition is true. abortIfWith :: MonadClientAbort m => Bool -> Msg -> m a -- | Abort and conditionally print the fixed message. neverMind :: MonadClientAbort m => Bool -> m a -- | Take a handler and a computation. If the computation fails, the -- handler is invoked and then the computation is retried. tryRepeatedlyWith :: MonadClientAbort m => (Msg -> m ()) -> m () -> m () -- | Try the given computation and silently catch failure. tryIgnore :: MonadClientAbort m => m () -> m () -- | Set the current exception handler. Apart of executing it, draw and -- pass along a slide with the abort message (even if message empty). tryWithSlide :: (MonadClientAbort m, MonadClientUI m) => m a -> WriterT Slideshow m a -> WriterT Slideshow m a -- | Read and parse UI config file. mkConfigUI :: Ops RuleKind -> IO ConfigUI -- | Get the key binding. askBinding :: MonadClientUI m => m Binding -- | Get the current perception of a client. getPerFid :: MonadClient m => LevelId -> m Perception -- | Add a message to the current report. msgAdd :: MonadClientUI m => Msg -> m () -- | Wipe out and set a new value for the current report. msgReset :: MonadClient m => Msg -> m () -- | Store current report in the history and reset report. recordHistory :: MonadClient m => m () -- | Display an overlay and wait for a human player command. getKeyOverlayCommand :: MonadClientUI m => Overlay -> m KM -- | Display a slideshow, awaiting confirmation for each slide except the -- last. getInitConfirms :: MonadClientUI m => [KM] -> Slideshow -> m Bool -- | Push frames or delays to the frame queue. displayFrames :: MonadClientUI m => Frames -> m () -- | Display a msg with a more prompt. Return value indicates if -- the player tried to cancel/escape. displayMore :: MonadClientUI m => ColorMode -> Msg -> m Bool -- | Print a yes/no question and return the player's answer. Use black and -- white colours to turn player's attention to the choice. displayYesNo :: MonadClientUI m => ColorMode -> Msg -> m Bool -- | Print a prompt and an overlay and wait for a player keypress. If many -- overlays, scroll screenfuls with SPACE. Do not wrap screenfuls (in -- some menus ? cycles views, so the user can restart from the -- top). displayChoiceUI :: (MonadClientAbort m, MonadClientUI m) => Msg -> Overlay -> [KM] -> m KM -- | The prompt is shown after the current message, but not added to -- history. This is useful, e.g., in targeting mode, not to spam history. promptToSlideshow :: MonadClientUI m => Msg -> m Slideshow -- | The prompt is shown after the current message at the top of each -- slide. Together they may take more than one line. The prompt is not -- added to history. The portions of overlay that fit on the the rest of -- the screen are displayed below. As many slides as needed are shown. overlayToSlideshow :: MonadClientUI m => Msg -> Overlay -> m Slideshow -- | Draw the current level with the overlay on top. drawOverlay :: MonadClientUI m => ColorMode -> Overlay -> m SingleFrame -- | Render animations on top of the current screen frame. animate :: MonadClientUI m => LevelId -> Animation -> m Frames clientGameSave :: MonadClient m => Bool -> m () restoreGame :: MonadClient m => m (Either (State, StateClient, Msg) Msg) -- | Push the frame depicting the current level to the frame queue. Only -- one screenful of the report is shown, the rest is ignored. displayPush :: MonadClientUI m => m () scoreToSlideshow :: MonadClientUI m => Int -> Status -> m Slideshow -- | Invoke pseudo-random computation with the generator kept in the state. rndToAction :: MonadClient m => Rnd a -> m a getArenaUI :: MonadClientUI m => m LevelId getLeaderUI :: MonadClientUI m => m ActorId -- | Calculate the position of leader's target. targetToPos :: MonadClientUI m => m (Maybe Point) -- | The part of speech describing the actor (designated by actor id and -- present in the dungeon) or a special name if a leader of the -- observer's faction. partAidLeader :: MonadClient m => ActorId -> m Part -- | The part of speech describing the actor or a special name if a leader -- of the observer's faction. The actor may not be present in the -- dungeon. partActorLeader :: MonadClient m => ActorId -> Actor -> m Part debugPrint :: MonadClient m => Text -> m () -- | The main loop of the client, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Client.LoopAction loopAI :: MonadConnClient CmdClientAI m => (CmdClientAI -> m ()) -> m () loopUI :: (MonadClientUI m, MonadConnClient CmdClientUI m) => (CmdClientUI -> m ()) -> m () -- | Semantics of HumanCmd client commands that do not return -- server commands. None of such commands takes game time. TODO: document module Game.LambdaHack.Client.HumanLocal moveCursor :: MonadClientUI m => Vector -> Int -> WriterT Slideshow m () retargetLeader :: MonadClientUI m => WriterT Slideshow m () selectHeroHuman :: (MonadClientAbort m, MonadClientUI m) => Int -> m () -- | Switches current member to the next on the level, if any, wrapping. memberCycleHuman :: (MonadClientAbort m, MonadClientUI m) => m () -- | Switches current member to the previous in the whole dungeon, -- wrapping. memberBackHuman :: (MonadClientAbort m, MonadClientUI m) => m () -- | Display inventory inventoryHuman :: (MonadClientAbort m, MonadClientUI m) => WriterT Slideshow m () -- | Start floor targeting mode or reset the cursor position to the leader. -- Note that the origin of a command (the hero that performs it) is -- unaffected by targeting. For example, not the targeted door, but one -- adjacent to the selected hero is closed by him. tgtFloorLeader :: MonadClientUI m => TgtMode -> WriterT Slideshow m () -- | Start the enemy targeting mode. Cycle between enemy targets. tgtEnemyLeader :: MonadClientUI m => TgtMode -> WriterT Slideshow m () -- | Change the displayed level in targeting mode to (at most) k levels -- shallower. Enters targeting mode, if not already in one. tgtAscendHuman :: (MonadClientAbort m, MonadClientUI m) => Int -> WriterT Slideshow m () -- | Tweak the eps parameter of the targeting digital line. epsIncrHuman :: MonadClientAbort m => Bool -> m () -- | Cancel something, e.g., targeting mode, resetting the cursor to the -- position of the leader. Chosen target is not invalidated. cancelHuman :: MonadClientUI m => WriterT Slideshow m () -> WriterT Slideshow m () -- | Display the main menu. displayMainMenu :: MonadClientUI m => WriterT Slideshow m () -- | Accept something, e.g., targeting mode, keeping cursor where it was. -- Or perform the default action, if nothing needs accepting. acceptHuman :: MonadClientUI m => WriterT Slideshow m () -> WriterT Slideshow m () -- | Clear current messages, show the next screen if any. clearHuman :: Monad m => m () historyHuman :: MonadClientUI m => WriterT Slideshow m () humanMarkVision :: MonadClientUI m => m () humanMarkSmell :: MonadClientUI m => m () humanMarkSuspect :: MonadClientUI m => m () -- | Display command help. helpHuman :: MonadClientUI m => WriterT Slideshow m () -- | End targeting mode, accepting the current position or not. endTargeting :: MonadClientUI m => Bool -> m () -- | Create a list of item names. floorItemOverlay :: MonadClient m => ItemBag -> m Overlay -- | Create a list of item names. itemOverlay :: MonadClient m => ItemBag -> ItemInv -> m Overlay viewedLevel :: MonadClientUI m => m (LevelId, Level) -- | Select a faction leader. False, if nothing to do. selectLeader :: MonadClientUI m => ActorId -> m Bool stopRunning :: MonadClient m => m () -- | Produces a textual description of the terrain and items at an already -- explored position. Mute for unknown positions. The detailed variant is -- for use in the targeting mode. lookAt :: MonadClientUI m => Bool -> Bool -> Point -> ActorId -> Text -> m Text -- | Semantics of client UI response to atomic commands. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Client.AtomicSemCli cmdAtomicSem :: MonadAction m => CmdAtomic -> m () -- | Effect of atomic actions on client state is calculated in the global -- state before the command is executed. Clients keep a subset of atomic -- commands sent by the server and add their own. The result of this -- function is the list of commands kept for each command received. cmdAtomicSemCli :: MonadClient m => CmdAtomic -> m () -- | Clients keep a subset of atomic commands sent by the server and add -- some of their own. The result of this function is the list of commands -- kept for each command received. cmdAtomicFilterCli :: MonadClient m => CmdAtomic -> m [CmdAtomic] -- | Visualization of atomic actions for the client is perfomed in the -- global state after the command is executed and after the client state -- is modified by the command. drawCmdAtomicUI :: MonadClientUI m => Bool -> CmdAtomic -> m () drawSfxAtomicUI :: MonadClientUI m => Bool -> SfxAtomic -> m () -- | Running and disturbance. module Game.LambdaHack.Client.RunAction -- | Start running in the given direction and with the given number of -- tiles already traversed (usually 0). The first turn of running -- succeeds much more often than subsequent turns, because most of the -- disturbances are ignored, since the player is aware of them and still -- explicitly requests a run. canRun :: MonadClient m => ActorId -> (Vector, Int) -> m Bool -- | This function implements the actual logic of running. It checks if we -- have to stop running because something interesting cropped up, it -- ajusts the direction given by the vector if we reached a corridor's -- corner (we never change direction except in corridors) and it -- increments the counter of traversed tiles. continueRunDir :: MonadClientAbort m => ActorId -> (Vector, Int) -> m (Vector, Int) -- | AI strategy operations implemented with the Action monad. module Game.LambdaHack.Client.StrategyAction -- | AI proposes possible targets for the actor. Never empty. targetStrategy :: MonadClient m => ActorId -> [Ability] -> m (Strategy (Maybe Target)) -- | AI strategy based on actor's sight, smell, intelligence, etc. Never -- empty. actionStrategy :: MonadClient m => ActorId -> [Ability] -> m (Strategy CmdSer) visibleFoes :: MonadActionRO m => FactionPers -> ActorId -> m [(ActorId, Actor)] -- | Semantics of Cmd client commands that return server commands. A -- couple of them do not take time, the rest does. TODO: document module Game.LambdaHack.Client.HumanGlobal moveLeader :: MonadClientUI m => Vector -> m CmdSer exploreLeader :: MonadClientUI m => Vector -> m CmdSer runLeader :: MonadClientUI m => Vector -> m CmdSer -- | Leader waits a turn (and blocks, etc.). waitHuman :: MonadClientUI m => m CmdSer pickupHuman :: (MonadClientAbort m, MonadClientUI m) => m CmdSer -- | Drop a single item. dropHuman :: (MonadClientAbort m, MonadClientUI m) => m CmdSer projectLeader :: (MonadClientAbort m, MonadClientUI m) => [Trigger] -> m CmdSer applyHuman :: (MonadClientAbort m, MonadClientUI m) => [Trigger] -> m CmdSer -- | Ask for a direction and trigger a tile, if possible. triggerDirHuman :: (MonadClientAbort m, MonadClientUI m) => [Trigger] -> m CmdSer -- | Leader tries to trigger the tile he's standing on. triggerTileHuman :: (MonadClientAbort m, MonadClientUI m) => [Trigger] -> m CmdSer gameRestartHuman :: (MonadClientAbort m, MonadClientUI m) => Text -> m CmdSer gameExitHuman :: (MonadClientAbort m, MonadClientUI m) => m CmdSer gameSaveHuman :: MonadClientUI m => m CmdSer cfgDumpHuman :: MonadClientUI m => m CmdSer instance Eq ItemDialogState -- | Semantics of human player commands. module Game.LambdaHack.Client.HumanSem -- | The semantics of human player commands in terms of the Action -- monad. Decides if the action takes time and what action to perform. -- Time cosuming commands are marked as such in help and cannot be -- invoked in targeting mode on a remote level (level different than the -- level of the selected hero). cmdHumanSem :: (MonadClientAbort m, MonadClientUI m) => HumanCmd -> WriterT Slideshow m (Maybe CmdSer) -- | Semantics of most CmdClientAI client commands. module Game.LambdaHack.Client.ClientSem queryAI :: MonadClient m => ActorId -> m CmdSer queryAIPick :: MonadClient m => ActorId -> m CmdSer -- | Handle the move of the hero. queryUI :: (MonadClientAbort m, MonadClientUI m) => ActorId -> m CmdSer -- | Continue running in the given direction. continueRun :: MonadClientAbort m => ActorId -> (Vector, Int) -> m CmdSer -- | Determine and process the next human player command. The argument is -- the last abort message due to running, if any. humanCommand :: (MonadClientAbort m, MonadClientUI m) => Msg -> m CmdSer -- | Semantics of client commands. See -- https://github.com/kosmikus/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Client cmdClientAISem :: (MonadAtomic m, MonadConnClient c m) => CmdClientAI -> m () cmdClientUISem :: (MonadAtomic m, MonadClientAbort m, MonadClientUI m, MonadConnClient c m) => CmdClientUI -> m () loopAI :: MonadConnClient CmdClientAI m => (CmdClientAI -> m ()) -> m () loopUI :: (MonadClientUI m, MonadConnClient CmdClientUI m) => (CmdClientUI -> m ()) -> m () -- | Wire together game content, the main loop of game clients, the main -- game loop assigned to this frontend (possibly containing the server -- loop, if the whole game runs in one process), UI config and the -- definitions of game commands. exeFrontend :: (MonadAtomic m, MonadClientAbort m, MonadClientUI m, MonadConnClient CmdClientUI m, MonadAtomic n, MonadConnClient CmdClientAI n) => (m () -> SessionUI -> State -> StateClient -> ConnServer CmdClientUI -> IO ()) -> (n () -> SessionUI -> State -> StateClient -> ConnServer CmdClientAI -> IO ()) -> COps -> ((FactionId -> ChanFrontend -> ChanServer CmdClientUI -> IO ()) -> (FactionId -> ChanServer CmdClientAI -> IO ()) -> IO ()) -> IO () class MonadActionRO m => MonadClient m class MonadClient m => MonadClientUI m class MonadClient m => MonadConnClient c m | m -> c