-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A game engine library for tactical squad ASCII roguelike dungeon crawlers -- -- LambdaHack is a Haskell game engine library for ASCII roguelike games -- of arbitrary theme, size and complexity, with optional tactical squad -- combat. It's packaged together with a sample dungeon crawler in -- fantasy setting that can be tried out in the browser: -- http://lambdahack.github.io (It runs fastest on Chrome. -- Keyboard commands and savefiles are supported only on recent enough -- versions of browsers. Mouse should work everywhere.) -- -- Please see the changelog file for recent improvements and the issue -- tracker for short-term plans. Long term goals include multiplayer -- tactical squad combat, in-game content creation, auto-balancing and -- persistent content modification based on player behaviour. -- Contributions are welcome. -- -- Games known to use the LambdaHack library: -- -- -- -- 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 when developing the -- library --- library users are free to access any modules, since the -- library authors are in no position to guess their particular needs. @package LambdaHack @version 0.8.1.2 -- | Custom Prelude, compatible across many GHC versions. module Game.LambdaHack.Common.Prelude -- | Append two lists, i.e., -- --
--   [x1, ..., xm] ++ [y1, ..., yn] == [x1, ..., xm, y1, ..., yn]
--   [x1, ..., xm] ++ [y1, ...] == [x1, ..., xm, y1, ...]
--   
-- -- If the first list is not finite, the result is the first list. (++) :: () => [a] -> [a] -> [a] infixr 5 ++ -- | The value of seq a b is bottom if a is bottom, and -- otherwise equal to b. In other words, it evaluates the first -- argument a to weak head normal form (WHNF). seq is -- usually introduced to improve performance by avoiding unneeded -- laziness. -- -- A note on evaluation order: the expression seq a b does -- not guarantee that a will be evaluated before -- b. The only guarantee given by seq is that the both -- a and b will be evaluated before seq -- returns a value. In particular, this means that b may be -- evaluated before a. If you need to guarantee a specific order -- of evaluation, you must use the function pseq from the -- "parallel" package. seq :: () => a -> b -> b -- | filter, applied to a predicate and a list, returns the list of -- those elements that satisfy the predicate; i.e., -- --
--   filter p xs = [ x | x <- xs, p x]
--   
filter :: () => a -> Bool -> [a] -> [a] -- | zip takes two lists and returns a list of corresponding pairs. -- If one input list is short, excess elements of the longer list are -- discarded. -- -- zip is right-lazy: -- --
--   zip [] _|_ = []
--   
zip :: () => [a] -> [b] -> [(a, b)] -- | The print function outputs a value of any printable type to the -- standard output device. Printable types are those that are instances -- of class Show; print converts values to strings for -- output using the show operation and adds a newline. -- -- For example, a program to print the first 20 integers and their powers -- of 2 could be written as: -- --
--   main = print ([(n, 2^n) | n <- [0..19]])
--   
print :: Show a => a -> IO () -- | Extract the first component of a pair. fst :: () => (a, b) -> a -- | Extract the second component of a pair. snd :: () => (a, b) -> b -- | otherwise is defined as the value True. It helps to make -- guards more readable. eg. -- --
--   f x | x < 0     = ...
--       | otherwise = ...
--   
otherwise :: Bool -- | map f xs is the list obtained by applying f -- to each element of xs, i.e., -- --
--   map f [x1, x2, ..., xn] == [f x1, f x2, ..., f xn]
--   map f [x1, x2, ...] == [f x1, f x2, ...]
--   
map :: () => a -> b -> [a] -> [b] -- | Application operator. This operator is redundant, since ordinary -- application (f x) means the same as (f $ x). -- However, $ has low, right-associative binding precedence, so it -- sometimes allows parentheses to be omitted; for example: -- --
--   f $ g $ h x  =  f (g (h x))
--   
-- -- It is also useful in higher-order situations, such as map -- ($ 0) xs, or zipWith ($) fs xs. ($) :: () => a -> b -> a -> b infixr 0 $ -- | general coercion from integral types fromIntegral :: (Integral a, Num b) => a -> b -- | general coercion to fractional types realToFrac :: (Real a, Fractional b) => a -> b -- | The Bounded class is used to name the upper and lower limits of -- a type. Ord is not a superclass of Bounded since types -- that are not totally ordered may also have upper and lower bounds. -- -- The Bounded class may be derived for any enumeration type; -- minBound is the first constructor listed in the data -- declaration and maxBound is the last. Bounded may also -- be derived for single-constructor datatypes whose constituent types -- are in Bounded. class Bounded a minBound :: Bounded a => a maxBound :: Bounded a => a -- | Class Enum defines operations on sequentially ordered types. -- -- The enumFrom... methods are used in Haskell's translation of -- arithmetic sequences. -- -- Instances of Enum may be derived for any enumeration type -- (types whose constructors have no fields). The nullary constructors -- are assumed to be numbered left-to-right by fromEnum from -- 0 through n-1. See Chapter 10 of the Haskell -- Report for more details. -- -- For any type that is an instance of class Bounded as well as -- Enum, the following should hold: -- -- -- --
--   enumFrom     x   = enumFromTo     x maxBound
--   enumFromThen x y = enumFromThenTo x y bound
--     where
--       bound | fromEnum y >= fromEnum x = maxBound
--             | otherwise                = minBound
--   
class Enum a -- | the successor of a value. For numeric types, succ adds 1. succ :: Enum a => a -> a -- | the predecessor of a value. For numeric types, pred subtracts -- 1. pred :: Enum a => a -> a -- | Convert from an Int. toEnum :: Enum a => Int -> a -- | Convert to an Int. It is implementation-dependent what -- fromEnum returns when applied to a value that is too large to -- fit in an Int. fromEnum :: Enum a => a -> Int -- | Used in Haskell's translation of [n..]. enumFrom :: Enum a => a -> [a] -- | Used in Haskell's translation of [n,n'..]. enumFromThen :: Enum a => a -> a -> [a] -- | Used in Haskell's translation of [n..m]. enumFromTo :: Enum a => a -> a -> [a] -- | Used in Haskell's translation of [n,n'..m]. enumFromThenTo :: Enum a => a -> a -> a -> [a] -- | The Eq class defines equality (==) and inequality -- (/=). All the basic datatypes exported by the Prelude -- are instances of Eq, and Eq may be derived for any -- datatype whose constituents are also instances of Eq. -- -- Minimal complete definition: either == or /=. class Eq a (==) :: Eq a => a -> a -> Bool (/=) :: Eq a => a -> a -> Bool -- | Trigonometric and hyperbolic functions and related functions. class Fractional a => Floating a pi :: Floating a => a exp :: Floating a => a -> a log :: Floating a => a -> a sqrt :: Floating a => a -> a (**) :: Floating a => a -> a -> a logBase :: Floating a => a -> a -> a sin :: Floating a => a -> a cos :: Floating a => a -> a tan :: Floating a => a -> a asin :: Floating a => a -> a acos :: Floating a => a -> a atan :: Floating a => a -> a sinh :: Floating a => a -> a cosh :: Floating a => a -> a tanh :: Floating a => a -> a asinh :: Floating a => a -> a acosh :: Floating a => a -> a atanh :: Floating a => a -> a -- | Fractional numbers, supporting real division. class Num a => Fractional a -- | fractional division (/) :: Fractional a => a -> a -> a -- | reciprocal fraction recip :: Fractional a => a -> a -- | Conversion from a Rational (that is Ratio -- Integer). A floating literal stands for an application of -- fromRational to a value of type Rational, so such -- literals have type (Fractional a) => a. fromRational :: Fractional a => Rational -> a -- | Integral numbers, supporting integer division. class (Real a, Enum a) => Integral a -- | integer division truncated toward zero quot :: Integral a => a -> a -> a -- | integer remainder, satisfying -- --
--   (x `quot` y)*y + (x `rem` y) == x
--   
rem :: Integral a => a -> a -> a -- | integer division truncated toward negative infinity div :: Integral a => a -> a -> a -- | integer modulus, satisfying -- --
--   (x `div` y)*y + (x `mod` y) == x
--   
mod :: Integral a => a -> a -> a -- | simultaneous quot and rem quotRem :: Integral a => a -> a -> (a, a) -- | simultaneous div and mod divMod :: Integral a => a -> a -> (a, a) -- | conversion to Integer toInteger :: Integral a => a -> Integer -- | The Monad class defines the basic operations over a -- monad, a concept from a branch of mathematics known as -- category theory. From the perspective of a Haskell programmer, -- however, it is best to think of a monad as an abstract datatype -- of actions. Haskell's do expressions provide a convenient -- syntax for writing monadic expressions. -- -- Instances of Monad should satisfy the following laws: -- -- -- -- Furthermore, the Monad and Applicative operations should -- relate as follows: -- -- -- -- The above laws imply: -- -- -- -- and that pure and (<*>) satisfy the applicative -- functor laws. -- -- The instances of Monad for lists, Maybe and IO -- defined in the Prelude satisfy these laws. class Applicative m => Monad (m :: * -> *) -- | Sequentially compose two actions, passing any value produced by the -- first as an argument to the second. (>>=) :: Monad m => m a -> a -> m b -> m b -- | Sequentially compose two actions, discarding any value produced by the -- first, like sequencing operators (such as the semicolon) in imperative -- languages. (>>) :: Monad m => m a -> m b -> m b -- | Inject a value into the monadic type. return :: Monad m => a -> m a -- | Fail with a message. This operation is not part of the mathematical -- definition of a monad, but is invoked on pattern-match failure in a -- do expression. -- -- As part of the MonadFail proposal (MFP), this function is moved to its -- own class MonadFail (see Control.Monad.Fail for more -- details). The definition here will be removed in a future release. fail :: Monad m => String -> m a -- | The Functor class is used for types that can be mapped over. -- Instances of Functor should satisfy the following laws: -- --
--   fmap id  ==  id
--   fmap (f . g)  ==  fmap f . fmap g
--   
-- -- The instances of Functor for lists, Maybe and IO -- satisfy these laws. class Functor (f :: * -> *) fmap :: Functor f => a -> b -> f a -> f b -- | Replace all locations in the input with the same value. The default -- definition is fmap . const, but this may be -- overridden with a more efficient version. (<$) :: Functor f => a -> f b -> f a -- | Basic numeric class. class Num a (+) :: Num a => a -> a -> a (-) :: Num a => a -> a -> a (*) :: Num a => a -> a -> a -- | Unary negation. negate :: Num a => a -> a -- | Absolute value. abs :: Num a => a -> a -- | Sign of a number. The functions abs and signum should -- satisfy the law: -- --
--   abs x * signum x == x
--   
-- -- For real numbers, the signum is either -1 (negative), -- 0 (zero) or 1 (positive). signum :: Num a => a -> a -- | Conversion from an Integer. An integer literal represents the -- application of the function fromInteger to the appropriate -- value of type Integer, so such literals have type -- (Num a) => a. fromInteger :: Num a => Integer -> a -- | The Ord class is used for totally ordered datatypes. -- -- Instances of Ord can be derived for any user-defined datatype -- whose constituent types are in Ord. The declared order of the -- constructors in the data declaration determines the ordering in -- derived Ord instances. The Ordering datatype allows a -- single comparison to determine the precise ordering of two objects. -- -- Minimal complete definition: either compare or <=. -- Using compare can be more efficient for complex types. class Eq a => Ord a compare :: Ord a => a -> a -> Ordering (<) :: Ord a => a -> a -> Bool (<=) :: Ord a => a -> a -> Bool (>) :: Ord a => a -> a -> Bool (>=) :: Ord a => a -> a -> Bool max :: Ord a => a -> a -> a min :: Ord a => a -> a -> a -- | Parsing of Strings, producing values. -- -- Derived instances of Read make the following assumptions, which -- derived instances of Show obey: -- -- -- -- For example, given the declarations -- --
--   infixr 5 :^:
--   data Tree a =  Leaf a  |  Tree a :^: Tree a
--   
-- -- the derived instance of Read in Haskell 2010 is equivalent to -- --
--   instance (Read a) => Read (Tree a) where
--   
--           readsPrec d r =  readParen (d > app_prec)
--                            (\r -> [(Leaf m,t) |
--                                    ("Leaf",s) <- lex r,
--                                    (m,t) <- readsPrec (app_prec+1) s]) r
--   
--                         ++ readParen (d > up_prec)
--                            (\r -> [(u:^:v,w) |
--                                    (u,s) <- readsPrec (up_prec+1) r,
--                                    (":^:",t) <- lex s,
--                                    (v,w) <- readsPrec (up_prec+1) t]) r
--   
--             where app_prec = 10
--                   up_prec = 5
--   
-- -- Note that right-associativity of :^: is unused. -- -- The derived instance in GHC is equivalent to -- --
--   instance (Read a) => Read (Tree a) where
--   
--           readPrec = parens $ (prec app_prec $ do
--                                    Ident "Leaf" <- lexP
--                                    m <- step readPrec
--                                    return (Leaf m))
--   
--                        +++ (prec up_prec $ do
--                                    u <- step readPrec
--                                    Symbol ":^:" <- lexP
--                                    v <- step readPrec
--                                    return (u :^: v))
--   
--             where app_prec = 10
--                   up_prec = 5
--   
--           readListPrec = readListPrecDefault
--   
-- -- Why do both readsPrec and readPrec exist, and why does -- GHC opt to implement readPrec in derived Read instances -- instead of readsPrec? The reason is that readsPrec is -- based on the ReadS type, and although ReadS is mentioned -- in the Haskell 2010 Report, it is not a very efficient parser data -- structure. -- -- readPrec, on the other hand, is based on a much more efficient -- ReadPrec datatype (a.k.a "new-style parsers"), but its -- definition relies on the use of the RankNTypes language -- extension. Therefore, readPrec (and its cousin, -- readListPrec) are marked as GHC-only. Nevertheless, it is -- recommended to use readPrec instead of readsPrec -- whenever possible for the efficiency improvements it brings. -- -- As mentioned above, derived Read instances in GHC will -- implement readPrec instead of readsPrec. The default -- implementations of readsPrec (and its cousin, readList) -- will simply use readPrec under the hood. If you are writing a -- Read instance by hand, it is recommended to write it like so: -- --
--   instance Read T where
--     readPrec     = ...
--     readListPrec = readListPrecDefault
--   
class Read a -- | attempts to parse a value from the front of the string, returning a -- list of (parsed value, remaining string) pairs. If there is no -- successful parse, the returned list is empty. -- -- Derived instances of Read and Show satisfy the -- following: -- -- -- -- That is, readsPrec parses the string produced by -- showsPrec, and delivers the value that showsPrec started -- with. readsPrec :: Read a => Int -> ReadS a -- | The method readList is provided to allow the programmer to give -- a specialised way of parsing lists of values. For example, this is -- used by the predefined Read instance of the Char type, -- where values of type String should be are expected to use -- double quotes, rather than square brackets. readList :: Read a => ReadS [a] class (Num a, Ord a) => Real a -- | the rational equivalent of its real argument with full precision toRational :: Real a => a -> Rational -- | Efficient, machine-independent access to the components of a -- floating-point number. class (RealFrac a, Floating a) => RealFloat a -- | a constant function, returning the radix of the representation (often -- 2) floatRadix :: RealFloat a => a -> Integer -- | a constant function, returning the number of digits of -- floatRadix in the significand floatDigits :: RealFloat a => a -> Int -- | a constant function, returning the lowest and highest values the -- exponent may assume floatRange :: RealFloat a => a -> (Int, Int) -- | The function decodeFloat applied to a real floating-point -- number returns the significand expressed as an Integer and an -- appropriately scaled exponent (an Int). If -- decodeFloat x yields (m,n), then x -- is equal in value to m*b^^n, where b is the -- floating-point radix, and furthermore, either m and -- n are both zero or else b^(d-1) <= abs m < -- b^d, where d is the value of floatDigits -- x. In particular, decodeFloat 0 = (0,0). If the -- type contains a negative zero, also decodeFloat (-0.0) = -- (0,0). The result of decodeFloat x is -- unspecified if either of isNaN x or -- isInfinite x is True. decodeFloat :: RealFloat a => a -> (Integer, Int) -- | encodeFloat performs the inverse of decodeFloat in the -- sense that for finite x with the exception of -0.0, -- uncurry encodeFloat (decodeFloat x) = -- x. encodeFloat m n is one of the two closest -- representable floating-point numbers to m*b^^n (or -- ±Infinity if overflow occurs); usually the closer, but if -- m contains too many bits, the result may be rounded in the -- wrong direction. encodeFloat :: RealFloat a => Integer -> Int -> a -- | exponent corresponds to the second component of -- decodeFloat. exponent 0 = 0 and for finite -- nonzero x, exponent x = snd (decodeFloat x) -- + floatDigits x. If x is a finite floating-point -- number, it is equal in value to significand x * b ^^ -- exponent x, where b is the floating-point radix. -- The behaviour is unspecified on infinite or NaN values. exponent :: RealFloat a => a -> Int -- | The first component of decodeFloat, scaled to lie in the open -- interval (-1,1), either 0.0 or of absolute -- value >= 1/b, where b is the floating-point -- radix. The behaviour is unspecified on infinite or NaN -- values. significand :: RealFloat a => a -> a -- | multiplies a floating-point number by an integer power of the radix scaleFloat :: RealFloat a => Int -> a -> a -- | True if the argument is an IEEE "not-a-number" (NaN) value isNaN :: RealFloat a => a -> Bool -- | True if the argument is an IEEE infinity or negative infinity isInfinite :: RealFloat a => a -> Bool -- | True if the argument is too small to be represented in -- normalized format isDenormalized :: RealFloat a => a -> Bool -- | True if the argument is an IEEE negative zero isNegativeZero :: RealFloat a => a -> Bool -- | True if the argument is an IEEE floating point number isIEEE :: RealFloat a => a -> Bool -- | a version of arctangent taking two real floating-point arguments. For -- real floating x and y, atan2 y x -- computes the angle (from the positive x-axis) of the vector from the -- origin to the point (x,y). atan2 y x returns -- a value in the range [-pi, pi]. It follows the -- Common Lisp semantics for the origin when signed zeroes are supported. -- atan2 y 1, with y in a type that is -- RealFloat, should return the same value as atan -- y. A default definition of atan2 is provided, but -- implementors can provide a more accurate implementation. atan2 :: RealFloat a => a -> a -> a -- | Extracting components of fractions. class (Real a, Fractional a) => RealFrac a -- | The function properFraction takes a real fractional number -- x and returns a pair (n,f) such that x = -- n+f, and: -- -- -- -- The default definitions of the ceiling, floor, -- truncate and round functions are in terms of -- properFraction. properFraction :: (RealFrac a, Integral b) => a -> (b, a) -- | truncate x returns the integer nearest x -- between zero and x truncate :: (RealFrac a, Integral b) => a -> b -- | round x returns the nearest integer to x; the -- even integer if x is equidistant between two integers round :: (RealFrac a, Integral b) => a -> b -- | ceiling x returns the least integer not less than -- x ceiling :: (RealFrac a, Integral b) => a -> b -- | floor x returns the greatest integer not greater than -- x floor :: (RealFrac a, Integral b) => a -> b -- | Conversion of values to readable Strings. -- -- Derived instances of Show have the following properties, which -- are compatible with derived instances of Read: -- -- -- -- For example, given the declarations -- --
--   infixr 5 :^:
--   data Tree a =  Leaf a  |  Tree a :^: Tree a
--   
-- -- the derived instance of Show is equivalent to -- --
--   instance (Show a) => Show (Tree a) where
--   
--          showsPrec d (Leaf m) = showParen (d > app_prec) $
--               showString "Leaf " . showsPrec (app_prec+1) m
--            where app_prec = 10
--   
--          showsPrec d (u :^: v) = showParen (d > up_prec) $
--               showsPrec (up_prec+1) u .
--               showString " :^: "      .
--               showsPrec (up_prec+1) v
--            where up_prec = 5
--   
-- -- Note that right-associativity of :^: is ignored. For example, -- -- class Show a -- | Convert a value to a readable String. -- -- showsPrec should satisfy the law -- --
--   showsPrec d x r ++ s  ==  showsPrec d x (r ++ s)
--   
-- -- Derived instances of Read and Show satisfy the -- following: -- -- -- -- That is, readsPrec parses the string produced by -- showsPrec, and delivers the value that showsPrec started -- with. showsPrec :: Show a => Int -> a -> ShowS -- | A specialised variant of showsPrec, using precedence context -- zero, and returning an ordinary String. show :: Show a => a -> String -- | The method showList is provided to allow the programmer to give -- a specialised way of showing lists of values. For example, this is -- used by the predefined Show instance of the Char type, -- where values of type String should be shown in double quotes, -- rather than between square brackets. showList :: Show a => [a] -> ShowS -- | A functor with application, providing operations to -- -- -- -- A minimal complete definition must include implementations of -- pure and of either <*> or liftA2. If it -- defines both, then they must behave the same as their default -- definitions: -- --
--   (<*>) = liftA2 id
--   
-- --
--   liftA2 f x y = f <$> x <*> y
--   
-- -- Further, any definition must satisfy the following: -- -- -- -- The other methods have the following default definitions, which may be -- overridden with equivalent specialized implementations: -- -- -- -- As a consequence of these laws, the Functor instance for -- f will satisfy -- -- -- -- It may be useful to note that supposing -- --
--   forall x y. p (q x y) = f x . g y
--   
-- -- it follows from the above that -- --
--   liftA2 p (liftA2 q u v) = liftA2 f u . liftA2 g v
--   
-- -- If f is also a Monad, it should satisfy -- -- -- -- (which implies that pure and <*> satisfy the -- applicative functor laws). class Functor f => Applicative (f :: * -> *) -- | Lift a value. pure :: Applicative f => a -> f a -- | Sequential application. -- -- A few functors support an implementation of <*> that is -- more efficient than the default one. (<*>) :: Applicative f => f a -> b -> f a -> f b -- | Sequence actions, discarding the value of the first argument. (*>) :: Applicative f => f a -> f b -> f b -- | Sequence actions, discarding the value of the second argument. (<*) :: Applicative f => f a -> f b -> f a -- | Data structures that can be folded. -- -- For example, given a data type -- --
--   data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
--   
-- -- a suitable instance would be -- --
--   instance Foldable Tree where
--      foldMap f Empty = mempty
--      foldMap f (Leaf x) = f x
--      foldMap f (Node l k r) = foldMap f l `mappend` f k `mappend` foldMap f r
--   
-- -- This is suitable even for abstract types, as the monoid is assumed to -- satisfy the monoid laws. Alternatively, one could define -- foldr: -- --
--   instance Foldable Tree where
--      foldr f z Empty = z
--      foldr f z (Leaf x) = f x z
--      foldr f z (Node l k r) = foldr f (f k (foldr f z r)) l
--   
-- -- Foldable instances are expected to satisfy the following -- laws: -- --
--   foldr f z t = appEndo (foldMap (Endo . f) t ) z
--   
-- --
--   foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
--   
-- --
--   fold = foldMap id
--   
-- --
--   length = getSum . foldMap (Sum . const  1)
--   
-- -- sum, product, maximum, and minimum -- should all be essentially equivalent to foldMap forms, such -- as -- --
--   sum = getSum . foldMap Sum
--   
-- -- but may be less defined. -- -- If the type is also a Functor instance, it should satisfy -- --
--   foldMap f = fold . fmap f
--   
-- -- which implies that -- --
--   foldMap f . fmap g = foldMap (f . g)
--   
class Foldable (t :: * -> *) -- | Map each element of the structure to a monoid, and combine the -- results. foldMap :: (Foldable t, Monoid m) => a -> m -> t a -> m -- | Right-associative fold of a structure. -- -- In the case of lists, foldr, when applied to a binary operator, -- a starting value (typically the right-identity of the operator), and a -- list, reduces the list using the binary operator, from right to left: -- --
--   foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)
--   
-- -- Note that, since the head of the resulting expression is produced by -- an application of the operator to the first element of the list, -- foldr can produce a terminating expression from an infinite -- list. -- -- For a general Foldable structure this should be semantically -- identical to, -- --
--   foldr f z = foldr f z . toList
--   
foldr :: Foldable t => a -> b -> b -> b -> t a -> b -- | Left-associative fold of a structure. -- -- In the case of lists, foldl, when applied to a binary operator, -- a starting value (typically the left-identity of the operator), and a -- list, reduces the list using the binary operator, from left to right: -- --
--   foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
--   
-- -- Note that to produce the outermost application of the operator the -- entire input list must be traversed. This means that foldl' -- will diverge if given an infinite list. -- -- Also note that if you want an efficient left-fold, you probably want -- to use foldl' instead of foldl. The reason for this is -- that latter does not force the "inner" results (e.g. z f -- x1 in the above example) before applying them to the operator -- (e.g. to (f x2)). This results in a thunk chain -- O(n) elements long, which then must be evaluated from the -- outside-in. -- -- For a general Foldable structure this should be semantically -- identical to, -- --
--   foldl f z = foldl f z . toList
--   
foldl :: Foldable t => b -> a -> b -> b -> t a -> b -- | A variant of foldr that has no base case, and thus may only be -- applied to non-empty structures. -- --
--   foldr1 f = foldr1 f . toList
--   
foldr1 :: Foldable t => a -> a -> a -> t a -> a -- | A variant of foldl that has no base case, and thus may only be -- applied to non-empty structures. -- --
--   foldl1 f = foldl1 f . toList
--   
foldl1 :: Foldable t => a -> a -> a -> t a -> a -- | Does the element occur in the structure? elem :: (Foldable t, Eq a) => a -> t a -> Bool -- | The largest element of a non-empty structure. maximum :: (Foldable t, Ord a) => t a -> a -- | The least element of a non-empty structure. minimum :: (Foldable t, Ord a) => t a -> a -- | The sum function computes the sum of the numbers of a -- structure. sum :: (Foldable t, Num a) => t a -> a -- | The product function computes the product of the numbers of a -- structure. product :: (Foldable t, Num a) => t a -> a -- | Functors representing data structures that can be traversed from left -- to right. -- -- A definition of traverse must satisfy the following laws: -- -- -- -- A definition of sequenceA must satisfy the following laws: -- -- -- -- where an applicative transformation is a function -- --
--   t :: (Applicative f, Applicative g) => f a -> g a
--   
-- -- preserving the Applicative operations, i.e. -- -- -- -- and the identity functor Identity and composition of functors -- Compose are defined as -- --
--   newtype Identity a = Identity a
--   
--   instance Functor Identity where
--     fmap f (Identity x) = Identity (f x)
--   
--   instance Applicative Identity where
--     pure x = Identity x
--     Identity f <*> Identity x = Identity (f x)
--   
--   newtype Compose f g a = Compose (f (g a))
--   
--   instance (Functor f, Functor g) => Functor (Compose f g) where
--     fmap f (Compose x) = Compose (fmap (fmap f) x)
--   
--   instance (Applicative f, Applicative g) => Applicative (Compose f g) where
--     pure x = Compose (pure (pure x))
--     Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
--   
-- -- (The naturality law is implied by parametricity.) -- -- Instances are similar to Functor, e.g. given a data type -- --
--   data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
--   
-- -- a suitable instance would be -- --
--   instance Traversable Tree where
--      traverse f Empty = pure Empty
--      traverse f (Leaf x) = Leaf <$> f x
--      traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r
--   
-- -- This is suitable even for abstract types, as the laws for -- <*> imply a form of associativity. -- -- The superclass instances should satisfy the following: -- -- class (Functor t, Foldable t) => Traversable (t :: * -> *) -- | Map each element of a structure to an action, evaluate these actions -- from left to right, and collect the results. For a version that -- ignores the results see traverse_. traverse :: (Traversable t, Applicative f) => a -> f b -> t a -> f t b -- | Evaluate each action in the structure from left to right, and and -- collect the results. For a version that ignores the results see -- sequenceA_. sequenceA :: (Traversable t, Applicative f) => t f a -> f t a -- | Map each element of a structure to a monadic action, evaluate these -- actions from left to right, and collect the results. For a version -- that ignores the results see mapM_. mapM :: (Traversable t, Monad m) => a -> m b -> t a -> m t b -- | Evaluate each monadic action in the structure from left to right, and -- collect the results. For a version that ignores the results see -- sequence_. sequence :: (Traversable t, Monad m) => t m a -> m t a -- | The class of semigroups (types with an associative binary operation). -- -- Instances should satisfy the associativity law: -- -- class Semigroup a -- | The class of monoids (types with an associative binary operation that -- has an identity). Instances should satisfy the following laws: -- -- -- -- The method names refer to the monoid of lists under concatenation, but -- there are many other instances. -- -- Some types can be viewed as a monoid in more than one way, e.g. both -- addition and multiplication on numbers. In such cases we often define -- newtypes and make those instances of Monoid, e.g. -- Sum and Product. -- -- NOTE: Semigroup is a superclass of Monoid since -- base-4.11.0.0. class Semigroup a => Monoid a -- | Identity of mappend mempty :: Monoid a => a -- | An associative operation -- -- NOTE: This method is redundant and has the default -- implementation mappend = '(<>)' since -- base-4.11.0.0. mappend :: Monoid a => a -> a -> a -- | Fold a list using the monoid. -- -- For most types, the default definition for mconcat will be -- used, but the function is included in the class definition so that an -- optimized version can be provided for specific types. mconcat :: Monoid a => [a] -> a data Bool False :: Bool True :: Bool -- | The character type Char is an enumeration whose values -- represent Unicode (or equivalently ISO/IEC 10646) code points (i.e. -- characters, see http://www.unicode.org/ for details). This set -- extends the ISO 8859-1 (Latin-1) character set (the first 256 -- characters), which is itself an extension of the ASCII character set -- (the first 128 characters). A character literal in Haskell has type -- Char. -- -- To convert a Char to or from the corresponding Int value -- defined by Unicode, use toEnum and fromEnum from the -- Enum class respectively (or equivalently ord and -- chr). data Char -- | Double-precision floating point numbers. It is desirable that this -- type be at least equal in range and precision to the IEEE -- double-precision type. data Double -- | Single-precision floating point numbers. It is desirable that this -- type be at least equal in range and precision to the IEEE -- single-precision type. data Float -- | A fixed-precision integer type with at least the range [-2^29 .. -- 2^29-1]. The exact range for a given implementation can be -- determined by using minBound and maxBound from the -- Bounded class. data Int -- | Invariant: Jn# and Jp# are used iff value doesn't fit in -- S# -- -- Useful properties resulting from the invariants: -- -- data Integer -- | The Maybe type encapsulates an optional value. A value of type -- Maybe a either contains a value of type a -- (represented as Just a), or it is empty (represented -- as Nothing). Using Maybe is a good way to deal with -- errors or exceptional cases without resorting to drastic measures such -- as error. -- -- The Maybe type is also a monad. It is a simple kind of error -- monad, where all errors are represented by Nothing. A richer -- error monad can be built using the Either type. data Maybe a Nothing :: Maybe a Just :: a -> Maybe a data Ordering LT :: Ordering EQ :: Ordering GT :: Ordering -- | Arbitrary-precision rational numbers, represented as a ratio of two -- Integer values. A rational number may be constructed using the -- % operator. type Rational = Ratio Integer -- | A value of type IO a is a computation which, when -- performed, does some I/O before returning a value of type a. -- -- There is really only one way to "perform" an I/O action: bind it to -- Main.main in your program. When your program is run, the I/O -- will be performed. It isn't possible to perform I/O from an arbitrary -- function, unless that function is itself in the IO monad and -- called at some point, directly or indirectly, from Main.main. -- -- IO is a monad, so IO actions can be combined using -- either the do-notation or the >> and >>= -- operations from the Monad class. data IO a -- | A Word is an unsigned integral type, with the same size as -- Int. data Word -- | The Either type represents values with two possibilities: a -- value of type Either a b is either Left -- a or Right b. -- -- The Either type is sometimes used to represent a value which is -- either correct or an error; by convention, the Left constructor -- is used to hold an error value and the Right constructor is -- used to hold a correct value (mnemonic: "right" also means "correct"). -- --

Examples

-- -- The type Either String Int is the type -- of values which can be either a String or an Int. The -- Left constructor can be used only on Strings, and the -- Right constructor can be used only on Ints: -- --
--   >>> let s = Left "foo" :: Either String Int
--   
--   >>> s
--   Left "foo"
--   
--   >>> let n = Right 3 :: Either String Int
--   
--   >>> n
--   Right 3
--   
--   >>> :type s
--   s :: Either String Int
--   
--   >>> :type n
--   n :: Either String Int
--   
-- -- The fmap from our Functor instance will ignore -- Left values, but will apply the supplied function to values -- contained in a Right: -- --
--   >>> let s = Left "foo" :: Either String Int
--   
--   >>> let n = Right 3 :: Either String Int
--   
--   >>> fmap (*2) s
--   Left "foo"
--   
--   >>> fmap (*2) n
--   Right 6
--   
-- -- The Monad instance for Either allows us to chain -- together multiple actions which may fail, and fail overall if any of -- the individual steps failed. First we'll write a function that can -- either parse an Int from a Char, or fail. -- --
--   >>> import Data.Char ( digitToInt, isDigit )
--   
--   >>> :{
--       let parseEither :: Char -> Either String Int
--           parseEither c
--             | isDigit c = Right (digitToInt c)
--             | otherwise = Left "parse error"
--   
--   >>> :}
--   
-- -- The following should work, since both '1' and '2' -- can be parsed as Ints. -- --
--   >>> :{
--       let parseMultiple :: Either String Int
--           parseMultiple = do
--             x <- parseEither '1'
--             y <- parseEither '2'
--             return (x + y)
--   
--   >>> :}
--   
-- --
--   >>> parseMultiple
--   Right 3
--   
-- -- But the following should fail overall, since the first operation where -- we attempt to parse 'm' as an Int will fail: -- --
--   >>> :{
--       let parseMultiple :: Either String Int
--           parseMultiple = do
--             x <- parseEither 'm'
--             y <- parseEither '2'
--             return (x + y)
--   
--   >>> :}
--   
-- --
--   >>> parseMultiple
--   Left "parse error"
--   
data Either a b Left :: a -> Either a b Right :: b -> Either a b -- | A String is a list of characters. String constants in Haskell -- are values of type String. type String = [Char] -- | The shows functions return a function that prepends the -- output String to an existing String. This allows -- constant-time concatenation of results using function composition. type ShowS = String -> String -- | error stops execution and displays an error message. error :: HasCallStack => [Char] -> a -- | The readIO function is similar to read except that it -- signals parse failure to the IO monad instead of terminating -- the program. readIO :: Read a => String -> IO a -- | The readLn function combines getLine and readIO. readLn :: Read a => IO a -- | The interact function takes a function of type -- String->String as its argument. The entire input from the -- standard input device is passed to this function as its argument, and -- the resulting string is output on the standard output device. interact :: String -> String -> IO () -- | The getContents operation returns all user input as a single -- string, which is read lazily as it is needed (same as -- hGetContents stdin). getContents :: IO String -- | Read a line from the standard input device (same as hGetLine -- stdin). getLine :: IO String -- | Read a character from the standard input device (same as -- hGetChar stdin). getChar :: IO Char -- | The same as putStr, but adds a newline character. putStrLn :: String -> IO () -- | Write a string to the standard output device (same as hPutStr -- stdout). putStr :: String -> IO () -- | Write a character to the standard output device (same as -- hPutChar stdout). putChar :: Char -> IO () -- | Raise an IOError in the IO monad. ioError :: () => IOError -> IO a -- | File and directory names are values of type String, whose -- precise meaning is operating system dependent. Files can be opened, -- yielding a handle which can then be used to operate on the contents of -- that file. type FilePath = String -- | Construct an IOError value with a string describing the error. -- The fail method of the IO instance of the Monad -- class raises a userError, thus: -- --
--   instance Monad IO where
--     ...
--     fail s = ioError (userError s)
--   
userError :: String -> IOError -- | The Haskell 2010 type for exceptions in the IO monad. Any I/O -- operation may raise an IOError instead of returning a result. -- For a more general type of exception, including also those that arise -- in pure code, see Exception. -- -- In Haskell 2010, this is an opaque type. type IOError = IOException -- | notElem is the negation of elem. notElem :: (Foldable t, Eq a) => a -> t a -> Bool infix 4 `notElem` -- | Determines whether all elements of the structure satisfy the -- predicate. all :: Foldable t => a -> Bool -> t a -> Bool -- | Determines whether any element of the structure satisfies the -- predicate. any :: Foldable t => a -> Bool -> t a -> Bool -- | or returns the disjunction of a container of Bools. For the -- result to be False, the container must be finite; True, -- however, results from a True value finitely far from the left -- end. or :: Foldable t => t Bool -> Bool -- | and returns the conjunction of a container of Bools. For the -- result to be True, the container must be finite; False, -- however, results from a False value finitely far from the left -- end. and :: Foldable t => t Bool -> Bool -- | Map a function over all the elements of a container and concatenate -- the resulting lists. concatMap :: Foldable t => a -> [b] -> t a -> [b] -- | The concatenation of all the elements of a container of lists. concat :: Foldable t => t [a] -> [a] -- | Evaluate each monadic action in the structure from left to right, and -- ignore the results. For a version that doesn't ignore the results see -- sequence. -- -- As of base 4.8.0.0, sequence_ is just sequenceA_, -- specialized to Monad. sequence_ :: (Foldable t, Monad m) => t m a -> m () -- | Map each element of a structure to a monadic action, evaluate these -- actions from left to right, and ignore the results. For a version that -- doesn't ignore the results see mapM. -- -- As of base 4.8.0.0, mapM_ is just traverse_, specialized -- to Monad. mapM_ :: (Foldable t, Monad m) => a -> m b -> t a -> m () -- | unwords is an inverse operation to words. It joins words -- with separating spaces. -- --
--   >>> unwords ["Lorem", "ipsum", "dolor"]
--   "Lorem ipsum dolor"
--   
unwords :: [String] -> String -- | words breaks a string up into a list of words, which were -- delimited by white space. -- --
--   >>> words "Lorem ipsum\ndolor"
--   ["Lorem","ipsum","dolor"]
--   
words :: String -> [String] -- | unlines is an inverse operation to lines. It joins -- lines, after appending a terminating newline to each. -- --
--   >>> unlines ["Hello", "World", "!"]
--   "Hello\nWorld\n!\n"
--   
unlines :: [String] -> String -- | lines breaks a string up into a list of strings at newline -- characters. The resulting strings do not contain newlines. -- -- Note that after splitting the string at newline characters, the last -- part of the string is considered a line even if it doesn't end with a -- newline. For example, -- --
--   >>> lines ""
--   []
--   
-- --
--   >>> lines "\n"
--   [""]
--   
-- --
--   >>> lines "one"
--   ["one"]
--   
-- --
--   >>> lines "one\n"
--   ["one"]
--   
-- --
--   >>> lines "one\n\n"
--   ["one",""]
--   
-- --
--   >>> lines "one\ntwo"
--   ["one","two"]
--   
-- --
--   >>> lines "one\ntwo\n"
--   ["one","two"]
--   
-- -- Thus lines s contains at least as many elements as -- newlines in s. lines :: String -> [String] -- | The read function reads input from a string, which must be -- completely consumed by the input process. read fails with an -- error if the parse is unsuccessful, and it is therefore -- discouraged from being used in real applications. Use readMaybe -- or readEither for safe alternatives. -- --
--   >>> read "123" :: Int
--   123
--   
-- --
--   >>> read "hello" :: Int
--   *** Exception: Prelude.read: no parse
--   
read :: Read a => String -> a -- | equivalent to readsPrec with a precedence of 0. reads :: Read a => ReadS a -- | Case analysis for the Either type. If the value is -- Left a, apply the first function to a; if it -- is Right b, apply the second function to b. -- --

Examples

-- -- We create two values of type Either String -- Int, one using the Left constructor and another -- using the Right constructor. Then we apply "either" the -- length function (if we have a String) or the -- "times-two" function (if we have an Int): -- --
--   >>> let s = Left "foo" :: Either String Int
--   
--   >>> let n = Right 3 :: Either String Int
--   
--   >>> either length (*2) s
--   3
--   
--   >>> either length (*2) n
--   6
--   
either :: () => a -> c -> b -> c -> Either a b -> c -- | The lex function reads a single lexeme from the input, -- discarding initial white space, and returning the characters that -- constitute the lexeme. If the input string contains only white space, -- lex returns a single successful `lexeme' consisting of the -- empty string. (Thus lex "" = [("","")].) If there is -- no legal lexeme at the beginning of the input string, lex fails -- (i.e. returns []). -- -- This lexer is not completely faithful to the Haskell lexical syntax in -- the following respects: -- -- lex :: ReadS String -- | readParen True p parses what p parses, -- but surrounded with parentheses. -- -- readParen False p parses what p -- parses, but optionally surrounded with parentheses. readParen :: () => Bool -> ReadS a -> ReadS a -- | A parser for a type a, represented as a function that takes a -- String and returns a list of possible parses as -- (a,String) pairs. -- -- Note that this kind of backtracking parser is very inefficient; -- reading a large structure may be quite slow (cf ReadP). type ReadS a = String -> [(a, String)] -- | An infix synonym for fmap. -- -- The name of this operator is an allusion to $. Note the -- similarities between their types: -- --
--    ($)  ::              (a -> b) ->   a ->   b
--   (<$>) :: Functor f => (a -> b) -> f a -> f b
--   
-- -- Whereas $ is function application, <$> is -- function application lifted over a Functor. -- --

Examples

-- -- Convert from a Maybe Int to a -- Maybe String using show: -- --
--   >>> show <$> Nothing
--   Nothing
--   
--   >>> show <$> Just 3
--   Just "3"
--   
-- -- Convert from an Either Int Int to -- an Either Int String using -- show: -- --
--   >>> show <$> Left 17
--   Left 17
--   
--   >>> show <$> Right 17
--   Right "17"
--   
-- -- Double each element of a list: -- --
--   >>> (*2) <$> [1,2,3]
--   [2,4,6]
--   
-- -- Apply even to the second element of a pair: -- --
--   >>> even <$> (2,2)
--   (2,True)
--   
(<$>) :: Functor f => a -> b -> f a -> f b infixl 4 <$> -- | lcm x y is the smallest positive integer that both -- x and y divide. lcm :: Integral a => a -> a -> a -- | gcd x y is the non-negative factor of both x -- and y of which every common factor of x and -- y is also a factor; for example gcd 4 2 = 2, -- gcd (-4) 6 = 2, gcd 0 4 = 4. -- gcd 0 0 = 0. (That is, the common divisor -- that is "greatest" in the divisibility preordering.) -- -- Note: Since for signed fixed-width integer types, abs -- minBound < 0, the result may be negative if one of the -- arguments is minBound (and necessarily is if the other -- is 0 or minBound) for such types. gcd :: Integral a => a -> a -> a -- | raise a number to an integral power (^^) :: (Fractional a, Integral b) => a -> b -> a infixr 8 ^^ -- | raise a number to a non-negative integral power (^) :: (Num a, Integral b) => a -> b -> a infixr 8 ^ odd :: Integral a => a -> Bool even :: Integral a => a -> Bool -- | utility function that surrounds the inner show function with -- parentheses when the Bool parameter is True. showParen :: Bool -> ShowS -> ShowS -- | utility function converting a String to a show function that -- simply prepends the string unchanged. showString :: String -> ShowS -- | utility function converting a Char to a show function that -- simply prepends the character unchanged. showChar :: Char -> ShowS -- | equivalent to showsPrec with a precedence of 0. shows :: Show a => a -> ShowS -- | The unzip3 function takes a list of triples and returns three -- lists, analogous to unzip. unzip3 :: () => [(a, b, c)] -> ([a], [b], [c]) -- | unzip transforms a list of pairs into a list of first -- components and a list of second components. unzip :: () => [(a, b)] -> ([a], [b]) -- | The zipWith3 function takes a function which combines three -- elements, as well as three lists and returns a list of their -- point-wise combination, analogous to zipWith. zipWith3 :: () => a -> b -> c -> d -> [a] -> [b] -> [c] -> [d] -- | zipWith generalises zip by zipping with the function -- given as the first argument, instead of a tupling function. For -- example, zipWith (+) is applied to two lists to -- produce the list of corresponding sums. -- -- zipWith is right-lazy: -- --
--   zipWith f [] _|_ = []
--   
zipWith :: () => a -> b -> c -> [a] -> [b] -> [c] -- | zip3 takes three lists and returns a list of triples, analogous -- to zip. zip3 :: () => [a] -> [b] -> [c] -> [(a, b, c)] -- | List index (subscript) operator, starting from 0. It is an instance of -- the more general genericIndex, which takes an index of any -- integral type. (!!) :: () => [a] -> Int -> a infixl 9 !! -- | lookup key assocs looks up a key in an association -- list. lookup :: Eq a => a -> [(a, b)] -> Maybe b -- | reverse xs returns the elements of xs in -- reverse order. xs must be finite. reverse :: () => [a] -> [a] -- | break, applied to a predicate p and a list -- xs, returns a tuple where first element is longest prefix -- (possibly empty) of xs of elements that do not satisfy -- p and second element is the remainder of the list: -- --
--   break (> 3) [1,2,3,4,1,2,3,4] == ([1,2,3],[4,1,2,3,4])
--   break (< 9) [1,2,3] == ([],[1,2,3])
--   break (> 9) [1,2,3] == ([1,2,3],[])
--   
-- -- break p is equivalent to span (not . -- p). break :: () => a -> Bool -> [a] -> ([a], [a]) -- | span, applied to a predicate p and a list xs, -- returns a tuple where first element is longest prefix (possibly empty) -- of xs of elements that satisfy p and second element -- is the remainder of the list: -- --
--   span (< 3) [1,2,3,4,1,2,3,4] == ([1,2],[3,4,1,2,3,4])
--   span (< 9) [1,2,3] == ([1,2,3],[])
--   span (< 0) [1,2,3] == ([],[1,2,3])
--   
-- -- span p xs is equivalent to (takeWhile p xs, -- dropWhile p xs) span :: () => a -> Bool -> [a] -> ([a], [a]) -- | splitAt n xs returns a tuple where first element is -- xs prefix of length n and second element is the -- remainder of the list: -- --
--   splitAt 6 "Hello World!" == ("Hello ","World!")
--   splitAt 3 [1,2,3,4,5] == ([1,2,3],[4,5])
--   splitAt 1 [1,2,3] == ([1],[2,3])
--   splitAt 3 [1,2,3] == ([1,2,3],[])
--   splitAt 4 [1,2,3] == ([1,2,3],[])
--   splitAt 0 [1,2,3] == ([],[1,2,3])
--   splitAt (-1) [1,2,3] == ([],[1,2,3])
--   
-- -- It is equivalent to (take n xs, drop n xs) when -- n is not _|_ (splitAt _|_ xs = _|_). -- splitAt is an instance of the more general -- genericSplitAt, in which n may be of any integral -- type. splitAt :: () => Int -> [a] -> ([a], [a]) -- | drop n xs returns the suffix of xs after the -- first n elements, or [] if n > length -- xs: -- --
--   drop 6 "Hello World!" == "World!"
--   drop 3 [1,2,3,4,5] == [4,5]
--   drop 3 [1,2] == []
--   drop 3 [] == []
--   drop (-1) [1,2] == [1,2]
--   drop 0 [1,2] == [1,2]
--   
-- -- It is an instance of the more general genericDrop, in which -- n may be of any integral type. drop :: () => Int -> [a] -> [a] -- | take n, applied to a list xs, returns the -- prefix of xs of length n, or xs itself if -- n > length xs: -- --
--   take 5 "Hello World!" == "Hello"
--   take 3 [1,2,3,4,5] == [1,2,3]
--   take 3 [1,2] == [1,2]
--   take 3 [] == []
--   take (-1) [1,2] == []
--   take 0 [1,2] == []
--   
-- -- It is an instance of the more general genericTake, in which -- n may be of any integral type. take :: () => Int -> [a] -> [a] -- | dropWhile p xs returns the suffix remaining after -- takeWhile p xs: -- --
--   dropWhile (< 3) [1,2,3,4,5,1,2,3] == [3,4,5,1,2,3]
--   dropWhile (< 9) [1,2,3] == []
--   dropWhile (< 0) [1,2,3] == [1,2,3]
--   
dropWhile :: () => a -> Bool -> [a] -> [a] -- | takeWhile, applied to a predicate p and a list -- xs, returns the longest prefix (possibly empty) of -- xs of elements that satisfy p: -- --
--   takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]
--   takeWhile (< 9) [1,2,3] == [1,2,3]
--   takeWhile (< 0) [1,2,3] == []
--   
takeWhile :: () => a -> Bool -> [a] -> [a] -- | cycle ties a finite list into a circular one, or equivalently, -- the infinite repetition of the original list. It is the identity on -- infinite lists. cycle :: () => [a] -> [a] -- | replicate n x is a list of length n with -- x the value of every element. It is an instance of the more -- general genericReplicate, in which n may be of any -- integral type. replicate :: () => Int -> a -> [a] -- | repeat x is an infinite list, with x the -- value of every element. repeat :: () => a -> [a] -- | iterate f x returns an infinite list of repeated -- applications of f to x: -- --
--   iterate f x == [x, f x, f (f x), ...]
--   
-- -- Note that iterate is lazy, potentially leading to thunk -- build-up if the consumer doesn't force each iterate. See 'iterate\'' -- for a strict variant of this function. iterate :: () => a -> a -> a -> [a] -- | scanr1 is a variant of scanr that has no starting value -- argument. scanr1 :: () => a -> a -> a -> [a] -> [a] -- | scanr is the right-to-left dual of scanl. Note that -- --
--   head (scanr f z xs) == foldr f z xs.
--   
scanr :: () => a -> b -> b -> b -> [a] -> [b] -- | scanl1 is a variant of scanl that has no starting value -- argument: -- --
--   scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
--   
scanl1 :: () => a -> a -> a -> [a] -> [a] -- | scanl is similar to foldl, but returns a list of -- successive reduced values from the left: -- --
--   scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
--   
-- -- Note that -- --
--   last (scanl f z xs) == foldl f z xs.
--   
scanl :: () => b -> a -> b -> b -> [a] -> [b] -- | Return all the elements of a list except the last one. The list must -- be non-empty. init :: () => [a] -> [a] -- | Extract the last element of a list, which must be finite and -- non-empty. last :: () => [a] -> a -- | Extract the elements after the head of a list, which must be -- non-empty. tail :: () => [a] -> [a] -- | Extract the first element of a list, which must be non-empty. head :: () => [a] -> a -- | The maybe function takes a default value, a function, and a -- Maybe value. If the Maybe value is Nothing, the -- function returns the default value. Otherwise, it applies the function -- to the value inside the Just and returns the result. -- --

Examples

-- -- Basic usage: -- --
--   >>> maybe False odd (Just 3)
--   True
--   
-- --
--   >>> maybe False odd Nothing
--   False
--   
-- -- Read an integer from a string using readMaybe. If we succeed, -- return twice the integer; that is, apply (*2) to it. If -- instead we fail to parse an integer, return 0 by default: -- --
--   >>> import Text.Read ( readMaybe )
--   
--   >>> maybe 0 (*2) (readMaybe "5")
--   10
--   
--   >>> maybe 0 (*2) (readMaybe "")
--   0
--   
-- -- Apply show to a Maybe Int. If we have Just -- n, we want to show the underlying Int n. But if -- we have Nothing, we return the empty string instead of (for -- example) "Nothing": -- --
--   >>> maybe "" show (Just 5)
--   "5"
--   
--   >>> maybe "" show Nothing
--   ""
--   
maybe :: () => b -> a -> b -> Maybe a -> b -- | uncurry converts a curried function to a function on pairs. -- --

Examples

-- --
--   >>> uncurry (+) (1,2)
--   3
--   
-- --
--   >>> uncurry ($) (show, 1)
--   "1"
--   
-- --
--   >>> map (uncurry max) [(1,2), (3,4), (6,8)]
--   [2,4,8]
--   
uncurry :: () => a -> b -> c -> (a, b) -> c -- | curry converts an uncurried function to a curried function. -- --

Examples

-- --
--   >>> curry fst 1 2
--   1
--   
curry :: () => (a, b) -> c -> a -> b -> c -- | the same as flip (-). -- -- Because - is treated specially in the Haskell grammar, -- (- e) is not a section, but an application of -- prefix negation. However, (subtract -- exp) is equivalent to the disallowed section. subtract :: Num a => a -> a -> a -- | asTypeOf is a type-restricted version of const. It is -- usually used as an infix operator, and its typing forces its first -- argument (which is usually overloaded) to have the same type as the -- second. asTypeOf :: () => a -> a -> a -- | until p f yields the result of applying f -- until p holds. until :: () => a -> Bool -> a -> a -> a -> a -- | Strict (call-by-value) application operator. It takes a function and -- an argument, evaluates the argument to weak head normal form (WHNF), -- then calls the function with that value. ($!) :: () => a -> b -> a -> b infixr 0 $! -- | flip f takes its (first) two arguments in the reverse -- order of f. -- --
--   >>> flip (++) "hello" "world"
--   "worldhello"
--   
flip :: () => a -> b -> c -> b -> a -> c -- | Function composition. (.) :: () => b -> c -> a -> b -> a -> c infixr 9 . -- | const x is a unary function which evaluates to x for -- all inputs. -- --
--   >>> const 42 "hello"
--   42
--   
-- --
--   >>> map (const 42) [0..3]
--   [42,42,42,42]
--   
const :: () => a -> b -> a -- | Identity function. -- --
--   id x = x
--   
id :: () => a -> a -- | Same as >>=, but with the arguments interchanged. (=<<) :: Monad m => a -> m b -> m a -> m b infixr 1 =<< -- | A special case of error. It is expected that compilers will -- recognize this and insert error messages which are more appropriate to -- the context in which undefined appears. undefined :: HasCallStack => a -- | A variant of error that does not produce a stack trace. errorWithoutStackTrace :: () => [Char] -> a -- | Boolean "and" (&&) :: Bool -> Bool -> Bool infixr 3 && -- | Boolean "or" (||) :: Bool -> Bool -> Bool infixr 2 || -- | Boolean "not" not :: Bool -> Bool -- | Append two lists, i.e., -- --
--   [x1, ..., xm] ++ [y1, ..., yn] == [x1, ..., xm, y1, ..., yn]
--   [x1, ..., xm] ++ [y1, ...] == [x1, ..., xm, y1, ...]
--   
-- -- If the first list is not finite, the result is the first list. (++) :: () => [a] -> [a] -> [a] infixr 5 ++ -- | filter, applied to a predicate and a list, returns the list of -- those elements that satisfy the predicate; i.e., -- --
--   filter p xs = [ x | x <- xs, p x]
--   
filter :: () => a -> Bool -> [a] -> [a] -- | zip takes two lists and returns a list of corresponding pairs. -- If one input list is short, excess elements of the longer list are -- discarded. -- -- zip is right-lazy: -- --
--   zip [] _|_ = []
--   
zip :: () => [a] -> [b] -> [(a, b)] -- | map f xs is the list obtained by applying f -- to each element of xs, i.e., -- --
--   map f [x1, x2, ..., xn] == [f x1, f x2, ..., f xn]
--   map f [x1, x2, ...] == [f x1, f x2, ...]
--   
map :: () => a -> b -> [a] -> [b] -- | Right-associative fold of a structure. -- -- In the case of lists, foldr, when applied to a binary operator, -- a starting value (typically the right-identity of the operator), and a -- list, reduces the list using the binary operator, from right to left: -- --
--   foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)
--   
-- -- Note that, since the head of the resulting expression is produced by -- an application of the operator to the first element of the list, -- foldr can produce a terminating expression from an infinite -- list. -- -- For a general Foldable structure this should be semantically -- identical to, -- --
--   foldr f z = foldr f z . toList
--   
foldr :: Foldable t => a -> b -> b -> b -> t a -> b -- | Left-associative fold of a structure. -- -- In the case of lists, foldl, when applied to a binary operator, -- a starting value (typically the left-identity of the operator), and a -- list, reduces the list using the binary operator, from left to right: -- --
--   foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
--   
-- -- Note that to produce the outermost application of the operator the -- entire input list must be traversed. This means that foldl' -- will diverge if given an infinite list. -- -- Also note that if you want an efficient left-fold, you probably want -- to use foldl' instead of foldl. The reason for this is -- that latter does not force the "inner" results (e.g. z f -- x1 in the above example) before applying them to the operator -- (e.g. to (f x2)). This results in a thunk chain -- O(n) elements long, which then must be evaluated from the -- outside-in. -- -- For a general Foldable structure this should be semantically -- identical to, -- --
--   foldl f z = foldl f z . toList
--   
foldl :: Foldable t => b -> a -> b -> b -> t a -> b -- | Left-associative fold of a structure but with strict application of -- the operator. -- -- This ensures that each step of the fold is forced to weak head normal -- form before being applied, avoiding the collection of thunks that -- would otherwise occur. This is often what you want to strictly reduce -- a finite list to a single, monolithic result (e.g. length). -- -- For a general Foldable structure this should be semantically -- identical to, -- --
--   foldl f z = foldl' f z . toList
--   
foldl' :: Foldable t => b -> a -> b -> b -> t a -> b -- | A variant of foldl that has no base case, and thus may only be -- applied to non-empty structures. -- --
--   foldl1 f = foldl1 f . toList
--   
foldl1 :: Foldable t => a -> a -> a -> t a -> a -- | The sum function computes the sum of the numbers of a -- structure. sum :: (Foldable t, Num a) => t a -> a -- | The product function computes the product of the numbers of a -- structure. product :: (Foldable t, Num a) => t a -> a -- | A variant of foldr that has no base case, and thus may only be -- applied to non-empty structures. -- --
--   foldr1 f = foldr1 f . toList
--   
foldr1 :: Foldable t => a -> a -> a -> t a -> a -- | The largest element of a non-empty structure. maximum :: (Foldable t, Ord a) => t a -> a -- | The least element of a non-empty structure. minimum :: (Foldable t, Ord a) => t a -> a -- | Does the element occur in the structure? elem :: (Foldable t, Eq a) => a -> t a -> Bool infix 4 `elem` -- | The isSubsequenceOf function takes two lists and returns -- True if all the elements of the first list occur, in order, in -- the second. The elements do not have to occur consecutively. -- -- isSubsequenceOf x y is equivalent to elem x -- (subsequences y). -- --

Examples

-- --
--   >>> isSubsequenceOf "GHC" "The Glorious Haskell Compiler"
--   True
--   
--   >>> isSubsequenceOf ['a','d'..'z'] ['a'..'z']
--   True
--   
--   >>> isSubsequenceOf [1..10] [10,9..0]
--   False
--   
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool -- | The mapAccumR function behaves like a combination of -- fmap and foldr; it applies a function to each element -- of a structure, passing an accumulating parameter from right to left, -- and returning a final value of this accumulator together with the new -- structure. mapAccumR :: Traversable t => a -> b -> (a, c) -> a -> t b -> (a, t c) -- | The mapAccumL function behaves like a combination of -- fmap and foldl; it applies a function to each element -- of a structure, passing an accumulating parameter from left to right, -- and returning a final value of this accumulator together with the new -- structure. mapAccumL :: Traversable t => a -> b -> (a, c) -> a -> t b -> (a, t c) -- | The find function takes a predicate and a structure and returns -- the leftmost element of the structure matching the predicate, or -- Nothing if there is no such element. find :: Foldable t => a -> Bool -> t a -> Maybe a -- | notElem is the negation of elem. notElem :: (Foldable t, Eq a) => a -> t a -> Bool infix 4 `notElem` -- | The least element of a non-empty structure with respect to the given -- comparison function. minimumBy :: Foldable t => a -> a -> Ordering -> t a -> a -- | The largest element of a non-empty structure with respect to the given -- comparison function. maximumBy :: Foldable t => a -> a -> Ordering -> t a -> a -- | Determines whether all elements of the structure satisfy the -- predicate. all :: Foldable t => a -> Bool -> t a -> Bool -- | Determines whether any element of the structure satisfies the -- predicate. any :: Foldable t => a -> Bool -> t a -> Bool -- | or returns the disjunction of a container of Bools. For the -- result to be False, the container must be finite; True, -- however, results from a True value finitely far from the left -- end. or :: Foldable t => t Bool -> Bool -- | and returns the conjunction of a container of Bools. For the -- result to be True, the container must be finite; False, -- however, results from a False value finitely far from the left -- end. and :: Foldable t => t Bool -> Bool -- | Map a function over all the elements of a container and concatenate -- the resulting lists. concatMap :: Foldable t => a -> [b] -> t a -> [b] -- | The concatenation of all the elements of a container of lists. concat :: Foldable t => t [a] -> [a] -- | unwords is an inverse operation to words. It joins words -- with separating spaces. -- --
--   >>> unwords ["Lorem", "ipsum", "dolor"]
--   "Lorem ipsum dolor"
--   
unwords :: [String] -> String -- | words breaks a string up into a list of words, which were -- delimited by white space. -- --
--   >>> words "Lorem ipsum\ndolor"
--   ["Lorem","ipsum","dolor"]
--   
words :: String -> [String] -- | unlines is an inverse operation to lines. It joins -- lines, after appending a terminating newline to each. -- --
--   >>> unlines ["Hello", "World", "!"]
--   "Hello\nWorld\n!\n"
--   
unlines :: [String] -> String -- | lines breaks a string up into a list of strings at newline -- characters. The resulting strings do not contain newlines. -- -- Note that after splitting the string at newline characters, the last -- part of the string is considered a line even if it doesn't end with a -- newline. For example, -- --
--   >>> lines ""
--   []
--   
-- --
--   >>> lines "\n"
--   [""]
--   
-- --
--   >>> lines "one"
--   ["one"]
--   
-- --
--   >>> lines "one\n"
--   ["one"]
--   
-- --
--   >>> lines "one\n\n"
--   ["one",""]
--   
-- --
--   >>> lines "one\ntwo"
--   ["one","two"]
--   
-- --
--   >>> lines "one\ntwo\n"
--   ["one","two"]
--   
-- -- Thus lines s contains at least as many elements as -- newlines in s. lines :: String -> [String] -- | The unfoldr function is a `dual' to foldr: while -- foldr reduces a list to a summary value, unfoldr builds -- a list from a seed value. The function takes the element and returns -- Nothing if it is done producing the list or returns Just -- (a,b), in which case, a is a prepended to the list -- and b is used as the next element in a recursive call. For -- example, -- --
--   iterate f == unfoldr (\x -> Just (x, f x))
--   
-- -- In some cases, unfoldr can undo a foldr operation: -- --
--   unfoldr f' (foldr f z xs) == xs
--   
-- -- if the following holds: -- --
--   f' (f x y) = Just (x,y)
--   f' z       = Nothing
--   
-- -- A simple use of unfoldr: -- --
--   >>> unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
--   [10,9,8,7,6,5,4,3,2,1]
--   
unfoldr :: () => b -> Maybe (a, b) -> b -> [a] -- | Sort a list by comparing the results of a key function applied to each -- element. sortOn f is equivalent to sortBy (comparing -- f), but has the performance advantage of only evaluating -- f once for each element in the input list. This is called the -- decorate-sort-undecorate paradigm, or Schwartzian transform. -- -- Elements are arranged from from lowest to highest, keeping duplicates -- in the order they appeared in the input. -- --
--   >>> sortOn fst [(2, "world"), (4, "!"), (1, "Hello")]
--   [(1,"Hello"),(2,"world"),(4,"!")]
--   
sortOn :: Ord b => a -> b -> [a] -> [a] -- | The sortBy function is the non-overloaded version of -- sort. -- --
--   >>> sortBy (\(a,_) (b,_) -> compare a b) [(2, "world"), (4, "!"), (1, "Hello")]
--   [(1,"Hello"),(2,"world"),(4,"!")]
--   
sortBy :: () => a -> a -> Ordering -> [a] -> [a] -- | The sort function implements a stable sorting algorithm. It is -- a special case of sortBy, which allows the programmer to supply -- their own comparison function. -- -- Elements are arranged from from lowest to highest, keeping duplicates -- in the order they appeared in the input. -- --
--   >>> sort [1,6,4,3,2,5]
--   [1,2,3,4,5,6]
--   
sort :: Ord a => [a] -> [a] -- | The permutations function returns the list of all permutations -- of the argument. -- --
--   >>> permutations "abc"
--   ["abc","bac","cba","bca","cab","acb"]
--   
permutations :: () => [a] -> [[a]] -- | The subsequences function returns the list of all subsequences -- of the argument. -- --
--   >>> subsequences "abc"
--   ["","a","b","ab","c","ac","bc","abc"]
--   
subsequences :: () => [a] -> [[a]] -- | The tails function returns all final segments of the argument, -- longest first. For example, -- --
--   >>> tails "abc"
--   ["abc","bc","c",""]
--   
-- -- Note that tails has the following strictness property: -- tails _|_ = _|_ : _|_ tails :: () => [a] -> [[a]] -- | The inits function returns all initial segments of the -- argument, shortest first. For example, -- --
--   >>> inits "abc"
--   ["","a","ab","abc"]
--   
-- -- Note that inits has the following strictness property: -- inits (xs ++ _|_) = inits xs ++ _|_ -- -- In particular, inits _|_ = [] : _|_ inits :: () => [a] -> [[a]] -- | The groupBy function is the non-overloaded version of -- group. groupBy :: () => a -> a -> Bool -> [a] -> [[a]] -- | The group function takes a list and returns a list of lists -- such that the concatenation of the result is equal to the argument. -- Moreover, each sublist in the result contains only equal elements. For -- example, -- --
--   >>> group "Mississippi"
--   ["M","i","ss","i","ss","i","pp","i"]
--   
-- -- It is a special case of groupBy, which allows the programmer to -- supply their own equality test. group :: Eq a => [a] -> [[a]] -- | The deleteFirstsBy function takes a predicate and two lists and -- returns the first list with the first occurrence of each element of -- the second list removed. deleteFirstsBy :: () => a -> a -> Bool -> [a] -> [a] -> [a] -- | The unzip7 function takes a list of seven-tuples and returns -- seven lists, analogous to unzip. unzip7 :: () => [(a, b, c, d, e, f, g)] -> ([a], [b], [c], [d], [e], [f], [g]) -- | The unzip6 function takes a list of six-tuples and returns six -- lists, analogous to unzip. unzip6 :: () => [(a, b, c, d, e, f)] -> ([a], [b], [c], [d], [e], [f]) -- | The unzip5 function takes a list of five-tuples and returns -- five lists, analogous to unzip. unzip5 :: () => [(a, b, c, d, e)] -> ([a], [b], [c], [d], [e]) -- | The unzip4 function takes a list of quadruples and returns four -- lists, analogous to unzip. unzip4 :: () => [(a, b, c, d)] -> ([a], [b], [c], [d]) -- | The zipWith7 function takes a function which combines seven -- elements, as well as seven lists and returns a list of their -- point-wise combination, analogous to zipWith. zipWith7 :: () => a -> b -> c -> d -> e -> f -> g -> h -> [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [h] -- | The zipWith6 function takes a function which combines six -- elements, as well as six lists and returns a list of their point-wise -- combination, analogous to zipWith. zipWith6 :: () => a -> b -> c -> d -> e -> f -> g -> [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -- | The zipWith5 function takes a function which combines five -- elements, as well as five lists and returns a list of their point-wise -- combination, analogous to zipWith. zipWith5 :: () => a -> b -> c -> d -> e -> f -> [a] -> [b] -> [c] -> [d] -> [e] -> [f] -- | The zipWith4 function takes a function which combines four -- elements, as well as four lists and returns a list of their point-wise -- combination, analogous to zipWith. zipWith4 :: () => a -> b -> c -> d -> e -> [a] -> [b] -> [c] -> [d] -> [e] -- | The zip7 function takes seven lists and returns a list of -- seven-tuples, analogous to zip. zip7 :: () => [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [(a, b, c, d, e, f, g)] -- | The zip6 function takes six lists and returns a list of -- six-tuples, analogous to zip. zip6 :: () => [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [(a, b, c, d, e, f)] -- | The zip5 function takes five lists and returns a list of -- five-tuples, analogous to zip. zip5 :: () => [a] -> [b] -> [c] -> [d] -> [e] -> [(a, b, c, d, e)] -- | The zip4 function takes four lists and returns a list of -- quadruples, analogous to zip. zip4 :: () => [a] -> [b] -> [c] -> [d] -> [(a, b, c, d)] -- | The genericReplicate function is an overloaded version of -- replicate, which accepts any Integral value as the -- number of repetitions to make. genericReplicate :: Integral i => i -> a -> [a] -- | The genericIndex function is an overloaded version of -- !!, which accepts any Integral value as the index. genericIndex :: Integral i => [a] -> i -> a -- | The genericSplitAt function is an overloaded version of -- splitAt, which accepts any Integral value as the -- position at which to split. genericSplitAt :: Integral i => i -> [a] -> ([a], [a]) -- | The genericDrop function is an overloaded version of -- drop, which accepts any Integral value as the number of -- elements to drop. genericDrop :: Integral i => i -> [a] -> [a] -- | The genericTake function is an overloaded version of -- take, which accepts any Integral value as the number of -- elements to take. genericTake :: Integral i => i -> [a] -> [a] -- | The genericLength function is an overloaded version of -- length. In particular, instead of returning an Int, it -- returns any type which is an instance of Num. It is, however, -- less efficient than length. genericLength :: Num i => [a] -> i -- | The non-overloaded version of insert. insertBy :: () => a -> a -> Ordering -> a -> [a] -> [a] -- | The insert function takes an element and a list and inserts the -- element into the list at the first position where it is less than or -- equal to the next element. In particular, if the list is sorted before -- the call, the result will also be sorted. It is a special case of -- insertBy, which allows the programmer to supply their own -- comparison function. -- --
--   >>> insert 4 [1,2,3,5,6,7]
--   [1,2,3,4,5,6,7]
--   
insert :: Ord a => a -> [a] -> [a] -- | The partition function takes a predicate a list and returns the -- pair of lists of elements which do and do not satisfy the predicate, -- respectively; i.e., -- --
--   partition p xs == (filter p xs, filter (not . p) xs)
--   
-- --
--   >>> partition (`elem` "aeiou") "Hello World!"
--   ("eoo","Hll Wrld!")
--   
partition :: () => a -> Bool -> [a] -> ([a], [a]) -- | The transpose function transposes the rows and columns of its -- argument. For example, -- --
--   >>> transpose [[1,2,3],[4,5,6]]
--   [[1,4],[2,5],[3,6]]
--   
-- -- If some of the rows are shorter than the following rows, their -- elements are skipped: -- --
--   >>> transpose [[10,11],[20],[],[30,31,32]]
--   [[10,20,30],[11,31],[32]]
--   
transpose :: () => [[a]] -> [[a]] -- | intercalate xs xss is equivalent to (concat -- (intersperse xs xss)). It inserts the list xs in -- between the lists in xss and concatenates the result. -- --
--   >>> intercalate ", " ["Lorem", "ipsum", "dolor"]
--   "Lorem, ipsum, dolor"
--   
intercalate :: () => [a] -> [[a]] -> [a] -- | The intersperse function takes an element and a list and -- `intersperses' that element between the elements of the list. For -- example, -- --
--   >>> intersperse ',' "abcde"
--   "a,b,c,d,e"
--   
intersperse :: () => a -> [a] -> [a] -- | The intersectBy function is the non-overloaded version of -- intersect. intersectBy :: () => a -> a -> Bool -> [a] -> [a] -> [a] -- | The intersect function takes the list intersection of two -- lists. For example, -- --
--   >>> [1,2,3,4] `intersect` [2,4,6,8]
--   [2,4]
--   
-- -- If the first list contains duplicates, so will the result. -- --
--   >>> [1,2,2,3,4] `intersect` [6,4,4,2]
--   [2,2,4]
--   
-- -- It is a special case of intersectBy, which allows the -- programmer to supply their own equality test. If the element is found -- in both the first and the second list, the element from the first list -- will be used. intersect :: Eq a => [a] -> [a] -> [a] -- | The unionBy function is the non-overloaded version of -- union. unionBy :: () => a -> a -> Bool -> [a] -> [a] -> [a] -- | The union function returns the list union of the two lists. For -- example, -- --
--   >>> "dog" `union` "cow"
--   "dogcw"
--   
-- -- Duplicates, and elements of the first list, are removed from the the -- second list, but if the first list contains duplicates, so will the -- result. It is a special case of unionBy, which allows the -- programmer to supply their own equality test. union :: Eq a => [a] -> [a] -> [a] -- | The \\ function is list difference (non-associative). In the -- result of xs \\ ys, the first occurrence of -- each element of ys in turn (if any) has been removed from -- xs. Thus -- --
--   (xs ++ ys) \\ xs == ys.
--   
-- --
--   >>> "Hello World!" \\ "ell W"
--   "Hoorld!"
--   
-- -- It is a special case of deleteFirstsBy, which allows the -- programmer to supply their own equality test. (\\) :: Eq a => [a] -> [a] -> [a] infix 5 \\ -- | The deleteBy function behaves like delete, but takes a -- user-supplied equality predicate. -- --
--   >>> deleteBy (<=) 4 [1..10]
--   [1,2,3,5,6,7,8,9,10]
--   
deleteBy :: () => a -> a -> Bool -> a -> [a] -> [a] -- | delete x removes the first occurrence of x -- from its list argument. For example, -- --
--   >>> delete 'a' "banana"
--   "bnana"
--   
-- -- It is a special case of deleteBy, which allows the programmer -- to supply their own equality test. delete :: Eq a => a -> [a] -> [a] -- | The nubBy function behaves just like nub, except it uses -- a user-supplied equality predicate instead of the overloaded == -- function. -- --
--   >>> nubBy (\x y -> mod x 3 == mod y 3) [1,2,4,5,6]
--   [1,2,6]
--   
nubBy :: () => a -> a -> Bool -> [a] -> [a] -- | O(n^2). The nub function removes duplicate elements from -- a list. In particular, it keeps only the first occurrence of each -- element. (The name nub means `essence'.) It is a special case -- of nubBy, which allows the programmer to supply their own -- equality test. -- --
--   >>> nub [1,2,3,4,3,2,1,2,4,3,5]
--   [1,2,3,4,5]
--   
nub :: Eq a => [a] -> [a] -- | The isInfixOf function takes two lists and returns True -- iff the first list is contained, wholly and intact, anywhere within -- the second. -- --
--   >>> isInfixOf "Haskell" "I really like Haskell."
--   True
--   
-- --
--   >>> isInfixOf "Ial" "I really like Haskell."
--   False
--   
isInfixOf :: Eq a => [a] -> [a] -> Bool -- | The isSuffixOf function takes two lists and returns True -- iff the first list is a suffix of the second. The second list must be -- finite. -- --
--   >>> "ld!" `isSuffixOf` "Hello World!"
--   True
--   
-- --
--   >>> "World" `isSuffixOf` "Hello World!"
--   False
--   
isSuffixOf :: Eq a => [a] -> [a] -> Bool -- | The isPrefixOf function takes two lists and returns True -- iff the first list is a prefix of the second. -- --
--   >>> "Hello" `isPrefixOf` "Hello World!"
--   True
--   
-- --
--   >>> "Hello" `isPrefixOf` "Wello Horld!"
--   False
--   
isPrefixOf :: Eq a => [a] -> [a] -> Bool -- | The findIndices function extends findIndex, by returning -- the indices of all elements satisfying the predicate, in ascending -- order. -- --
--   >>> findIndices (`elem` "aeiou") "Hello World!"
--   [1,4,7]
--   
findIndices :: () => a -> Bool -> [a] -> [Int] -- | The findIndex function takes a predicate and a list and returns -- the index of the first element in the list satisfying the predicate, -- or Nothing if there is no such element. -- --
--   >>> findIndex isSpace "Hello World!"
--   Just 5
--   
findIndex :: () => a -> Bool -> [a] -> Maybe Int -- | The elemIndices function extends elemIndex, by returning -- the indices of all elements equal to the query element, in ascending -- order. -- --
--   >>> elemIndices 'o' "Hello World"
--   [4,7]
--   
elemIndices :: Eq a => a -> [a] -> [Int] -- | The elemIndex function returns the index of the first element -- in the given list which is equal (by ==) to the query element, -- or Nothing if there is no such element. -- --
--   >>> elemIndex 4 [0..]
--   Just 4
--   
elemIndex :: Eq a => a -> [a] -> Maybe Int -- | The stripPrefix function drops the given prefix from a list. It -- returns Nothing if the list did not start with the prefix -- given, or Just the list after the prefix, if it does. -- --
--   >>> stripPrefix "foo" "foobar"
--   Just "bar"
--   
-- --
--   >>> stripPrefix "foo" "foo"
--   Just ""
--   
-- --
--   >>> stripPrefix "foo" "barfoo"
--   Nothing
--   
-- --
--   >>> stripPrefix "foo" "barfoobaz"
--   Nothing
--   
stripPrefix :: Eq a => [a] -> [a] -> Maybe [a] -- | The dropWhileEnd function drops the largest suffix of a list in -- which the given predicate holds for all elements. For example: -- --
--   >>> dropWhileEnd isSpace "foo\n"
--   "foo"
--   
-- --
--   >>> dropWhileEnd isSpace "foo bar"
--   "foo bar"
--   
-- --
--   dropWhileEnd isSpace ("foo\n" ++ undefined) == "foo" ++ undefined
--   
dropWhileEnd :: () => a -> Bool -> [a] -> [a] -- | The unzip3 function takes a list of triples and returns three -- lists, analogous to unzip. unzip3 :: () => [(a, b, c)] -> ([a], [b], [c]) -- | unzip transforms a list of pairs into a list of first -- components and a list of second components. unzip :: () => [(a, b)] -> ([a], [b]) -- | The zipWith3 function takes a function which combines three -- elements, as well as three lists and returns a list of their -- point-wise combination, analogous to zipWith. zipWith3 :: () => a -> b -> c -> d -> [a] -> [b] -> [c] -> [d] -- | zipWith generalises zip by zipping with the function -- given as the first argument, instead of a tupling function. For -- example, zipWith (+) is applied to two lists to -- produce the list of corresponding sums. -- -- zipWith is right-lazy: -- --
--   zipWith f [] _|_ = []
--   
zipWith :: () => a -> b -> c -> [a] -> [b] -> [c] -- | zip3 takes three lists and returns a list of triples, analogous -- to zip. zip3 :: () => [a] -> [b] -> [c] -> [(a, b, c)] -- | List index (subscript) operator, starting from 0. It is an instance of -- the more general genericIndex, which takes an index of any -- integral type. (!!) :: () => [a] -> Int -> a infixl 9 !! -- | lookup key assocs looks up a key in an association -- list. lookup :: Eq a => a -> [(a, b)] -> Maybe b -- | reverse xs returns the elements of xs in -- reverse order. xs must be finite. reverse :: () => [a] -> [a] -- | break, applied to a predicate p and a list -- xs, returns a tuple where first element is longest prefix -- (possibly empty) of xs of elements that do not satisfy -- p and second element is the remainder of the list: -- --
--   break (> 3) [1,2,3,4,1,2,3,4] == ([1,2,3],[4,1,2,3,4])
--   break (< 9) [1,2,3] == ([],[1,2,3])
--   break (> 9) [1,2,3] == ([1,2,3],[])
--   
-- -- break p is equivalent to span (not . -- p). break :: () => a -> Bool -> [a] -> ([a], [a]) -- | span, applied to a predicate p and a list xs, -- returns a tuple where first element is longest prefix (possibly empty) -- of xs of elements that satisfy p and second element -- is the remainder of the list: -- --
--   span (< 3) [1,2,3,4,1,2,3,4] == ([1,2],[3,4,1,2,3,4])
--   span (< 9) [1,2,3] == ([1,2,3],[])
--   span (< 0) [1,2,3] == ([],[1,2,3])
--   
-- -- span p xs is equivalent to (takeWhile p xs, -- dropWhile p xs) span :: () => a -> Bool -> [a] -> ([a], [a]) -- | splitAt n xs returns a tuple where first element is -- xs prefix of length n and second element is the -- remainder of the list: -- --
--   splitAt 6 "Hello World!" == ("Hello ","World!")
--   splitAt 3 [1,2,3,4,5] == ([1,2,3],[4,5])
--   splitAt 1 [1,2,3] == ([1],[2,3])
--   splitAt 3 [1,2,3] == ([1,2,3],[])
--   splitAt 4 [1,2,3] == ([1,2,3],[])
--   splitAt 0 [1,2,3] == ([],[1,2,3])
--   splitAt (-1) [1,2,3] == ([],[1,2,3])
--   
-- -- It is equivalent to (take n xs, drop n xs) when -- n is not _|_ (splitAt _|_ xs = _|_). -- splitAt is an instance of the more general -- genericSplitAt, in which n may be of any integral -- type. splitAt :: () => Int -> [a] -> ([a], [a]) -- | drop n xs returns the suffix of xs after the -- first n elements, or [] if n > length -- xs: -- --
--   drop 6 "Hello World!" == "World!"
--   drop 3 [1,2,3,4,5] == [4,5]
--   drop 3 [1,2] == []
--   drop 3 [] == []
--   drop (-1) [1,2] == [1,2]
--   drop 0 [1,2] == [1,2]
--   
-- -- It is an instance of the more general genericDrop, in which -- n may be of any integral type. drop :: () => Int -> [a] -> [a] -- | take n, applied to a list xs, returns the -- prefix of xs of length n, or xs itself if -- n > length xs: -- --
--   take 5 "Hello World!" == "Hello"
--   take 3 [1,2,3,4,5] == [1,2,3]
--   take 3 [1,2] == [1,2]
--   take 3 [] == []
--   take (-1) [1,2] == []
--   take 0 [1,2] == []
--   
-- -- It is an instance of the more general genericTake, in which -- n may be of any integral type. take :: () => Int -> [a] -> [a] -- | dropWhile p xs returns the suffix remaining after -- takeWhile p xs: -- --
--   dropWhile (< 3) [1,2,3,4,5,1,2,3] == [3,4,5,1,2,3]
--   dropWhile (< 9) [1,2,3] == []
--   dropWhile (< 0) [1,2,3] == [1,2,3]
--   
dropWhile :: () => a -> Bool -> [a] -> [a] -- | takeWhile, applied to a predicate p and a list -- xs, returns the longest prefix (possibly empty) of -- xs of elements that satisfy p: -- --
--   takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]
--   takeWhile (< 9) [1,2,3] == [1,2,3]
--   takeWhile (< 0) [1,2,3] == []
--   
takeWhile :: () => a -> Bool -> [a] -> [a] -- | cycle ties a finite list into a circular one, or equivalently, -- the infinite repetition of the original list. It is the identity on -- infinite lists. cycle :: () => [a] -> [a] -- | replicate n x is a list of length n with -- x the value of every element. It is an instance of the more -- general genericReplicate, in which n may be of any -- integral type. replicate :: () => Int -> a -> [a] -- | repeat x is an infinite list, with x the -- value of every element. repeat :: () => a -> [a] -- | 'iterate\'' is the strict version of iterate. -- -- It ensures that the result of each application of force to weak head -- normal form before proceeding. iterate' :: () => a -> a -> a -> [a] -- | iterate f x returns an infinite list of repeated -- applications of f to x: -- --
--   iterate f x == [x, f x, f (f x), ...]
--   
-- -- Note that iterate is lazy, potentially leading to thunk -- build-up if the consumer doesn't force each iterate. See 'iterate\'' -- for a strict variant of this function. iterate :: () => a -> a -> a -> [a] -- | scanr1 is a variant of scanr that has no starting value -- argument. scanr1 :: () => a -> a -> a -> [a] -> [a] -- | scanr is the right-to-left dual of scanl. Note that -- --
--   head (scanr f z xs) == foldr f z xs.
--   
scanr :: () => a -> b -> b -> b -> [a] -> [b] -- | A strictly accumulating version of scanl scanl' :: () => b -> a -> b -> b -> [a] -> [b] -- | scanl1 is a variant of scanl that has no starting value -- argument: -- --
--   scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
--   
scanl1 :: () => a -> a -> a -> [a] -> [a] -- | scanl is similar to foldl, but returns a list of -- successive reduced values from the left: -- --
--   scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
--   
-- -- Note that -- --
--   last (scanl f z xs) == foldl f z xs.
--   
scanl :: () => b -> a -> b -> b -> [a] -> [b] -- | A strict version of foldl1 foldl1' :: () => a -> a -> a -> [a] -> a -- | Return all the elements of a list except the last one. The list must -- be non-empty. init :: () => [a] -> [a] -- | Extract the last element of a list, which must be finite and -- non-empty. last :: () => [a] -> a -- | Extract the elements after the head of a list, which must be -- non-empty. tail :: () => [a] -> [a] -- | Decompose a list into its head and tail. If the list is empty, returns -- Nothing. If the list is non-empty, returns Just (x, -- xs), where x is the head of the list and xs its -- tail. uncons :: () => [a] -> Maybe (a, [a]) -- | Extract the first element of a list, which must be non-empty. head :: () => [a] -> a -- | 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 -- | 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 (<= height) [yf, y1, y2])
--   
allB :: Show a => a -> Bool -> [a] -> Bool -- | Syntactic sugar for the pair operation, to be used for blame as -- in -- --
--   assert (age < 120 `blame` "age too high" `swith` age) $ savings / (120 - age)
--   
-- -- Fixing the first component of the pair to String prevents -- warnings about defaulting, even when OverloadedStrings -- extension is enabled. swith :: () => String -> v -> (String, v) infix 2 `swith` -- | A helper function for error. To be used as in -- --
--   case xs of
--     0 : _ -> error $ "insignificant zero" `showFailure` xs
--   
-- -- Fixing the first argument to String instead of anything -- Showable prevents warnings about defaulting, even when -- OverloadedStrings extension is enabled. showFailure :: Show v => String -> v -> String infix 2 `showFailure` -- | If the condition fails, display the value blamed for the failure. Used -- as in -- --
--   assert (age < 120 `blame` age) $ savings / (120 - age)
--   
blame :: Show a => Bool -> a -> Bool infix 1 `blame` -- | A space efficient, packed, unboxed Unicode text type. data Text -- | Separated by space unless one of them is empty (in which case just the -- non-empty one). (<+>) :: Text -> Text -> Text infixr 6 <+> -- | Show and pack the result. tshow :: Show a => a -> Text -- | Integer division, rounding up. divUp :: Integral a => a -> a -> a infixl 7 `divUp` (<$$>) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b) infixl 4 <$$> partitionM :: Applicative m => (a -> m Bool) -> [a] -> m ([a], [a]) -- | A version specialized to lists to avoid errors such as taking length -- of Maybe [a] instead of [a]. Such errors are hard to -- detect, because the type of elements of the list is not constrained. length :: [a] -> Int -- | A version specialized to lists to avoid errors such as taking null of -- Maybe [a] instead of [a]. Such errors are hard to -- detect, because the type of elements of the list is not constrained. null :: [a] -> Bool -- | Split the input between the two argument arrows and combine their -- output. Note that this is in general not a functor. -- -- The default definition may be overridden with a more efficient version -- if desired. (***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c') infixr 3 *** -- | Fanout: send the input to both argument arrows and combine their -- output. -- -- The default definition may be overridden with a more efficient version -- if desired. (&&&) :: Arrow a => a b c -> a b c' -> a b (c, c') infixr 3 &&& -- | Send the first component of the input through the argument arrow, and -- copy the rest unchanged to the output. first :: Arrow a => a b c -> a (b, d) (c, d) -- | A mirror image of first. -- -- The default definition may be overridden with a more efficient version -- if desired. second :: Arrow a => a b c -> a (d, b) (d, c) -- | Basic operations on 2D points represented as linear offsets. module Game.LambdaHack.Common.Point -- | Spacial dimension for points and vectors. type X = Int -- | Spacial dimension for points and vectors. type Y = Int -- | 2D points in cartesian representation. Coordinates grow to the right -- and down, so that the (0, 0) point is in the top-left corner of the -- screen. Coordinates are never negative. data Point Point :: X -> Y -> Point [px] :: Point -> X [py] :: Point -> Y -- | The maximum number of bits for level X and Y dimension (16). The value -- is chosen to support architectures with 32-bit Ints. maxLevelDimExponent :: Int -- | The distance between two points in the chessboard metric. chessDist :: Point -> Point -> Int -- | Squared euclidean distance between two points. euclidDistSq :: Point -> Point -> Int -- | Checks whether two points are adjacent on the map (horizontally, -- vertically or diagonally). adjacent :: Point -> Point -> Bool -- | Checks that a point belongs to an area. inside :: Point -> (X, Y, X, Y) -> Bool -- | 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. The target is -- given as Point to permit aiming out of the level, e.g., to -- get uniform distributions of directions for explosions close to the -- edge of the level. bla :: X -> Y -> Int -> Point -> Point -> Maybe [Point] -- | A list of all points on a straight vertical or straight horizontal -- line between two points. Fails if no such line exists. fromTo :: Point -> Point -> [Point] originPoint :: Point -- | Maximal supported level X and Y dimension. Not checked anywhere. The -- value is chosen to support architectures with 32-bit Ints. maxLevelDim :: Int -- | 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 -> Point -> Point -> [Point] -- | See -- http://roguebasin.roguelikedevelopment.org/index.php/Digital_lines. balancedWord :: Int -> Int -> Int -> [Int] instance GHC.Generics.Generic Game.LambdaHack.Common.Point.Point instance GHC.Classes.Ord Game.LambdaHack.Common.Point.Point instance GHC.Classes.Eq Game.LambdaHack.Common.Point.Point instance GHC.Show.Show Game.LambdaHack.Common.Point.Point instance Data.Binary.Class.Binary Game.LambdaHack.Common.Point.Point instance GHC.Enum.Enum Game.LambdaHack.Common.Point.Point -- | Arrays, based on Data.Vector.Unboxed, indexed by Point. module Game.LambdaHack.Common.PointArray class (Ord c, Eq (UnboxRep c), Ord (UnboxRep c), Bounded (UnboxRep c), Binary (UnboxRep c), Unbox (UnboxRep c)) => UnboxRepClass c where { type family UnboxRep c; type UnboxRep c = c; } toUnboxRepUnsafe :: UnboxRepClass c => c -> UnboxRep c fromUnboxRep :: UnboxRepClass c => UnboxRep c -> c -- | Arrays indexed by Point. data Array c Array :: X -> Y -> Vector (UnboxRep c) -> Array c [axsize] :: Array c -> X [aysize] :: Array c -> Y [avector] :: Array c -> Vector (UnboxRep c) pindex :: X -> Point -> Int punindex :: X -> Int -> Point -- | Array lookup. (!) :: UnboxRepClass c => Array c -> Point -> c accessI :: UnboxRepClass c => Array c -> Int -> UnboxRep c -- | Construct an array updated with the association list. (//) :: UnboxRepClass c => Array c -> [(Point, c)] -> Array c unsafeUpdateA :: UnboxRepClass c => Array c -> [(Point, c)] -> () unsafeWriteA :: UnboxRepClass c => Array c -> Point -> c -> () unsafeWriteManyA :: UnboxRepClass c => Array c -> [Point] -> c -> () -- | Create an array from a replicated element. replicateA :: UnboxRepClass c => X -> Y -> c -> Array c -- | Create an array from a replicated monadic action. replicateMA :: (Monad m, UnboxRepClass c) => X -> Y -> m c -> m (Array c) -- | Create an array from a function. generateA :: UnboxRepClass c => X -> Y -> (Point -> c) -> Array c -- | Create an array from a monadic function. generateMA :: (Monad m, UnboxRepClass c) => X -> Y -> (Point -> m c) -> m (Array c) unfoldrNA :: UnboxRepClass c => X -> Y -> (b -> (c, b)) -> b -> Array c -- | Content identifiers array size. sizeA :: Array c -> (X, Y) -- | Fold right over an array. foldrA :: UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a -- | Fold right strictly over an array. foldrA' :: UnboxRepClass c => (c -> a -> a) -> a -> Array c -> a -- | Fold left strictly over an array. foldlA' :: UnboxRepClass c => (a -> c -> a) -> a -> Array c -> a -- | Fold right over an array (function applied to each element and its -- index). ifoldrA :: UnboxRepClass c => (Point -> c -> a -> a) -> a -> Array c -> a -- | Fold right strictly over an array (function applied to each element -- and its index). ifoldrA' :: UnboxRepClass c => (Point -> c -> a -> a) -> a -> Array c -> a -- | Fold left strictly over an array (function applied to each element and -- its index). ifoldlA' :: UnboxRepClass c => (a -> Point -> c -> a) -> a -> Array c -> a -- | Fold monadically strictly over an array. foldMA' :: (Monad m, UnboxRepClass c) => (a -> c -> m a) -> a -> Array c -> m a -- | Fold monadically strictly over an array (function applied to each -- element and its index). ifoldMA' :: (Monad m, UnboxRepClass c) => (a -> Point -> c -> m a) -> a -> Array c -> m a -- | Map over an array. mapA :: (UnboxRepClass c, UnboxRepClass d) => (c -> d) -> Array c -> Array d -- | Map over an array (function applied to each element and its index). imapA :: (UnboxRepClass c, UnboxRepClass d) => (Point -> c -> d) -> Array c -> Array d -- | Map monadically over an array (function applied to each element and -- its index) and ignore the results. imapMA_ :: (Monad m, UnboxRepClass c) => (Point -> c -> m ()) -> Array c -> m () -- | Set all elements to the given value, in place, if possible. safeSetA :: UnboxRepClass c => c -> Array c -> Array c -- | Set all elements to the given value, in place. unsafeSetA :: UnboxRepClass c => c -> Array c -> Array c -- | Yield the point coordinates of a minimum element of the array. The -- array may not be empty. minIndexA :: UnboxRepClass c => Array c -> Point -- | Yield the point coordinates of the last minimum element of the array. -- The array may not be empty. minLastIndexA :: UnboxRepClass c => Array c -> Point -- | Yield the point coordinates of all the minimum elements of the array. -- The array may not be empty. minIndexesA :: UnboxRepClass c => Array c -> [Point] -- | Yield the point coordinates of the first maximum element of the array. -- The array may not be empty. maxIndexA :: UnboxRepClass c => Array c -> Point -- | Yield the point coordinates of the last maximum element of the array. -- The array may not be empty. maxLastIndexA :: UnboxRepClass c => Array c -> Point -- | Force the array not to retain any extra memory. forceA :: UnboxRepClass c => Array c -> Array c fromListA :: UnboxRepClass c => X -> Y -> [c] -> Array c toListA :: UnboxRepClass c => Array c -> [c] toUnboxRep :: UnboxRepClass c => c -> UnboxRep c instance Game.LambdaHack.Common.PointArray.UnboxRepClass c => GHC.Classes.Eq (Game.LambdaHack.Common.PointArray.Array c) instance GHC.Show.Show (Game.LambdaHack.Common.PointArray.Array c) instance Game.LambdaHack.Common.PointArray.UnboxRepClass c => Data.Binary.Class.Binary (Game.LambdaHack.Common.PointArray.Array c) instance Game.LambdaHack.Common.PointArray.UnboxRepClass GHC.Types.Bool instance Game.LambdaHack.Common.PointArray.UnboxRepClass GHC.Word.Word8 -- | Hacks that haven't found their home yet. module Game.LambdaHack.Common.Misc -- | A unique identifier of a faction in a game. data FactionId -- | Abstract level identifiers. data LevelId -- | A unique identifier of an actor in the dungeon. data ActorId -- | Item container type. data Container CFloor :: LevelId -> Point -> Container CEmbed :: LevelId -> Point -> Container CActor :: ActorId -> CStore -> Container -- | for bootstrapping actor bodies CTrunk :: FactionId -> LevelId -> Point -> Container -- | Actor's item stores. data CStore CGround :: CStore COrgan :: CStore CEqp :: CStore CInv :: CStore CSha :: CStore -- | Item slot and lore categories. data SLore SItem :: SLore SOrgan :: SLore STrunk :: SLore STmp :: SLore SBlast :: SLore SEmbed :: SLore data ItemDialogMode MStore :: CStore -> ItemDialogMode MOrgans :: ItemDialogMode MOwned :: ItemDialogMode MStats :: ItemDialogMode MLore :: SLore -> ItemDialogMode data GroupName a -- | Tactic of non-leader actors. Apart of determining AI operation, each -- tactic implies a skill modifier, that is added to the non-leader -- skills defined in fskillsOther field of Player. data Tactic -- | if enemy nearby, attack, if no items, etc., explore unknown TExplore :: Tactic -- | always follow leader's target or his position if no target TFollow :: Tactic -- | follow but don't do any item management nor use TFollowNoItems :: Tactic -- | only melee and do ranged combat TMeleeAndRanged :: Tactic -- | only melee (or wait) TMeleeAdjacent :: Tactic -- | always only wait, even if enemy in melee range TBlock :: Tactic -- | if enemy nearby, attack, if no items, etc., roam randomly TRoam :: Tactic -- | find an open and uncrowded area, patrol it according to sight radius -- and fallback temporarily to TRoam when enemy is seen by the -- faction and is within the actor's sight radius TPatrol :: Tactic toGroupName :: Text -> GroupName a describeTactic :: Tactic -> Text -- | 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 -- | Apply the WWandW constructor, first representing repetitions -- as CardinalWs. The parts are not sorted, only grouped, to -- keep the order. The internal structure of speech parts is compared, -- not their string rendering, so some coincidental clashes are avoided -- (and code is simpler). squashedWWandW :: [Part] -> (Part, Person) -- | Level bounds. normalLevelBound :: (Int, Int) -- | Personal data directory for the game. Depends on the OS and the game, -- e.g., for LambdaHack under Linux it's ~/.LambdaHack/. appDataDir :: IO FilePath xM :: Int -> Int64 xD :: Double -> Double minusM :: Int64 minusM1 :: Int64 oneM :: Int64 tenthM :: Int64 instance GHC.Generics.Generic Game.LambdaHack.Common.Misc.Tactic instance GHC.Enum.Bounded Game.LambdaHack.Common.Misc.Tactic instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.Tactic instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.Tactic instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.Tactic instance GHC.Generics.Generic (Game.LambdaHack.Common.Misc.GroupName a) instance Data.Binary.Class.Binary (Game.LambdaHack.Common.Misc.GroupName a) instance Data.Hashable.Class.Hashable (Game.LambdaHack.Common.Misc.GroupName a) instance GHC.Classes.Ord (Game.LambdaHack.Common.Misc.GroupName a) instance GHC.Classes.Eq (Game.LambdaHack.Common.Misc.GroupName a) instance GHC.Read.Read (Game.LambdaHack.Common.Misc.GroupName a) instance GHC.Generics.Generic Game.LambdaHack.Common.Misc.ItemDialogMode instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.ItemDialogMode instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.ItemDialogMode instance GHC.Read.Read Game.LambdaHack.Common.Misc.ItemDialogMode instance GHC.Show.Show Game.LambdaHack.Common.Misc.ItemDialogMode instance GHC.Generics.Generic Game.LambdaHack.Common.Misc.SLore instance GHC.Enum.Bounded Game.LambdaHack.Common.Misc.SLore instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.SLore instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.SLore instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.SLore instance GHC.Read.Read Game.LambdaHack.Common.Misc.SLore instance GHC.Show.Show Game.LambdaHack.Common.Misc.SLore instance GHC.Generics.Generic Game.LambdaHack.Common.Misc.Container instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.Container instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.Container instance GHC.Show.Show Game.LambdaHack.Common.Misc.Container instance GHC.Generics.Generic Game.LambdaHack.Common.Misc.CStore instance GHC.Enum.Bounded Game.LambdaHack.Common.Misc.CStore instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.CStore instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.CStore instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.CStore instance GHC.Read.Read Game.LambdaHack.Common.Misc.CStore instance GHC.Show.Show Game.LambdaHack.Common.Misc.CStore instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.ActorId instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.ActorId instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.ActorId instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.ActorId instance GHC.Show.Show Game.LambdaHack.Common.Misc.ActorId instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.LevelId instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Misc.LevelId instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.LevelId instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.LevelId instance GHC.Show.Show Game.LambdaHack.Common.Misc.LevelId instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.FactionId instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Misc.FactionId instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.FactionId instance GHC.Classes.Ord Game.LambdaHack.Common.Misc.FactionId instance GHC.Classes.Eq Game.LambdaHack.Common.Misc.FactionId instance GHC.Show.Show Game.LambdaHack.Common.Misc.FactionId instance GHC.Show.Show Game.LambdaHack.Common.Misc.Tactic instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.Tactic instance Control.DeepSeq.NFData Game.LambdaHack.Common.Misc.Tactic instance Data.String.IsString (Game.LambdaHack.Common.Misc.GroupName a) instance GHC.Show.Show (Game.LambdaHack.Common.Misc.GroupName a) instance Control.DeepSeq.NFData (Game.LambdaHack.Common.Misc.GroupName a) instance Control.DeepSeq.NFData Game.LambdaHack.Common.Misc.ItemDialogMode instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.ItemDialogMode instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.SLore instance Control.DeepSeq.NFData Game.LambdaHack.Common.Misc.SLore instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.Container instance Data.Binary.Class.Binary Game.LambdaHack.Common.Misc.CStore instance Control.DeepSeq.NFData Game.LambdaHack.Common.Misc.CStore instance GHC.Enum.Enum Game.LambdaHack.Common.Misc.LevelId instance (GHC.Enum.Enum k, Data.Binary.Class.Binary k, Data.Binary.Class.Binary e) => Data.Binary.Class.Binary (Data.EnumMap.Base.EnumMap k e) instance (GHC.Enum.Enum k, Data.Binary.Class.Binary k) => Data.Binary.Class.Binary (Data.EnumSet.EnumSet k) instance Data.Binary.Class.Binary Data.Time.Clock.Internal.NominalDiffTime.NominalDiffTime instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k, Data.Binary.Class.Binary k, Data.Binary.Class.Binary v) => Data.Binary.Class.Binary (Data.HashMap.Base.HashMap k v) instance Data.Key.Zip (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.ZipWithKey (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.Keyed (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.FoldableWithKey (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.TraversableWithKey (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.Indexable (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.Lookup (Data.EnumMap.Base.EnumMap k) instance GHC.Enum.Enum k => Data.Key.Adjustable (Data.EnumMap.Base.EnumMap k) instance (GHC.Enum.Enum k, Data.Hashable.Class.Hashable k, Data.Hashable.Class.Hashable e) => Data.Hashable.Class.Hashable (Data.EnumMap.Base.EnumMap k e) instance Control.DeepSeq.NFData NLP.Miniutter.English.Part instance Control.DeepSeq.NFData NLP.Miniutter.English.Person instance Control.DeepSeq.NFData NLP.Miniutter.English.Polarity -- | Saving/loading to files, with serialization and compression. module Game.LambdaHack.Common.HSFile -- | 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. We catch exceptions in -- case many clients try to do the same thing at the same time. tryCreateDir :: FilePath -> IO () -- | The operation doesFileExist returns True if the argument -- file exists and is not a directory, and False otherwise. doesFileExist :: FilePath -> IO Bool -- | Try to write a file, given content, if the file not already there. We -- catch exceptions in case many clients try to do the same thing at the -- same time. tryWriteFile :: FilePath -> String -> IO () -- | The readFile function reads a file and returns the contents of -- the file as a string. The file is read lazily, on demand, as with -- getContents. readFile :: FilePath -> IO String -- | renameFile old new changes the name of an existing -- file system object from old to new. If the new -- object already exists, it is atomically replaced by the old -- object. Neither path may refer to an existing directory. A conformant -- implementation need not support renaming files in all situations (e.g. -- renaming across different physical devices), but the constraints must -- be documented. -- -- The operation may fail with: -- -- renameFile :: FilePath -> FilePath -> IO () -- | Serialize, compress and save data. Note that LBS.writeFile opens the -- file in binary mode. encodeData :: Binary a => FilePath -> a -> IO () -- | Saving/loading to files, with serialization and compression. module Game.LambdaHack.Common.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. We catch exceptions in -- case many clients try to do the same thing at the same time. tryCreateDir :: FilePath -> IO () -- | The operation doesFileExist returns True if the argument -- file exists and is not a directory, and False otherwise. doesFileExist :: FilePath -> IO Bool -- | Try to write a file, given content, if the file not already there. We -- catch exceptions in case many clients try to do the same thing at the -- same time. tryWriteFile :: FilePath -> String -> IO () -- | The readFile function reads a file and returns the contents of -- the file as a string. The file is read lazily, on demand, as with -- getContents. readFile :: FilePath -> IO String -- | renameFile old new changes the name of an existing -- file system object from old to new. If the new -- object already exists, it is atomically replaced by the old -- object. Neither path may refer to an existing directory. A conformant -- implementation need not support renaming files in all situations (e.g. -- renaming across different physical devices), but the constraints must -- be documented. -- -- The operation may fail with: -- -- renameFile :: FilePath -> FilePath -> IO () -- | A list of entities with relative frequencies of appearance. module Game.LambdaHack.Common.Frequency -- | The frequency distribution type. Not normalized (operations may or may -- not group the same elements and sum their frequencies). However, -- elements with zero frequency are removed upon construction. -- -- The Eq instance compares raw representations, not relative, -- normalized frequencies, so operations don't need to preserve the -- expected equalities. 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 frequency 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 -- | Set frequency of an element. setFreq :: Eq a => Frequency a -> a -> Int -> Frequency a -- | 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 minFreq :: Ord a => Frequency a -> Maybe a maxFreq :: Ord a => Frequency a -> Maybe a mostFreq :: Frequency a -> Maybe a instance GHC.Generics.Generic (Game.LambdaHack.Common.Frequency.Frequency a) instance Data.Traversable.Traversable Game.LambdaHack.Common.Frequency.Frequency instance Data.Foldable.Foldable Game.LambdaHack.Common.Frequency.Frequency instance GHC.Classes.Ord a => GHC.Classes.Ord (Game.LambdaHack.Common.Frequency.Frequency a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Game.LambdaHack.Common.Frequency.Frequency a) instance GHC.Show.Show a => GHC.Show.Show (Game.LambdaHack.Common.Frequency.Frequency a) instance GHC.Base.Monad Game.LambdaHack.Common.Frequency.Frequency instance GHC.Base.Functor Game.LambdaHack.Common.Frequency.Frequency instance GHC.Base.Applicative Game.LambdaHack.Common.Frequency.Frequency instance GHC.Base.MonadPlus Game.LambdaHack.Common.Frequency.Frequency instance GHC.Base.Alternative Game.LambdaHack.Common.Frequency.Frequency -- | Representation of dice scaled with current level depth. module Game.LambdaHack.Common.Dice -- | Multiple dice rolls, some scaled with current level depth, in which -- case the sum of all rolls is scaled in proportion to current depth -- divided by maximal dungeon depth. -- -- The simple dice should have positive number of rolls and number of -- sides. -- -- The Num instance doesn't have abs nor -- signum defined, because the functions for computing minimum, -- maximum and mean dice results would be too costly. data Dice -- | Absolute depth in the dungeon. When used for the maximum depth of the -- whole dungeon, this can be different than dungeon size, e.g., when the -- dungeon is branched, and it can even be different than the length of -- the longest branch, if levels at some depths are missing. newtype AbsDepth AbsDepth :: Int -> AbsDepth -- | Cast dice scaled with current level depth. When scaling, we round up, -- so that the value of 1 dL 1 is 1 even at the lowest -- level. -- -- The implementation calls RNG as many times as there are dice rolls, -- which is costly, so content should prefer to case fewer dice and then -- multiply them by a constant. If rounded results are not desired (often -- they are, to limit the number of distinct item varieties in -- inventory), another dice may be added to the result. -- -- A different possible implementation, with dice represented as -- Frequency, makes only one RNG call per dice, but due to lists -- lengths proportional to the maximal value of the dice, it's is -- intractable for 1000d1000 and problematic already for 100d100. castDice :: forall m. Monad m => ((Int, Int) -> m Int) -> AbsDepth -> AbsDepth -> Dice -> m Int -- | A die, rolled the given number of times. E.g., 1 d 2 -- rolls 2-sided die one time. d :: Int -> Int -> Dice -- | A die rolled the given number of times, with the result scaled with -- dungeon level depth. dL :: Int -> Int -> Dice -- | A die, starting from zero, ending at one less than the bound, rolled -- the given number of times. E.g., 1 z 1 always rolls -- zero. z :: Int -> Int -> Dice -- | A die, starting from zero, ending at one less than the bound, rolled -- the given number of times, with the result scaled with dungeon level -- depth. zL :: Int -> Int -> Dice intToDice :: Int -> Dice -- | Minimal and maximal possible value of the dice. -- -- divUp in the implementation corresponds to ceiling, -- applied to results of meanDice elsewhere in the code, and -- prevents treating 1d1-power effects (on shallow levels) as null -- effects. minmaxDice :: Dice -> (Int, Int) -- | Maximal value of dice. The scaled part taken assuming median level. maxDice :: Dice -> Int -- | Minimal value of dice. The scaled part taken assuming median level. minDice :: Dice -> Int -- | Mean value of dice. The scaled part taken assuming median level. meanDice :: Dice -> Double reduceDice :: Dice -> Maybe Int -- | Dice for rolling a pair of integer parameters pertaining to, -- respectively, the X and Y cartesian 2D coordinates. data DiceXY DiceXY :: Dice -> Dice -> DiceXY -- | Maximal value of DiceXY. maxDiceXY :: DiceXY -> (Int, Int) -- | Minimal value of DiceXY. minDiceXY :: DiceXY -> (Int, Int) -- | Mean value of DiceXY. meanDiceXY :: DiceXY -> (Double, Double) instance GHC.Generics.Generic Game.LambdaHack.Common.Dice.DiceXY instance GHC.Show.Show Game.LambdaHack.Common.Dice.DiceXY instance Data.Binary.Class.Binary Game.LambdaHack.Common.Dice.AbsDepth instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Dice.AbsDepth instance GHC.Classes.Ord Game.LambdaHack.Common.Dice.AbsDepth instance GHC.Classes.Eq Game.LambdaHack.Common.Dice.AbsDepth instance GHC.Show.Show Game.LambdaHack.Common.Dice.AbsDepth instance GHC.Generics.Generic Game.LambdaHack.Common.Dice.Dice instance GHC.Classes.Ord Game.LambdaHack.Common.Dice.Dice instance GHC.Classes.Eq Game.LambdaHack.Common.Dice.Dice instance Data.Binary.Class.Binary Game.LambdaHack.Common.Dice.DiceXY instance Control.DeepSeq.NFData Game.LambdaHack.Common.Dice.DiceXY instance GHC.Show.Show Game.LambdaHack.Common.Dice.Dice instance Data.Binary.Class.Binary Game.LambdaHack.Common.Dice.Dice instance Control.DeepSeq.NFData Game.LambdaHack.Common.Dice.Dice instance GHC.Num.Num Game.LambdaHack.Common.Dice.Dice -- | 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. defFG :: Color -- | A helper for the terminal frontends that display bright via bold. isBright :: Color -> Bool -- | Colour sets. darkCol :: [Color] -- | Colour sets. brightCol :: [Color] -- | Colour sets. stdCol :: [Color] -- | Translationg to heavily modified Linux console color RGB values. -- -- Warning: SDL frontend sadly duplicates this code. colorToRGB :: Color -> Text -- | Additional map cell highlight, e.g., a colorful square around the cell -- or a colorful background. data Highlight HighlightNone :: Highlight HighlightRed :: Highlight HighlightBlue :: Highlight HighlightYellow :: Highlight HighlightGrey :: Highlight HighlightWhite :: Highlight HighlightMagenta :: Highlight -- | Text attributes: foreground color and highlight. data Attr Attr :: Color -> Highlight -> Attr -- | foreground colour [fg] :: Attr -> Color -- | highlight [bg] :: Attr -> Highlight -- | The default attribute, to optimize attribute setting. defAttr :: Attr -- | Character to display, with its attribute. data AttrChar AttrChar :: Attr -> Char -> AttrChar [acAttr] :: AttrChar -> Attr [acChar] :: AttrChar -> Char -- | Optimized representation of AttrChar. newtype AttrCharW32 AttrCharW32 :: Word32 -> AttrCharW32 [attrCharW32] :: AttrCharW32 -> Word32 attrCharToW32 :: AttrChar -> AttrCharW32 attrCharFromW32 :: AttrCharW32 -> AttrChar fgFromW32 :: AttrCharW32 -> Color bgFromW32 :: AttrCharW32 -> Highlight charFromW32 :: AttrCharW32 -> Char attrFromW32 :: AttrCharW32 -> Attr attrEnumFromW32 :: AttrCharW32 -> Int spaceAttrW32 :: AttrCharW32 retAttrW32 :: AttrCharW32 attrChar2ToW32 :: Color -> Char -> AttrCharW32 attrChar1ToW32 :: Char -> AttrCharW32 instance Data.Binary.Class.Binary Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Enum.Enum Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Classes.Ord Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Classes.Eq Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Show.Show Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Classes.Ord Game.LambdaHack.Common.Color.AttrChar instance GHC.Classes.Eq Game.LambdaHack.Common.Color.AttrChar instance GHC.Show.Show Game.LambdaHack.Common.Color.AttrChar instance GHC.Classes.Ord Game.LambdaHack.Common.Color.Attr instance GHC.Classes.Eq Game.LambdaHack.Common.Color.Attr instance GHC.Show.Show Game.LambdaHack.Common.Color.Attr instance GHC.Generics.Generic Game.LambdaHack.Common.Color.Highlight instance GHC.Enum.Bounded Game.LambdaHack.Common.Color.Highlight instance GHC.Enum.Enum Game.LambdaHack.Common.Color.Highlight instance GHC.Classes.Ord Game.LambdaHack.Common.Color.Highlight instance GHC.Classes.Eq Game.LambdaHack.Common.Color.Highlight instance GHC.Show.Show Game.LambdaHack.Common.Color.Highlight instance GHC.Generics.Generic Game.LambdaHack.Common.Color.Color instance GHC.Enum.Bounded Game.LambdaHack.Common.Color.Color instance GHC.Enum.Enum Game.LambdaHack.Common.Color.Color instance GHC.Classes.Ord Game.LambdaHack.Common.Color.Color instance GHC.Classes.Eq Game.LambdaHack.Common.Color.Color instance GHC.Show.Show Game.LambdaHack.Common.Color.Color instance Game.LambdaHack.Common.PointArray.UnboxRepClass Game.LambdaHack.Common.Color.AttrCharW32 instance GHC.Enum.Enum Game.LambdaHack.Common.Color.Attr instance Data.Binary.Class.Binary Game.LambdaHack.Common.Color.Color instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Color.Color instance Control.DeepSeq.NFData Game.LambdaHack.Common.Color.Color -- | The appearance of in-game items, as communicated to the player. module Game.LambdaHack.Common.Flavour -- | The type of item flavours. data Flavour Flavour :: FancyName -> Color -> Flavour -- | Turn a colour set into a flavour set. zipPlain :: [Color] -> [Flavour] -- | Turn a colour set into a flavour set. zipFancy :: [Color] -> [Flavour] -- | Turn a colour set into a flavour set. zipLiquid :: [Color] -> [Flavour] -- | Get the underlying base colour of a flavour. flavourToColor :: Flavour -> Color -- | Construct the full name of a flavour. flavourToName :: Flavour -> Text -- | Human-readable names for item colors. The plain set. colorToPlainName :: Color -> Text -- | Human-readable names for item colors. The fancy set. colorToFancyName :: Color -> Text -- | Simple names for team colors (bright colours preferred). colorToTeamName :: Color -> Text data FancyName -- | Human-readable names for item colors. The liquid set. colorToLiquidName :: Color -> Text instance GHC.Generics.Generic Game.LambdaHack.Common.Flavour.Flavour instance GHC.Classes.Ord Game.LambdaHack.Common.Flavour.Flavour instance GHC.Classes.Eq Game.LambdaHack.Common.Flavour.Flavour instance GHC.Show.Show Game.LambdaHack.Common.Flavour.Flavour instance GHC.Generics.Generic Game.LambdaHack.Common.Flavour.FancyName instance GHC.Enum.Bounded Game.LambdaHack.Common.Flavour.FancyName instance GHC.Enum.Enum Game.LambdaHack.Common.Flavour.FancyName instance GHC.Classes.Ord Game.LambdaHack.Common.Flavour.FancyName instance GHC.Classes.Eq Game.LambdaHack.Common.Flavour.FancyName instance GHC.Show.Show Game.LambdaHack.Common.Flavour.FancyName instance GHC.Enum.Enum Game.LambdaHack.Common.Flavour.Flavour instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Flavour.Flavour instance Data.Binary.Class.Binary Game.LambdaHack.Common.Flavour.Flavour instance Control.DeepSeq.NFData Game.LambdaHack.Common.Flavour.Flavour instance Control.DeepSeq.NFData Game.LambdaHack.Common.Flavour.FancyName -- | AI strategy abilities. module Game.LambdaHack.Common.Ability -- | Actor and faction abilities corresponding to client-server requests. data Ability AbMove :: Ability AbMelee :: Ability AbDisplace :: Ability AbAlter :: Ability AbWait :: Ability AbMoveItem :: Ability AbProject :: Ability AbApply :: Ability -- | Skill level in particular abilities. -- -- This representation is sparse, so better than a record when there are -- more item kinds (with few abilities) than actors (with many -- abilities), especially if the number of abilities grows as the engine -- is developed. It's also easier to code and maintain. type Skills = EnumMap Ability Int zeroSkills :: Skills unitSkills :: Skills addSkills :: Skills -> Skills -> Skills scaleSkills :: Int -> Skills -> Skills tacticSkills :: Tactic -> Skills blockOnly :: Skills meleeAdjacent :: Skills meleeAndRanged :: Skills ignoreItems :: Skills instance GHC.Enum.Bounded Game.LambdaHack.Common.Ability.Ability instance GHC.Enum.Enum Game.LambdaHack.Common.Ability.Ability instance GHC.Generics.Generic Game.LambdaHack.Common.Ability.Ability instance GHC.Classes.Ord Game.LambdaHack.Common.Ability.Ability instance GHC.Classes.Eq Game.LambdaHack.Common.Ability.Ability instance GHC.Show.Show Game.LambdaHack.Common.Ability.Ability instance Control.DeepSeq.NFData Game.LambdaHack.Common.Ability.Ability instance Data.Binary.Class.Binary Game.LambdaHack.Common.Ability.Ability instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Ability.Ability -- | Screen overlays. module Game.LambdaHack.Client.UI.Overlay -- | Line of colourful text. type AttrLine = [AttrCharW32] emptyAttrLine :: Int -> AttrLine textToAL :: Text -> AttrLine -- | Render line of text in the given foreground colour. fgToAL :: Color -> Text -> AttrLine stringToAL :: String -> AttrLine (<+:>) :: AttrLine -> AttrLine -> AttrLine infixr 6 <+:> -- | A series of screen lines that either fit the width of the screen or -- are intended for truncation when displayed. The length of overlay may -- exceed the length of the screen, unlike in SingleFrame. An -- exception is lines generated from animation, which have to fit in -- either dimension. type Overlay = [AttrLine] -- | Sparse screen overlay representation where only the indicated rows are -- overlayed and the remaining rows are kept unchanged. type IntOverlay = [(Int, AttrLine)] -- | Split a string into lines. Avoids ending the line with a character -- other than whitespace or punctuation. Space characters are removed -- from the start, but never from the end of lines. Newlines are -- respected. splitAttrLine :: X -> AttrLine -> Overlay indentSplitAttrLine :: X -> AttrLine -> [AttrLine] glueLines :: Overlay -> Overlay -> Overlay updateLines :: Int -> (AttrLine -> AttrLine) -> Overlay -> Overlay -- | Color mode for the display. data ColorMode -- | normal, with full colours ColorFull :: ColorMode -- | black and white only ColorBW :: ColorMode linesAttr :: AttrLine -> Overlay splitAttrPhrase :: X -> AttrLine -> Overlay instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Overlay.ColorMode -- | Screen frames. module Game.LambdaHack.Client.UI.Frame type FrameST s = Mutable Vector s Word32 -> ST s () -- | Efficiently composable representation of an operation on a frame, that -- is, on a mutable vector. When the composite operation is eventually -- performed, the vector is frozen to become a SingleFrame. newtype FrameForall FrameForall :: forall s. FrameST s -> FrameForall [unFrameForall] :: FrameForall -> forall s. FrameST s -- | Representation of an operation of overwriting a frame with a single -- line at the given row. writeLine :: Int -> AttrLine -> FrameForall -- | An overlay that fits on the screen (or is meant to be truncated on -- display) and is padded to fill the whole screen and is displayed as a -- single game screen frame. -- -- Note that we don't provide a list of color-highlighed positions -- separately, because overlays need to obscure not only map, but the -- highlights as well. newtype SingleFrame SingleFrame :: Array AttrCharW32 -> SingleFrame [singleFrame] :: SingleFrame -> Array AttrCharW32 -- | Sequences of screen frames, including delays. type Frames = [Maybe FrameForall] blankSingleFrame :: SingleFrame -- | Overlays either the game map only or the whole empty screen frame. We -- assume the lines of the overlay are not too long nor too many. overlayFrame :: IntOverlay -> FrameForall -> FrameForall overlayFrameWithLines :: Bool -> Overlay -> FrameForall -> FrameForall -- | Add a space at the message end, for display overlayed over the level -- map. Also trim (do not wrap!) too long lines. truncateAttrLine :: X -> AttrLine -> X -> AttrLine instance GHC.Show.Show Game.LambdaHack.Client.UI.Frame.SingleFrame instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Frame.SingleFrame -- | Options that affect the behaviour of the client. module Game.LambdaHack.Client.ClientOptions -- | Options that affect the behaviour of the client (but not game rules). data ClientOptions ClientOptions :: Maybe Text -> Maybe Text -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> Maybe Int -> Bool -> Maybe Bool -> Bool -> Bool -> Maybe Text -> Maybe FilePath -> String -> Bool -> Bool -> Bool -> Bool -> Maybe Int -> Maybe Int -> Bool -> ClientOptions -- | Font family to use for the GTK main game window. [sgtkFontFamily] :: ClientOptions -> Maybe Text -- | Font file to use for the SDL2 main game window. [sdlFontFile] :: ClientOptions -> Maybe Text -- | Pixels to add to map cells on top of scalable font max glyph height. [sdlTtfSizeAdd] :: ClientOptions -> Maybe Int -- | Pixels to add to map cells on top of .fon font max glyph height. [sdlFonSizeAdd] :: ClientOptions -> Maybe Int -- | Font size to use for the main game window. [sfontSize] :: ClientOptions -> Maybe Int -- | Whether to use bold attribute for colorful characters. [scolorIsBold] :: ClientOptions -> Maybe Bool -- | How much to log (e.g., from SDL). 1 is all, 5 is errors, the default. [slogPriority] :: ClientOptions -> Maybe Int -- | Maximal frames per second. This is better low and fixed, to avoid -- jerkiness and delays that tell the player there are many intelligent -- enemies on the level. That's better than scaling AI sofistication down -- based on the FPS setting and machine speed. [smaxFps] :: ClientOptions -> Maybe Int -- | Never auto-answer all prompts, even if under AI control. [sdisableAutoYes] :: ClientOptions -> Bool -- | Don't show any animations. [snoAnim] :: ClientOptions -> Maybe Bool -- | Start a new game, overwriting the save file. [snewGameCli] :: ClientOptions -> Bool -- | Don't create directories and files and show time stats. [sbenchmark] :: ClientOptions -> Bool [stitle] :: ClientOptions -> Maybe Text [sfontDir] :: ClientOptions -> Maybe FilePath -- | Prefix of the save game file name. [ssavePrefixCli] :: ClientOptions -> String -- | Whether to use the stdout/stdin frontend. [sfrontendTeletype] :: ClientOptions -> Bool -- | Whether to use null (no input/output) frontend. [sfrontendNull] :: ClientOptions -> Bool -- | Whether to use lazy (output not even calculated) frontend. [sfrontendLazy] :: ClientOptions -> Bool -- | Show clients' internal debug messages. [sdbgMsgCli] :: ClientOptions -> Bool [sstopAfterSeconds] :: ClientOptions -> Maybe Int [sstopAfterFrames] :: ClientOptions -> Maybe Int [sprintEachScreen] :: ClientOptions -> Bool -- | Default value of client options. defClientOptions :: ClientOptions instance GHC.Generics.Generic Game.LambdaHack.Client.ClientOptions.ClientOptions instance GHC.Classes.Eq Game.LambdaHack.Client.ClientOptions.ClientOptions instance GHC.Show.Show Game.LambdaHack.Client.ClientOptions.ClientOptions instance Data.Binary.Class.Binary Game.LambdaHack.Client.ClientOptions.ClientOptions -- | Breadth first search algorithm. module Game.LambdaHack.Client.Bfs -- | Weighted distance between points along shortest paths. data BfsDistance -- | State of legality of moves between adjacent points. data MoveLegal MoveBlocked :: MoveLegal MoveToOpen :: MoveLegal MoveToClosed :: MoveLegal MoveToUnknown :: MoveLegal -- | The minimal distance value assigned to paths that don't enter any -- unknown tiles. minKnownBfs :: BfsDistance -- | The distance value that denotes no legal path between points, either -- due to blocked tiles or pathfinding aborted at earlier tiles, e.g., -- due to unknown tiles. apartBfs :: BfsDistance -- | Maximum value of the type. maxBfsDistance :: BfsDistance -- | Fill out the given BFS array. Unsafe PointArray operations -- are OK here, because the intermediate values of the vector don't leak -- anywhere outside nor are kept unevaluated and so they can't be -- overwritten by the unsafe side-effect. -- -- When computing move cost, we assume doors openable at no cost, because -- other actors use them, too, so the cost is shared and the extra -- visiblity is valuable, too. We treat unknown tiles specially. Whether -- suspect tiles are considered openable depends on -- smarkSuspect. fillBfs :: Array Word8 -> Word8 -> Point -> Array BfsDistance -> () data AndPath AndPath :: [Point] -> Point -> Int -> AndPath [pathList] :: AndPath -> [Point] [pathGoal] :: AndPath -> Point [pathLen] :: AndPath -> Int NoPath :: AndPath -- | Find a path, without the source position, with the smallest length. -- The eps coefficient determines which direction (of the -- closest directions available) that path should prefer, where 0 means -- north-west and 1 means north. findPathBfs :: Array Word8 -> (Point -> Bool) -> Point -> Point -> Int -> Array BfsDistance -> AndPath -- | Access a BFS array and interpret the looked up distance value. accessBfs :: Array BfsDistance -> Point -> Maybe Int -- | The distance value that denotes that path search was aborted at this -- tile due to too large actual distance and that the tile was known and -- not blocked. It is also a true distance value for this tile (shifted -- by minKnownBfs, as all distances of known tiles). abortedKnownBfs :: BfsDistance -- | The distance value that denotes that path search was aborted at this -- tile due to too large actual distance and that the tile was unknown. -- It is also a true distance value for this tile. abortedUnknownBfs :: BfsDistance instance GHC.Generics.Generic Game.LambdaHack.Client.Bfs.AndPath instance GHC.Show.Show Game.LambdaHack.Client.Bfs.AndPath instance GHC.Classes.Eq Game.LambdaHack.Client.Bfs.MoveLegal instance Data.Bits.Bits Game.LambdaHack.Client.Bfs.BfsDistance instance GHC.Enum.Enum Game.LambdaHack.Client.Bfs.BfsDistance instance GHC.Classes.Ord Game.LambdaHack.Client.Bfs.BfsDistance instance GHC.Classes.Eq Game.LambdaHack.Client.Bfs.BfsDistance instance GHC.Show.Show Game.LambdaHack.Client.Bfs.BfsDistance instance Data.Binary.Class.Binary Game.LambdaHack.Client.Bfs.AndPath instance Game.LambdaHack.Common.PointArray.UnboxRepClass Game.LambdaHack.Client.Bfs.BfsDistance -- | AI strategies to direct actors not controlled directly by human -- players. No operation in this module involves the State tyep -- or any of our client/server monads types. module Game.LambdaHack.Client.AI.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 infixr 2 .| -- | Strategy with no actions at all. reject :: Strategy a -- | Conditionally accepted strategy. (.=>) :: Bool -> Strategy a -> Strategy a infix 3 .=> -- | 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 mapStrategyM :: Monad m => (a -> m (Maybe b)) -> Strategy a -> m (Strategy b) instance Data.Traversable.Traversable Game.LambdaHack.Client.AI.Strategy.Strategy instance Data.Foldable.Foldable Game.LambdaHack.Client.AI.Strategy.Strategy instance GHC.Show.Show a => GHC.Show.Show (Game.LambdaHack.Client.AI.Strategy.Strategy a) instance GHC.Base.Monad Game.LambdaHack.Client.AI.Strategy.Strategy instance GHC.Base.Functor Game.LambdaHack.Client.AI.Strategy.Strategy instance GHC.Base.Applicative Game.LambdaHack.Client.AI.Strategy.Strategy instance GHC.Base.MonadPlus Game.LambdaHack.Client.AI.Strategy.Strategy instance GHC.Base.Alternative Game.LambdaHack.Client.AI.Strategy.Strategy -- | Representation of probabilities and random computations. module Game.LambdaHack.Common.Random -- | The monad of computations with random generator state. 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 -- | Fractional chance. type Chance = Rational -- | Give True, with probability determined by the fraction. chance :: Chance -> Rnd Bool -- | Cast dice scaled with current level depth. Note that at the first -- level, the scaled dice are always ignored. castDice :: AbsDepth -> AbsDepth -> Dice -> Rnd Int -- | Cast dice scaled with current level depth and return True if -- the results is greater than 50. chanceDice :: AbsDepth -> AbsDepth -> Dice -> Rnd Bool -- | Cast dice, scaled with current level depth, for coordinates. castDiceXY :: AbsDepth -> AbsDepth -> DiceXY -> Rnd (Int, Int) foldrM :: Foldable t => (a -> b -> Rnd b) -> b -> t a -> Rnd b foldlM' :: Foldable t => (b -> a -> Rnd b) -> b -> t a -> Rnd b -- | Randomly choose an item according to the distribution. rollFreq :: Show a => Frequency a -> StdGen -> (a, StdGen) -- | The type of item aspects and its operations. module Game.LambdaHack.Common.ItemAspect -- | Aspects of items. Those that are named Add* are additive -- (starting at 0) for all items wielded by an actor and they affect the -- actor. data Aspect -- | some effects disabled until item recharges; expressed in game turns Timeout :: Dice -> Aspect -- | percentage damage bonus in melee AddHurtMelee :: Dice -> Aspect -- | percentage armor bonus against melee AddArmorMelee :: Dice -> Aspect -- | percentage armor bonus against ranged AddArmorRanged :: Dice -> Aspect -- | maximal hp AddMaxHP :: Dice -> Aspect -- | maximal calm AddMaxCalm :: Dice -> Aspect -- | speed in m/10s (not when pushed or pulled) AddSpeed :: Dice -> Aspect -- | FOV radius, where 1 means a single tile FOV AddSight :: Dice -> Aspect -- | smell radius AddSmell :: Dice -> Aspect -- | shine radius AddShine :: Dice -> Aspect -- | noctovision radius AddNocto :: Dice -> Aspect -- | aggression, e.g., when closing in for melee AddAggression :: Dice -> Aspect -- | bonus to an ability AddAbility :: Ability -> Dice -> Aspect -- | Record of sums of aspect values of an item, container, actor, etc. data AspectRecord AspectRecord :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Skills -> AspectRecord [aTimeout] :: AspectRecord -> Int [aHurtMelee] :: AspectRecord -> Int [aArmorMelee] :: AspectRecord -> Int [aArmorRanged] :: AspectRecord -> Int [aMaxHP] :: AspectRecord -> Int [aMaxCalm] :: AspectRecord -> Int [aSpeed] :: AspectRecord -> Int [aSight] :: AspectRecord -> Int [aSmell] :: AspectRecord -> Int [aShine] :: AspectRecord -> Int [aNocto] :: AspectRecord -> Int [aAggression] :: AspectRecord -> Int [aSkills] :: AspectRecord -> Skills -- | Partial information about an item, deduced from its item kind. These -- are assigned to each ItemKind. The kmConst flag says -- whether the item's aspects are constant rather than random or -- dependent on item creation dungeon level. data KindMean KindMean :: Bool -> AspectRecord -> KindMean -- | whether the item doesn't need second identification [kmConst] :: KindMean -> Bool -- | mean value of item's possible aspects [kmMean] :: KindMean -> AspectRecord -- | A seed for rolling aspects of an item Clients have partial knowledge -- of how item ids map to the seeds. They gain knowledge by identifying -- items. data ItemSeed -- | AI and UI hints about the role of the item. data EqpSlot EqpSlotMiscBonus :: EqpSlot EqpSlotAddHurtMelee :: EqpSlot EqpSlotAddArmorMelee :: EqpSlot EqpSlotAddArmorRanged :: EqpSlot EqpSlotAddMaxHP :: EqpSlot EqpSlotAddSpeed :: EqpSlot EqpSlotAddSight :: EqpSlot EqpSlotLightSource :: EqpSlot EqpSlotWeapon :: EqpSlot EqpSlotMiscAbility :: EqpSlot EqpSlotAbMove :: EqpSlot EqpSlotAbMelee :: EqpSlot EqpSlotAbDisplace :: EqpSlot EqpSlotAbAlter :: EqpSlot EqpSlotAbProject :: EqpSlot EqpSlotAbApply :: EqpSlot EqpSlotAddMaxCalm :: EqpSlot EqpSlotAddSmell :: EqpSlot EqpSlotAddNocto :: EqpSlot EqpSlotAddAggression :: EqpSlot EqpSlotAbWait :: EqpSlot EqpSlotAbMoveItem :: EqpSlot emptyAspectRecord :: AspectRecord addMeanAspect :: AspectRecord -> Aspect -> AspectRecord castAspect :: AbsDepth -> AbsDepth -> AspectRecord -> Aspect -> Rnd AspectRecord aspectsRandom :: [Aspect] -> Bool sumAspectRecord :: [(AspectRecord, Int)] -> AspectRecord aspectRecordToList :: AspectRecord -> [Aspect] seedToAspect :: ItemSeed -> [Aspect] -> AbsDepth -> AbsDepth -> AspectRecord prEqpSlot :: EqpSlot -> AspectRecord -> Int ceilingMeanDice :: Dice -> Int instance GHC.Generics.Generic Game.LambdaHack.Common.ItemAspect.EqpSlot instance GHC.Enum.Bounded Game.LambdaHack.Common.ItemAspect.EqpSlot instance GHC.Enum.Enum Game.LambdaHack.Common.ItemAspect.EqpSlot instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.EqpSlot instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.EqpSlot instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.EqpSlot instance Data.Binary.Class.Binary Game.LambdaHack.Common.ItemAspect.ItemSeed instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.ItemAspect.ItemSeed instance GHC.Enum.Enum Game.LambdaHack.Common.ItemAspect.ItemSeed instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.ItemSeed instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.ItemSeed instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.ItemSeed instance GHC.Generics.Generic Game.LambdaHack.Common.ItemAspect.KindMean instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.KindMean instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.KindMean instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.KindMean instance GHC.Generics.Generic Game.LambdaHack.Common.ItemAspect.AspectRecord instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.AspectRecord instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.AspectRecord instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.AspectRecord instance GHC.Generics.Generic Game.LambdaHack.Common.ItemAspect.Aspect instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.Aspect instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.Aspect instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.Aspect instance Control.DeepSeq.NFData Game.LambdaHack.Common.ItemAspect.EqpSlot instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.ItemAspect.AspectRecord instance Data.Binary.Class.Binary Game.LambdaHack.Common.ItemAspect.AspectRecord instance Control.DeepSeq.NFData Game.LambdaHack.Common.ItemAspect.Aspect -- | A game requires the engine provided by the library, perhaps -- customized, and game content, defined completely afresh for the -- particular game. The possible kinds of content are fixed in the -- library and all defined within the library source code directory. On -- the other hand, game content, is defined in the directory hosting the -- particular game definition. -- -- Content of a given kind is just a list of content items. After the -- list is verified and the data preprocessed, it's held in the -- ContentData datatype. module Game.LambdaHack.Common.ContentData -- | Content identifiers for the content type c. newtype ContentId c ContentId :: Word16 -> ContentId c -- | Verified and preprocessed content data of a particular kind. data ContentData c -- | For each group that the kind belongs to, denoted by a -- GroupName in the first component of a pair, the second -- component of a pair shows how common the kind is within the group. type Freqs a = [(GroupName a, Int)] -- | Rarity on given depths. type Rarity = [(Double, Int)] contentIdIndex :: ContentId k -> Int validateRarity :: Rarity -> [Text] emptyContentData :: ContentData a makeContentData :: (NFData c, Show c) => String -> (c -> Text) -> (c -> Freqs c) -> (c -> [Text]) -> ([c] -> ContentData c -> [Text]) -> [c] -> ContentData c -- | Content element at given id. okind :: ContentData a -> ContentId a -> a omemberGroup :: ContentData a -> GroupName a -> Bool oisSingletonGroup :: ContentData a -> GroupName a -> Bool -- | The id of the unique member of a singleton content group. ouniqGroup :: Show a => ContentData a -> GroupName a -> ContentId a -- | Pick a random id belonging to a group and satisfying a predicate. opick :: Show a => ContentData a -> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a)) -- | Fold over all content elements of a. ofoldrWithKey :: ContentData a -> (ContentId a -> a -> b -> b) -> b -> b -- | Fold strictly over all content a. ofoldlWithKey' :: ContentData a -> (b -> ContentId a -> a -> b) -> b -> b -- | Fold over the given group only. ofoldlGroup' :: ContentData a -> GroupName a -> (b -> Int -> ContentId a -> a -> b) -> b -> b omapVector :: ContentData a -> (a -> b) -> Vector b oimapVector :: ContentData a -> (ContentId a -> a -> b) -> Vector b -- | Size of content a. olength :: ContentData a -> Int instance GHC.Generics.Generic (Game.LambdaHack.Common.ContentData.ContentData c) instance GHC.Generics.Generic (Game.LambdaHack.Common.ContentData.ContentId c) instance Data.Binary.Class.Binary (Game.LambdaHack.Common.ContentData.ContentId c) instance GHC.Enum.Enum (Game.LambdaHack.Common.ContentData.ContentId c) instance GHC.Classes.Ord (Game.LambdaHack.Common.ContentData.ContentId c) instance GHC.Classes.Eq (Game.LambdaHack.Common.ContentData.ContentId c) instance GHC.Show.Show (Game.LambdaHack.Common.ContentData.ContentId c) instance Control.DeepSeq.NFData c => Control.DeepSeq.NFData (Game.LambdaHack.Common.ContentData.ContentData c) instance Game.LambdaHack.Common.PointArray.UnboxRepClass (Game.LambdaHack.Common.ContentData.ContentId k) instance Control.DeepSeq.NFData (Game.LambdaHack.Common.ContentData.ContentId c) instance Data.Hashable.Class.Hashable (Game.LambdaHack.Common.ContentData.ContentId c) -- | Screen frames and animations. module Game.LambdaHack.Client.UI.Animation -- | 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 -- | Render animations on top of a screen frame. -- -- Located in this module to keep Animation abstract. renderAnim :: FrameForall -> Animation -> Frames pushAndDelay :: Animation blinkColorActor :: Point -> Char -> Color -> Color -> 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 -- | Attack that is subtle (e.g., damage dice 0). subtleHit :: Point -> Animation -- | Death animation for an organic body. deathBody :: Point -> Animation -- | Death animation for an organic body, short version (e.g., for -- enemies). shortDeathBody :: Point -> Animation -- | Mark actor location animation. actorX :: Point -> Animation -- | Actor teleport animation. teleport :: (Point, Point) -> Animation -- | Swap-places animation, both hostile and friendly. swapPlaces :: (Point, Point) -> Animation fadeout :: Bool -> Int -> X -> Y -> Rnd Animation blank :: Maybe AttrCharW32 cSym :: Color -> Char -> Maybe AttrCharW32 mapPosToOffset :: (Point, AttrCharW32) -> (Int, [AttrCharW32]) mzipSingleton :: Point -> Maybe AttrCharW32 -> IntOverlay mzipPairs :: (Point, Point) -> (Maybe AttrCharW32, Maybe AttrCharW32) -> IntOverlay instance GHC.Show.Show Game.LambdaHack.Client.UI.Animation.Animation instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Animation.Animation -- | Ring buffers. module Game.LambdaHack.Common.RingBuffer -- | Ring buffers of a size determined at initialization. data RingBuffer a empty :: Int -> a -> RingBuffer a cons :: a -> RingBuffer a -> RingBuffer a uncons :: RingBuffer a -> Maybe (a, RingBuffer a) toList :: RingBuffer a -> [a] length :: RingBuffer a -> Int instance GHC.Generics.Generic (Game.LambdaHack.Common.RingBuffer.RingBuffer a) instance GHC.Show.Show a => GHC.Show.Show (Game.LambdaHack.Common.RingBuffer.RingBuffer a) instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (Game.LambdaHack.Common.RingBuffer.RingBuffer a) -- | Keeping track of forked threads. module Game.LambdaHack.Common.Thread forkChild :: MVar [Async ()] -> IO () -> IO () waitForChildren :: MVar [Async ()] -> IO () -- | 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 -- | An infinitesimal time period. timeEpsilon :: Time -- | At least once per clip all moves are resolved and a frame or a frame -- delay is generated. Currently one clip is 0.05 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 -- | This many ticks fits in a single second. Do not export, timeSecond :: Time -- | Absolute time addition, e.g., for summing the total game session time -- from the times of individual games. absoluteTimeAdd :: Time -> Time -> Time absoluteTimeSubtract :: Time -> Time -> Time -- | Absolute time negation. To be used for reversing time flow, e.g., for -- comparing absolute times in the reverse order. absoluteTimeNegate :: Time -> Time -- | How many time intervals of the latter kind fits in an interval of the -- former kind. timeFit :: Time -> Time -> Int -- | How many time intervals of the latter kind cover an interval of the -- former kind (rounded up). timeFitUp :: Time -> Time -> Int -- | One-dimentional vectors. Introduced to tell apart the 2 uses of Time: -- as an absolute game time and as an increment. newtype Delta a Delta :: a -> Delta a -- | Shifting an absolute time by a time vector. timeShift :: Time -> Delta Time -> Time -- | Time time vector between the second and the first absolute times. The -- arguments are in the same order as in the underlying scalar -- subtraction. timeDeltaToFrom :: Time -> Time -> Delta Time -- | Addition of time deltas. timeDeltaAdd :: Delta Time -> Delta Time -> Delta Time -- | Subtraction of time deltas. The arguments are in the same order as in -- the underlying scalar subtraction. timeDeltaSubtract :: Delta Time -> Delta Time -> Delta Time -- | Reverse a time vector. timeDeltaReverse :: Delta Time -> Delta Time -- | Scale the time vector by an Int scalar value. timeDeltaScale :: Delta Time -> Int -> Delta Time -- | Take the given percent of the time vector. timeDeltaPercent :: Delta Time -> Int -> Delta Time -- | Divide a time vector. timeDeltaDiv :: Delta Time -> Int -> Delta Time -- | Represent the main 10 thresholds of a time range by digits, given the -- total length of the time range. timeDeltaToDigit :: Delta Time -> Delta 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 make one step (move one tile, -- which is 1 m by 1 m). data Speed -- | Constructor for content definitions. toSpeed :: Int -> Speed -- | Pretty-printing of speed in the format used in content definitions. fromSpeed :: Speed -> Int minSpeed :: Int -- | No movement possible at that speed. speedZero :: Speed -- | Fast walk speed (2 m/s) that suffices to move one tile in one turn. speedWalk :: Speed -- | Limp speed (1 m/s) that suffices to move one tile in two turns. This -- is the minimal speed for projectiles to fly just one space and drop. speedLimp :: Speed -- | Sword thrust speed (10 m/s). Base weapon damages, both melee and -- ranged, are given assuming this speed and ranged damage is modified -- accordingly when projectile speeds differ. Differences in melee weapon -- swing speeds are captured in damage bonuses instead, since many other -- factors influence total damage. -- -- Billiard ball is 25 ms, sword swing at the tip is 35 ms, -- medieval bow is 70 ms, AK47 is 700 ms. speedThrust :: Speed -- | Modify damage when projectiles is at a non-standard speed. Energy and -- so damage is proportional to the square of speed, hence the formula. modifyDamageBySpeed :: Int64 -> Speed -> Int64 -- | 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 -> Delta Time -- | Calculate projectile speed from item weight in grams and velocity -- percent modifier. See -- https://github.com/LambdaHack/LambdaHack/wiki/Item-statistics. speedFromWeight :: Int -> Int -> Speed -- | Calculate maximum range taking into account the linger percentage. rangeFromSpeedAndLinger :: Speed -> Int -> Int -- | The smallest unit of time. Should not be exported and used elsewhere, -- because the proportion of turn to tick is an implementation detail. -- The significance of this detail is only that it determines resolution -- of the time dimension. _timeTick :: Time -- | This many turns fit in a single second. turnsInSecond :: Int64 -- | Number of seconds in a mega-second. sInMs :: Int64 -- | The minimal speed is half a meter (half a step across a tile) per -- second (two standard turns, which the time span during which -- projectile moves, unless it has modified linger value). This is four -- times slower than standard human movement speed. -- -- It needen't be lower, because rangeFromSpeed gives 0 steps -- with such speed, so the actor's trajectory is empty, so it drops down -- at once. Twice that speed already moves a normal projectile one step -- before it stops. It shouldn't be lower or a slow actor would incur -- such a time debt for performing a single action that he'd be paralyzed -- for many turns, e.g., leaving his dead body on the screen for very -- long. minimalSpeed :: Int64 -- | Calculate maximum range in meters of a projectile from its speed. See -- https://github.com/LambdaHack/LambdaHack/wiki/Item-statistics. -- With this formula, each projectile flies for at most 1 second, that is -- 2 standard turns, and then drops to the ground. rangeFromSpeed :: Speed -> Int instance Data.Binary.Class.Binary Game.LambdaHack.Common.Time.Speed instance GHC.Classes.Ord Game.LambdaHack.Common.Time.Speed instance GHC.Classes.Eq Game.LambdaHack.Common.Time.Speed instance GHC.Base.Functor Game.LambdaHack.Common.Time.Delta instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (Game.LambdaHack.Common.Time.Delta a) instance GHC.Enum.Bounded a => GHC.Enum.Bounded (Game.LambdaHack.Common.Time.Delta a) instance GHC.Enum.Enum a => GHC.Enum.Enum (Game.LambdaHack.Common.Time.Delta a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Game.LambdaHack.Common.Time.Delta a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Game.LambdaHack.Common.Time.Delta a) instance GHC.Show.Show a => GHC.Show.Show (Game.LambdaHack.Common.Time.Delta a) instance Data.Binary.Class.Binary Game.LambdaHack.Common.Time.Time instance GHC.Enum.Bounded Game.LambdaHack.Common.Time.Time instance GHC.Enum.Enum Game.LambdaHack.Common.Time.Time instance GHC.Classes.Ord Game.LambdaHack.Common.Time.Time instance GHC.Classes.Eq Game.LambdaHack.Common.Time.Time instance GHC.Show.Show Game.LambdaHack.Common.Time.Time instance GHC.Show.Show Game.LambdaHack.Common.Time.Speed -- | Game messages displayed on top of the screen for the player to read -- and then saved to player history. module Game.LambdaHack.Client.UI.Msg -- | The type of a single game message. data Msg toMsg :: AttrLine -> Msg toPrompt :: AttrLine -> Msg -- | The set of messages, with repetitions, to show at the screen at once. data Report -- | Test if the set of messages is empty. nullReport :: Report -> Bool -- | Add a message to the start of report. consReport :: Msg -> Report -> Report -- | Render a report as a (possibly very long) AttrLine. renderReport :: Report -> AttrLine findInReport :: (AttrLine -> Bool) -> Report -> Maybe Msg -- | The history of reports. This is a ring buffer of the given length -- containing old archived history and two most recent reports stored -- separately. data History newReport :: History -> Report -- | Empty history of the given maximal length. emptyHistory :: Int -> History -- | Add a message to the new report of history, eliminating a possible -- duplicate and noting its existence in the result. addToReport :: History -> Msg -> Int -> (History, Bool) -- | Archive old report to history, filtering out prompts. Set up new -- report with a new timestamp. archiveReport :: History -> Time -> History lengthHistory :: History -> Int -- | Render history as many lines of text. New report is not rendered. It's -- expected to be empty when history is shown. renderHistory :: History -> [AttrLine] type UAttrLine = Vector Word32 data RepMsgN uToAttrLine :: UAttrLine -> AttrLine attrLineToU :: AttrLine -> UAttrLine -- | Empty set of messages. emptyReport :: Report -- | Add a message to the end of the report. snocReport :: Report -> Msg -> Int -> Report renderRepetition :: RepMsgN -> AttrLine scrapRepetition :: History -> Maybe History renderTimeReport :: Time -> Report -> [AttrLine] instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Msg.History instance GHC.Show.Show Game.LambdaHack.Client.UI.Msg.History instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Msg.Report instance GHC.Show.Show Game.LambdaHack.Client.UI.Msg.Report instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Msg.RepMsgN instance GHC.Show.Show Game.LambdaHack.Client.UI.Msg.RepMsgN instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Msg.Msg instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Msg.Msg instance GHC.Show.Show Game.LambdaHack.Client.UI.Msg.Msg instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Msg.History instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Msg.RepMsgN instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Msg.Msg -- | Basic operations on bounded 2D vectors, with an efficient, but not 1-1 -- and not monotonic Enum instance. module Game.LambdaHack.Common.Vector -- | 2D vectors in cartesian representation. Coordinates grow to the right -- and down, so that the (1, 1) vector points to the bottom-right corner -- of the screen. data Vector Vector :: X -> Y -> Vector [vx] :: Vector -> X [vy] :: Vector -> Y -- | Tells if a vector has length 1 in the chessboard metric. isUnit :: Vector -> Bool -- | Checks whether a unit vector is a diagonal direction, as opposed to -- cardinal. If the vector is not unit, it checks that the vector is not -- horizontal nor vertical. isDiagonal :: Vector -> Bool -- | Reverse an arbirary vector. neg :: Vector -> Vector -- | The lenght of a vector in the chessboard metric, where diagonal moves -- cost 1. chessDistVector :: Vector -> Int -- | Squared euclidean distance between two vectors. euclidDistSqVector :: Vector -> Vector -> Int -- | Vectors of all unit moves in the chessboard metric, clockwise, -- starting north-west. moves :: [Vector] -- | Vectors of all cardinal direction unit moves, clockwise, starting -- north. movesCardinal :: [Vector] -- | Vectors of all diagonal direction unit moves, clockwise, starting -- north. movesDiagonal :: [Vector] compassText :: Vector -> Text -- | All (8 at most) closest neighbours of a point within an area. vicinity :: X -> Y -> Point -> [Point] vicinityUnsafe :: Point -> [Point] -- | All (4 at most) cardinal direction neighbours of a point within an -- area. vicinityCardinal :: X -> Y -> Point -> [Point] vicinityCardinalUnsafe :: Point -> [Point] squareUnsafeSet :: Point -> EnumSet Point -- | Translate a point by a vector. shift :: Point -> Vector -> Point -- | Translate a point by a vector, but only if the result fits in an area. shiftBounded :: X -> Y -> Point -> Vector -> Point -- | A list of points that a list of vectors leads to. trajectoryToPath :: Point -> [Vector] -> [Point] -- | A list of points that a list of vectors leads to, bounded by level -- size. trajectoryToPathBounded :: X -> Y -> Point -> [Vector] -> [Point] -- | The vector between the second point and the first. We have -- --
--   shift pos1 (pos2 `vectorToFrom` pos1) == pos2
--   
-- -- The arguments are in the same order as in the underlying scalar -- subtraction. vectorToFrom :: Point -> Point -> Vector computeTrajectory :: Int -> Int -> Int -> [Point] -> ([Vector], (Speed, Int)) type RadianAngle = Double -- | Rotate a vector by the given angle (expressed in radians) -- counterclockwise and return a unit vector approximately in the -- resulting direction. rotate :: RadianAngle -> 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 :: Point -> Point -> Vector -- | Maximal supported vector X and Y coordinates. maxVectorDim :: Int -- | Currently unused. _moveTexts :: [Text] longMoveTexts :: [Text] -- | Given a vector of arbitrary non-zero length, produce a unit vector -- that points in the same direction (in the chessboard metric). Of -- several equally good directions it picks one of those that visually -- (in the euclidean metric) maximally align with the original vector. normalize :: Double -> Double -> Vector normalizeVector :: Vector -> Vector -- | A list of vectors between a list of points. pathToTrajectory :: [Point] -> [Vector] instance GHC.Generics.Generic Game.LambdaHack.Common.Vector.Vector instance GHC.Classes.Ord Game.LambdaHack.Common.Vector.Vector instance GHC.Classes.Eq Game.LambdaHack.Common.Vector.Vector instance GHC.Read.Read Game.LambdaHack.Common.Vector.Vector instance GHC.Show.Show Game.LambdaHack.Common.Vector.Vector instance Data.Binary.Class.Binary Game.LambdaHack.Common.Vector.Vector instance GHC.Enum.Enum Game.LambdaHack.Common.Vector.Vector instance Control.DeepSeq.NFData Game.LambdaHack.Common.Vector.Vector -- | Frontend-independent keyboard input operations. module Game.LambdaHack.Client.UI.Key -- | Frontend-independent datatype to represent keys. data Key Esc :: Key Return :: Key Space :: Key Tab :: Key BackTab :: Key BackSpace :: Key PgUp :: Key PgDn :: Key Left :: Key Right :: Key Up :: Key Down :: Key End :: Key Begin :: Key Insert :: Key Delete :: Key PrintScreen :: Key Home :: Key -- | a keypad key for a character (digits and operators) KP :: Char -> Key -- | a single printable character Char :: Char -> Key -- | function key Fun :: Int -> Key -- | left mouse button pressed LeftButtonPress :: Key -- | middle mouse button pressed MiddleButtonPress :: Key -- | right mouse button pressed RightButtonPress :: Key -- | left mouse button released LeftButtonRelease :: Key -- | middle mouse button released MiddleButtonRelease :: Key -- | right mouse button released RightButtonRelease :: Key -- | mouse wheel rotated north WheelNorth :: Key -- | mouse wheel rotated south WheelSouth :: Key -- | an unknown key, registered to warn the user Unknown :: String -> Key DeadKey :: Key -- | Our own encoding of modifiers. data Modifier NoModifier :: Modifier Shift :: Modifier Control :: Modifier Alt :: Modifier -- | Key and modifier. data KM KM :: Modifier -> Key -> KM [modifier] :: KM -> Modifier [key] :: KM -> Key -- | Key, modifier and position of mouse pointer. data KMP KMP :: KM -> Point -> KMP [kmpKeyMod] :: KMP -> KM [kmpPointer] :: KMP -> Point -- | Common and terse names for keys. showKey :: Key -> String -- | Show a key with a modifier, if any. showKM :: KM -> String escKM :: KM spaceKM :: KM safeSpaceKM :: KM returnKM :: KM pgupKM :: KM pgdnKM :: KM wheelNorthKM :: KM wheelSouthKM :: KM upKM :: KM downKM :: KM leftKM :: KM rightKM :: KM homeKM :: KM endKM :: KM backspaceKM :: KM leftButtonReleaseKM :: KM rightButtonReleaseKM :: KM dirAllKey :: Bool -> Bool -> [Key] -- | Configurable event handler for the direction keys. Used for directed -- commands such as close door. handleDir :: Bool -> Bool -> KM -> Maybe Vector -- | Binding of both sets of movement keys, vi and laptop. moveBinding :: Bool -> Bool -> (Vector -> a) -> (Vector -> a) -> [(KM, a)] mkKM :: String -> KM mkChar :: Char -> KM mkKP :: Char -> KM -- | 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. -- -- See -- https://github.com/twobob/gtk-/blob/master/gdk/keyname-table.h keyTranslate :: String -> Key -- | Translate key from a Web API string description -- (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key#Key_values) -- to our internal key type. To be used in web frontends. The argument -- says whether Shift is pressed. keyTranslateWeb :: String -> Bool -> Key dirKeypadKey :: [Key] dirKeypadShiftChar :: [Char] dirKeypadShiftKey :: [Key] dirLaptopKey :: [Key] dirLaptopShiftKey :: [Key] dirViChar :: [Char] dirViKey :: [Key] dirViShiftKey :: [Key] dirMoveNoModifier :: Bool -> Bool -> [Key] dirRunNoModifier :: Bool -> Bool -> [Key] dirRunControl :: [Key] dirRunShift :: [Key] instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Key.KM instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Key.KM instance GHC.Classes.Ord Game.LambdaHack.Client.UI.Key.KM instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Key.Modifier instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Key.Modifier instance GHC.Classes.Ord Game.LambdaHack.Client.UI.Key.Modifier instance GHC.Show.Show Game.LambdaHack.Client.UI.Key.Modifier instance GHC.Generics.Generic Game.LambdaHack.Client.UI.Key.Key instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Key.Key instance GHC.Classes.Ord Game.LambdaHack.Client.UI.Key.Key instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Key.KM instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.Key.KM instance GHC.Show.Show Game.LambdaHack.Client.UI.Key.KM instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Key.Modifier instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.Key.Modifier instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.Key.Key instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.Key.Key -- | Screen frames and animations. module Game.LambdaHack.Client.UI.Frontend.Common -- | Raw frontend definition. The minimal closed set of values that need to -- depend on the specifics of the chosen frontend. data RawFrontend RawFrontend :: SingleFrame -> IO () -> IO () -> MVar () -> TQueue KMP -> IO () -> RawFrontend [fdisplay] :: RawFrontend -> SingleFrame -> IO () [fshutdown] :: RawFrontend -> IO () [fshowNow] :: RawFrontend -> MVar () [fchanKey] :: RawFrontend -> TQueue KMP [fprintScreen] :: RawFrontend -> IO () startupBound :: (MVar RawFrontend -> IO ()) -> IO RawFrontend createRawFrontend :: (SingleFrame -> IO ()) -> IO () -> IO RawFrontend -- | Empty the keyboard channel. resetChanKey :: TQueue KMP -> IO () saveKMP :: RawFrontend -> Modifier -> Key -> Point -> IO () -- | Translates modifiers to our own encoding. modifierTranslate :: Bool -> Bool -> Bool -> Bool -> Modifier -- | Line terminal text frontend based on stdin/stdout, intended for -- logging tests, but may be used on a teletype terminal, or with -- keyboard and printer. module Game.LambdaHack.Client.UI.Frontend.Teletype -- | Set up the frontend input and output. startup :: ClientOptions -> IO RawFrontend -- | The name of the frontend. frontendName :: String -- | Text frontend based on SDL2. module Game.LambdaHack.Client.UI.Frontend.Sdl -- | Set up and start the main loop providing input and output. -- -- Apparently some SDL backends are not thread-safe -- (https://wiki.libsdl.org/FAQDevelopment; "this should only be -- run in the thread that initialized the video subsystem, and for extra -- safety, you should consider only doing those things on the main thread -- in any case") so we stick to a single bound thread (but not to the -- main thread; enough is enough and at least in the case of OpenGL all -- bound threads are supposed to be as good as the main thread). startup :: ClientOptions -> IO RawFrontend -- | The name of the frontend. frontendName :: String type FontAtlas = EnumMap AttrCharW32 Texture -- | Session data maintained by the frontend. data FrontendSession FrontendSession :: Window -> Renderer -> Font -> IORef FontAtlas -> IORef Texture -> IORef SingleFrame -> IORef Bool -> IORef Bool -> MVar SingleFrame -> MVar () -> FrontendSession [swindow] :: FrontendSession -> Window [srenderer] :: FrontendSession -> Renderer [sfont] :: FrontendSession -> Font [satlas] :: FrontendSession -> IORef FontAtlas [stexture] :: FrontendSession -> IORef Texture [spreviousFrame] :: FrontendSession -> IORef SingleFrame [sforcedShutdown] :: FrontendSession -> IORef Bool [scontinueSdlLoop] :: FrontendSession -> IORef Bool [sframeQueue] :: FrontendSession -> MVar SingleFrame [sframeDrawn] :: FrontendSession -> MVar () startupFun :: ClientOptions -> MVar RawFrontend -> IO () shutdown :: FrontendSession -> IO () forceShutdown :: FrontendSession -> IO () -- | Add a frame to be drawn. display :: FrontendSession -> SingleFrame -> IO () drawFrame :: ClientOptions -> FrontendSession -> SingleFrame -> IO () printScreen :: FrontendSession -> IO () -- | Translates modifiers to our own encoding, ignoring Shift. modTranslate :: KeyModifier -> Modifier keyTranslate :: Bool -> Keycode -> Key colorToRGBA :: Color -> V4 Word8 -- | Re-export the operations of the chosen raw frontend (determined at -- compile time with cabal flags). module Game.LambdaHack.Client.UI.Frontend.Chosen -- | Set up and start the main loop providing input and output. -- -- Apparently some SDL backends are not thread-safe -- (https://wiki.libsdl.org/FAQDevelopment; "this should only be -- run in the thread that initialized the video subsystem, and for extra -- safety, you should consider only doing those things on the main thread -- in any case") so we stick to a single bound thread (but not to the -- main thread; enough is enough and at least in the case of OpenGL all -- bound threads are supposed to be as good as the main thread). startup :: ClientOptions -> IO RawFrontend -- | The name of the frontend. frontendName :: String -- | Display game data on the screen and receive user input using one of -- the available raw frontends and derived operations. module Game.LambdaHack.Client.UI.Frontend -- | The instructions sent by clients to the raw frontend, indexed by the -- returned value. data FrontReq :: * -> * -- | Show a frame. [FrontFrame] :: {frontFrame :: FrameForall} -> FrontReq () -- | Perform an explicit delay of the given length. [FrontDelay] :: Int -> FrontReq () -- | Flush frames, display a frame and ask for a keypress. [FrontKey] :: {frontKeyKeys :: [KM], frontKeyFrame :: FrameForall} -> FrontReq KMP -- | Tell if a keypress is pending. [FrontPressed] :: FrontReq Bool -- | Discard a key in the queue, if any. [FrontDiscard] :: FrontReq () -- | Add a key to the queue. [FrontAdd] :: KMP -> FrontReq () -- | Set in the frontend that it should auto-answer prompts. [FrontAutoYes] :: Bool -> FrontReq () -- | Shut the frontend down. [FrontShutdown] :: FrontReq () -- | Take screenshot. [FrontPrintScreen] :: FrontReq () -- | Connection channel between a frontend and a client. Frontend acts as a -- server, serving keys, etc., when given frames to display. newtype ChanFrontend ChanFrontend :: (forall a. FrontReq a -> IO a) -> ChanFrontend -- | Initialize the frontend chosen by the player via client options. chanFrontendIO :: ClientOptions -> IO ChanFrontend -- | The name of the chosen frontend. frontendName :: String -- | Machinery allocated for an individual frontend at its startup, -- unchanged for its lifetime. data FrontSetup getKey :: ClientOptions -> FrontSetup -> RawFrontend -> [KM] -> FrameForall -> IO KMP fchanFrontend :: ClientOptions -> FrontSetup -> RawFrontend -> ChanFrontend display :: RawFrontend -> FrameForall -> IO () defaultMaxFps :: Int microInSec :: Int frameTimeoutThread :: Int -> MVar Int -> RawFrontend -> IO () lazyStartup :: IO RawFrontend nullStartup :: IO RawFrontend seqFrame :: SingleFrame -> IO () -- | The type of kinds of weapons, treasure, organs, blasts, etc. module Game.LambdaHack.Content.ItemKind -- | Item properties that are fixed for a given kind of items. Note that -- this type is mutually recursive with Effect and Feature. data ItemKind ItemKind :: Char -> Text -> Freqs ItemKind -> [Flavour] -> Dice -> Rarity -> Part -> Int -> Dice -> [Aspect] -> [Effect] -> [Feature] -> Text -> [(GroupName ItemKind, CStore)] -> ItemKind -- | map symbol [isymbol] :: ItemKind -> Char -- | generic name; is pluralized if needed [iname] :: ItemKind -> Text -- | frequency within groups [ifreq] :: ItemKind -> Freqs ItemKind -- | possible flavours [iflavour] :: ItemKind -> [Flavour] -- | created in that quantity [icount] :: ItemKind -> Dice -- | rarity on given depths [irarity] :: ItemKind -> Rarity -- | the verb for hitting [iverbHit] :: ItemKind -> Part -- | weight in grams [iweight] :: ItemKind -> Int -- | basic impact damage [idamage] :: ItemKind -> Dice -- | affect the actor continuously [iaspects] :: ItemKind -> [Aspect] -- | cause the effects when triggered [ieffects] :: ItemKind -> [Effect] -- | properties of the item [ifeature] :: ItemKind -> [Feature] -- | description [idesc] :: ItemKind -> Text -- | accompanying organs and equipment [ikit] :: ItemKind -> [(GroupName ItemKind, CStore)] makeData :: [ItemKind] -> ContentData ItemKind -- | Effects of items. Can be invoked by the item wielder to affect another -- actor or the wielder himself. Many occurences in the same item are -- possible. data Effect -- | burn with this damage Burn :: Dice -> Effect -- | explode producing this group of blasts Explode :: (GroupName ItemKind) -> Effect -- | modify HP of the actor by this amount RefillHP :: Int -> Effect -- | modify Calm of the actor by this amount RefillCalm :: Int -> Effect -- | change actor's allegiance Dominate :: Effect -- | make actor susceptible to domination Impress :: Effect -- | summon the given number of actors of this group Summon :: (GroupName ItemKind) -> Dice -> Effect -- | ascend to another level of the dungeon Ascend :: Bool -> Effect -- | escape from the dungeon Escape :: Effect -- | paralyze for this many game clips Paralyze :: Dice -> Effect -- | give free time to actor of this many actor turns InsertMove :: Dice -> Effect -- | teleport actor across rougly this distance Teleport :: Dice -> Effect -- | create an item of the group and insert into the store with the given -- random timer CreateItem :: CStore -> (GroupName ItemKind) -> TimerDice -> Effect -- | make the actor drop items of the given group from the given store; the -- first integer says how many item kinds to drop, the second, how many -- copies of each kind to drop; for non-organs, beware of not dropping -- all, or cluttering store with rubbish becomes beneficial DropItem :: Int -> Int -> CStore -> (GroupName ItemKind) -> Effect -- | find a suitable (i.e., numerous enough) item, starting from the floor, -- and polymorph it randomly PolyItem :: Effect -- | find a suitable (i.e., not identified) item, starting from the floor, -- and identify it Identify :: Effect -- | detect something on the map in the given radius Detect :: DetectKind -> Int -> Effect -- | send an actor flying (push or pull, depending) SendFlying :: ThrowMod -> Effect -- | push an actor PushActor :: ThrowMod -> Effect -- | pull an actor PullActor :: ThrowMod -> Effect -- | make the actor drop its best weapon DropBestWeapon :: Effect -- | activate all items with this symbol in inventory; space character -- means all symbols ActivateInv :: Char -> Effect -- | remove all smell on the level ApplyPerfume :: Effect -- | trigger one of the effects with equal probability OneOf :: [Effect] -> Effect -- | trigger the effect when item smashed (not when applied nor meleed) OnSmash :: Effect -> Effect -- | this effect inactive until timeout passes Recharging :: Effect -> Effect -- | only fire next effect if previous fully activated Composite :: [Effect] -> Effect -- | the item is temporary, vanishes at even void Periodic activation, -- unless Durable and not Fragile, and shows message with this verb at -- last copy activation or at each activation unless Durable and Fragile Temporary :: Text -> Effect data DetectKind DetectAll :: DetectKind DetectActor :: DetectKind DetectItem :: DetectKind DetectExit :: DetectKind DetectHidden :: DetectKind DetectEmbed :: DetectKind -- | Specification of how to randomly roll a timer at item creation to -- obtain a fixed timer for the item's lifetime. data TimerDice -- | Parameters modifying a throw of a projectile or flight of pushed -- actor. Not additive and don't start at 0. data ThrowMod ThrowMod :: Int -> Int -> ThrowMod -- | fly with this percentage of base throw speed [throwVelocity] :: ThrowMod -> Int -- | fly for this percentage of 2 turns [throwLinger] :: ThrowMod -> Int -- | Features of item. Affect only the item in question, not the actor -- carrying it, and so not additive in any sense. data Feature -- | extra label of the item; it's not pluralized ELabel :: Text -> Feature -- | drop and break at target tile, even if no hit Fragile :: Feature -- | drop at target tile, even if no hit Lobable :: Feature -- | don't break even when hitting or applying Durable :: Feature -- | parameters modifying a throw ToThrow :: ThrowMod -> Feature -- | until identified, presents as this unique kind HideAs :: (GroupName ItemKind) -> Feature -- | AI and UI flag: consider equipping (independent of EqpSlot, -- e.g., in case of mixed blessings) Equipable :: Feature -- | AI and UI flag: consider meleeing with Meleeable :: Feature -- | AI and UI flag: don't risk identifying by use; also, can't throw or -- apply if not calm enough Precious :: Feature -- | overrides actor's tactic; WIP; move? Tactic :: Tactic -> Feature -- | the item is an explosion blast particle Blast :: Feature -- | AI and UI flag that leaks item intended use EqpSlot :: EqpSlot -> Feature -- | at most one copy can ever be generated Unique :: Feature -- | in eqp, triggered as often as Timeout permits Periodic :: Feature -- | override: the effects on this item are considered minor and so not -- causing identification on use, and so this item will identify on -- pick-up MinorEffects :: Feature -- | Map from an item kind identifier to the mean aspect value for the -- kind. -- -- Significant portions of this map are unused and so intentially kept -- unevaluated. data ItemSpeedup emptyItemSpeedup :: ItemSpeedup getKindMean :: ContentId ItemKind -> ItemSpeedup -> KindMean speedupItem :: ContentData ItemKind -> ItemSpeedup boostItemKindList :: StdGen -> [ItemKind] -> [ItemKind] -- | Whether the effect has a chance of exhibiting any potentially -- noticeable behaviour, except when the item is destroyed. We assume at -- least one of OneOf effects must be noticeable. forApplyEffect :: Effect -> Bool onlyMinorEffects :: ItemKind -> Bool filterRecharging :: [Effect] -> [Effect] stripRecharging :: [Effect] -> [Effect] stripOnSmash :: [Effect] -> [Effect] strengthOnSmash :: ItemKind -> [Effect] getDropOrgans :: ItemKind -> [GroupName ItemKind] getToThrow :: ItemKind -> ThrowMod getHideAs :: ItemKind -> Maybe (GroupName ItemKind) getEqpSlot :: ItemKind -> Maybe EqpSlot isEffEscape :: Effect -> Bool isEffAscend :: Effect -> Bool isEffEscapeOrAscend :: Effect -> Bool isMelee :: ItemKind -> Bool isTmpCondition :: ItemKind -> Bool isBlast :: ItemKind -> Bool isHumanTrinket :: ItemKind -> Bool goesIntoEqp :: ItemKind -> Bool goesIntoInv :: ItemKind -> Bool goesIntoSha :: ItemKind -> Bool itemTrajectory :: ItemKind -> [Point] -> ([Vector], (Speed, Int)) totalRange :: ItemKind -> Int damageUsefulness :: ItemKind -> Double tmpNoLonger :: Text -> Effect tmpLess :: Text -> Effect toVelocity :: Int -> Feature toLinger :: Int -> Feature timerNone :: TimerDice isTimerNone :: TimerDice -> Bool foldTimer :: a -> (Dice -> a) -> (Dice -> a) -> TimerDice -> a toOrganBad :: GroupName ItemKind -> Dice -> Effect toOrganGood :: GroupName ItemKind -> Dice -> Effect toOrganNoTimer :: GroupName ItemKind -> Effect meanAspect :: ItemKind -> AspectRecord boostItemKind :: ItemKind -> ItemKind majorEffect :: Effect -> Bool -- | Catch invalid item kind definitions. validateSingle :: ItemKind -> [Text] -- | Validate all item kinds. validateAll :: [ItemKind] -> ContentData ItemKind -> [Text] validateDups :: ItemKind -> Feature -> [Text] validateDamage :: Dice -> [Text] hardwiredItemGroups :: [GroupName ItemKind] instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.ItemSpeedup instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.ItemSpeedup instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.ItemSpeedup instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.Effect instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.Effect instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.Effect instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.ItemKind instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.ItemKind instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.Feature instance GHC.Classes.Ord Game.LambdaHack.Content.ItemKind.Feature instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.Feature instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.Feature instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.ThrowMod instance GHC.Classes.Ord Game.LambdaHack.Content.ItemKind.ThrowMod instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.ThrowMod instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.ThrowMod instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.TimerDice instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.TimerDice instance GHC.Generics.Generic Game.LambdaHack.Content.ItemKind.DetectKind instance GHC.Classes.Eq Game.LambdaHack.Content.ItemKind.DetectKind instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.DetectKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.ItemKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.Effect instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.Feature instance Data.Binary.Class.Binary Game.LambdaHack.Content.ItemKind.Effect instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.ThrowMod instance Data.Binary.Class.Binary Game.LambdaHack.Content.ItemKind.ThrowMod instance GHC.Show.Show Game.LambdaHack.Content.ItemKind.TimerDice instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.TimerDice instance Data.Binary.Class.Binary Game.LambdaHack.Content.ItemKind.TimerDice instance Control.DeepSeq.NFData Game.LambdaHack.Content.ItemKind.DetectKind instance Data.Binary.Class.Binary Game.LambdaHack.Content.ItemKind.DetectKind -- | 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. -- -- In principle, it'se possible to have many rule sets and switch between -- them during a game session or even a single game. data RuleKind RuleKind :: Char -> Text -> Freqs RuleKind -> Text -> FilePath -> Version -> FilePath -> String -> Text -> [String] -> Bool -> Int -> Int -> FilePath -> Int -> RuleKind -- | a symbol [rsymbol] :: RuleKind -> Char -- | short description [rname] :: RuleKind -> Text -- | frequency within groups [rfreq] :: RuleKind -> Freqs RuleKind -- | title of the game (not lib) [rtitle] :: RuleKind -> Text -- | font directory for the game (not lib) [rfontDir] :: RuleKind -> FilePath -- | version of the game [rexeVersion] :: RuleKind -> Version -- | name of the UI config file [rcfgUIName] :: RuleKind -> FilePath -- | the default UI settings config file [rcfgUIDefault] :: RuleKind -> String -- | the ASCII art for the main menu [rmainMenuArt] :: RuleKind -> Text -- | the intro screen (first help screen) text [rintroScreen] :: RuleKind -> [String] -- | whether first non-spawner actor death ends the game [rfirstDeathEnds] :: RuleKind -> Bool -- | game is saved that often (not on browser) [rwriteSaveClips] :: RuleKind -> Int -- | server switches leader level that often [rleadLevelClips] :: RuleKind -> Int -- | name of the scores file [rscoresFile] :: RuleKind -> FilePath -- | what distance between actors is nearby [rnearby] :: RuleKind -> Int makeData :: [RuleKind] -> ContentData RuleKind -- | Catch invalid rule kind definitions. validateSingle :: RuleKind -> [Text] -- | Since we have only one rule kind, the set of rule kinds is always -- valid. validateAll :: [RuleKind] -> ContentData RuleKind -> [Text] instance GHC.Generics.Generic Game.LambdaHack.Content.RuleKind.RuleKind instance GHC.Show.Show Game.LambdaHack.Content.RuleKind.RuleKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.RuleKind.RuleKind -- | 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. Note that tile -- names (and any other content names) should not be plural (that would -- lead to "a stairs"), so "road with cobblestones" is fine, but "granite -- cobblestones" is wrong. -- -- Tile kind for unknown space has the minimal ContentId index. -- The talter for unknown space is 1 and no other tile -- kind has that value. data TileKind TileKind :: Char -> Text -> Freqs TileKind -> Color -> Color -> Word8 -> [Feature] -> TileKind -- | map symbol [tsymbol] :: TileKind -> Char -- | short description [tname] :: TileKind -> Text -- | frequency within groups [tfreq] :: TileKind -> Freqs TileKind -- | map color [tcolor] :: TileKind -> Color -- | map color when not in FOV [tcolor2] :: TileKind -> Color -- | minimal skill needed to alter the tile [talter] :: TileKind -> Word8 -- | properties [tfeature] :: TileKind -> [Feature] makeData :: ContentData ItemKind -> [TileKind] -> ContentData TileKind -- | All possible terrain tile features. data Feature -- | initially an item of this group is embedded; we assume the item has -- effects and is supposed to be triggered Embed :: (GroupName ItemKind) -> Feature -- | goes from a closed to (randomly closed or) open tile when altered OpenTo :: (GroupName TileKind) -> Feature -- | goes from an open to (randomly opened or) closed tile when altered CloseTo :: (GroupName TileKind) -> Feature -- | alters tile, but does not change walkability ChangeTo :: (GroupName TileKind) -> Feature -- | when hidden, looks as the unique tile of the group HideAs :: (GroupName TileKind) -> Feature -- | when generating, may be transformed to the unique tile of the group BuildAs :: (GroupName TileKind) -> Feature -- | when generating in opening, can be revealed to belong to the group RevealAs :: (GroupName TileKind) -> Feature -- | when generating in solid wall, can be revealed to belong to the group ObscureAs :: (GroupName TileKind) -> Feature -- | actors can walk through Walkable :: Feature -- | actors can see through Clear :: Feature -- | is not lit with an ambient light Dark :: Feature -- | initial items often generated there OftenItem :: Feature -- | initial actors often generated there OftenActor :: Feature -- | no items ever generated there NoItem :: Feature -- | no actors ever generated there NoActor :: Feature -- | even if otherwise uninteresting, taken into account for triggering by -- AI ConsideredByAI :: Feature -- | used for visible trails throughout the level Trail :: Feature -- | in place normal legend and in override, don't roll a tile kind only -- once per place, but roll for each position; one non-spicy and at most -- one spicy is rolled per place and then one of the two is rolled for -- each position Spice :: Feature -- | A lot of tabulated maps from tile kind identifier to a property of the -- tile kind. data TileSpeedup TileSpeedup :: Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Bool -> Tab Word8 -> Tab Word8 -> TileSpeedup [isClearTab] :: TileSpeedup -> Tab Bool [isLitTab] :: TileSpeedup -> Tab Bool [isWalkableTab] :: TileSpeedup -> Tab Bool [isDoorTab] :: TileSpeedup -> Tab Bool [isChangableTab] :: TileSpeedup -> Tab Bool [isSuspectTab] :: TileSpeedup -> Tab Bool [isHideAsTab] :: TileSpeedup -> Tab Bool [consideredByAITab] :: TileSpeedup -> Tab Bool [isOftenItemTab] :: TileSpeedup -> Tab Bool [isOftenActorTab] :: TileSpeedup -> Tab Bool [isNoItemTab] :: TileSpeedup -> Tab Bool [isNoActorTab] :: TileSpeedup -> Tab Bool [isEasyOpenTab] :: TileSpeedup -> Tab Bool [alterMinSkillTab] :: TileSpeedup -> Tab Word8 [alterMinWalkTab] :: TileSpeedup -> Tab Word8 -- | A map morally indexed by ContentId TileKind. newtype Tab a Tab :: (Vector a) -> Tab a emptyTileSpeedup :: TileSpeedup emptyTab :: Unbox a => Tab a -- | Features of tiles that differentiate them substantially from one -- another. The intention is the player can easily tell such tiles apart -- by their behaviour and only looking at the map, not tile name nor -- description. So if running uses this function, it won't stop at places -- that the player can't himself tell from other places, and so running -- does not confer any advantages, except UI convenience. Hashes are -- accurate enough for our purpose, given that we use arbitrary -- heuristics anyway. actionFeatures :: Bool -> TileKind -> IntSet isUknownSpace :: ContentId TileKind -> Bool unknownId :: ContentId TileKind isSuspectKind :: TileKind -> Bool isOpenableKind :: TileKind -> Bool isClosableKind :: TileKind -> Bool talterForStairs :: Word8 floorSymbol :: Char -- | Validate a single tile kind. validateSingle :: TileKind -> [Text] -- | Validate all tile kinds. -- -- We don't check it any more, but if tiles look the same on the map -- (symbol and color), their substantial features should be the same, -- too, unless there is a good reason they shouldn't. Otherwise the -- player has to inspect manually all the tiles with this look to see if -- any is special. This tends to be tedious. Note that tiles may freely -- differ wrt text blurb, dungeon generation rules, AI preferences, etc., -- whithout causing the tedium. validateAll :: ContentData ItemKind -> [TileKind] -> ContentData TileKind -> [Text] validateDups :: TileKind -> Feature -> [Text] hardwiredTileGroups :: [GroupName TileKind] instance GHC.Generics.Generic Game.LambdaHack.Content.TileKind.TileSpeedup instance GHC.Generics.Generic (Game.LambdaHack.Content.TileKind.Tab a) instance GHC.Generics.Generic Game.LambdaHack.Content.TileKind.TileKind instance GHC.Show.Show Game.LambdaHack.Content.TileKind.TileKind instance GHC.Generics.Generic Game.LambdaHack.Content.TileKind.Feature instance GHC.Classes.Ord Game.LambdaHack.Content.TileKind.Feature instance GHC.Classes.Eq Game.LambdaHack.Content.TileKind.Feature instance GHC.Show.Show Game.LambdaHack.Content.TileKind.Feature instance Control.DeepSeq.NFData Game.LambdaHack.Content.TileKind.TileSpeedup instance Control.DeepSeq.NFData (Game.LambdaHack.Content.TileKind.Tab a) instance Control.DeepSeq.NFData Game.LambdaHack.Content.TileKind.TileKind instance Data.Binary.Class.Binary Game.LambdaHack.Content.TileKind.Feature instance Data.Hashable.Class.Hashable Game.LambdaHack.Content.TileKind.Feature instance Control.DeepSeq.NFData Game.LambdaHack.Content.TileKind.Feature -- | 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 PlaceKind -> Rarity -> Cover -> Fence -> [Text] -> [(Char, GroupName TileKind)] -> PlaceKind -- | a symbol [psymbol] :: PlaceKind -> Char -- | short description [pname] :: PlaceKind -> Text -- | frequency within groups [pfreq] :: PlaceKind -> Freqs PlaceKind -- | rarity on given depths [prarity] :: PlaceKind -> Rarity -- | how to fill whole place based on the corner [pcover] :: PlaceKind -> Cover -- | whether to fence place with solid border [pfence] :: PlaceKind -> Fence -- | plan of the top-left corner of the place [ptopLeft] :: PlaceKind -> [Text] -- | legend override [poverride] :: PlaceKind -> [(Char, GroupName TileKind)] makeData :: ContentData TileKind -> [PlaceKind] -> ContentData PlaceKind -- | A method of filling the whole area (except for CVerbatim and CMirror, -- which are just placed in the middle of the 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 -- | just build the given interior, without filling the area CVerbatim :: Cover -- | build the given interior in one of 4 mirrored variants CMirror :: 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 space, like the rooms floor FFloor :: Fence -- | leave an empty space, like the caves ground FGround :: Fence -- | skip the fence and fill all with the place proper FNone :: Fence -- | Catch invalid place kind definitions. In particular, verify that the -- top-left corner map is rectangular and not empty. validateSingle :: PlaceKind -> [Text] -- | Validate all place kinds. validateAll :: ContentData TileKind -> [PlaceKind] -> ContentData PlaceKind -> [Text] instance GHC.Generics.Generic Game.LambdaHack.Content.PlaceKind.PlaceKind instance GHC.Show.Show Game.LambdaHack.Content.PlaceKind.PlaceKind instance GHC.Generics.Generic Game.LambdaHack.Content.PlaceKind.Fence instance GHC.Classes.Eq Game.LambdaHack.Content.PlaceKind.Fence instance GHC.Show.Show Game.LambdaHack.Content.PlaceKind.Fence instance GHC.Generics.Generic Game.LambdaHack.Content.PlaceKind.Cover instance GHC.Classes.Eq Game.LambdaHack.Content.PlaceKind.Cover instance GHC.Show.Show Game.LambdaHack.Content.PlaceKind.Cover instance Control.DeepSeq.NFData Game.LambdaHack.Content.PlaceKind.PlaceKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.PlaceKind.Fence instance Control.DeepSeq.NFData Game.LambdaHack.Content.PlaceKind.Cover -- | The type of cave kinds. module Game.LambdaHack.Content.CaveKind -- | Parameters for the generation of dungeon levels. Warning: for -- efficiency, avoid embedded items in any of the common tiles. data CaveKind CaveKind :: Char -> Text -> Freqs CaveKind -> X -> Y -> DiceXY -> DiceXY -> DiceXY -> Dice -> Dice -> Rational -> Rational -> Int -> Dice -> Chance -> Chance -> Int -> Int -> Freqs ItemKind -> Dice -> Freqs ItemKind -> Freqs PlaceKind -> Bool -> GroupName TileKind -> GroupName TileKind -> GroupName TileKind -> GroupName TileKind -> GroupName TileKind -> GroupName TileKind -> GroupName TileKind -> Maybe (GroupName PlaceKind) -> Freqs PlaceKind -> Text -> CaveKind -- | a symbol [csymbol] :: CaveKind -> Char -- | short description [cname] :: CaveKind -> Text -- | frequency within groups [cfreq] :: CaveKind -> Freqs CaveKind -- | 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 -> DiceXY -- | minimal size of places; for merging [cminPlaceSize] :: CaveKind -> DiceXY -- | maximal size of places [cmaxPlaceSize] :: CaveKind -> DiceXY -- | the chance a place is dark [cdarkChance] :: CaveKind -> Dice -- | the chance the cave is dark [cnightChance] :: CaveKind -> Dice -- | a proportion of extra connections [cauxConnects] :: CaveKind -> Rational -- | at most this proportion of rooms may be void [cmaxVoid] :: CaveKind -> Rational -- | minimal distance between stairs [cminStairDist] :: CaveKind -> Int -- | extra stairs on top of from above [cextraStairs] :: CaveKind -> Dice -- | 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 lower, the more monsters spawn [cactorCoeff] :: CaveKind -> Int -- | actor groups to consider [cactorFreq] :: CaveKind -> Freqs ItemKind -- | number of initial items in the cave [citemNum] :: CaveKind -> Dice -- | item groups to consider [citemFreq] :: CaveKind -> Freqs ItemKind -- | place groups to consider [cplaceFreq] :: CaveKind -> Freqs PlaceKind -- | are passable default tiles permitted [cpassable] :: CaveKind -> Bool -- | the default cave tile [cdefTile] :: CaveKind -> GroupName TileKind -- | the dark cave corridor tile [cdarkCorTile] :: CaveKind -> GroupName TileKind -- | the lit cave corridor tile [clitCorTile] :: CaveKind -> GroupName TileKind -- | the filler wall [cfillerTile] :: CaveKind -> GroupName TileKind -- | the outer fence wall [couterFenceTile] :: CaveKind -> GroupName TileKind -- | the dark place plan legend [clegendDarkTile] :: CaveKind -> GroupName TileKind -- | the lit place plan legend [clegendLitTile] :: CaveKind -> GroupName TileKind -- | escape, if any [cescapeGroup] :: CaveKind -> Maybe (GroupName PlaceKind) -- | place groups to consider for stairs; in this case the rarity of items -- in the group does not affect group choice [cstairFreq] :: CaveKind -> Freqs PlaceKind -- | full cave description [cdesc] :: CaveKind -> Text makeData :: ContentData ItemKind -> ContentData PlaceKind -> ContentData TileKind -> [CaveKind] -> ContentData CaveKind -- | Catch caves with not enough space for all the places. Check the size -- of the cave descriptions to make sure they fit on screen. Etc. validateSingle :: CaveKind -> [Text] -- | Validate all cave kinds. Note that names don't have to be unique: we -- can have several variants of a cave with a given name. validateAll :: ContentData ItemKind -> ContentData PlaceKind -> ContentData TileKind -> [CaveKind] -> ContentData CaveKind -> [Text] instance GHC.Generics.Generic Game.LambdaHack.Content.CaveKind.CaveKind instance GHC.Show.Show Game.LambdaHack.Content.CaveKind.CaveKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.CaveKind.CaveKind -- | The type of kinds of game modes. module Game.LambdaHack.Content.ModeKind -- | Game mode specification. data ModeKind ModeKind :: Char -> Text -> Freqs ModeKind -> Roster -> Caves -> Text -> ModeKind -- | a symbol [msymbol] :: ModeKind -> Char -- | short description [mname] :: ModeKind -> Text -- | frequency within groups [mfreq] :: ModeKind -> Freqs ModeKind -- | players taking part in the game [mroster] :: ModeKind -> Roster -- | arena of the game [mcaves] :: ModeKind -> Caves -- | description [mdesc] :: ModeKind -> Text makeData :: ContentData CaveKind -> ContentData ItemKind -> [ModeKind] -> ContentData ModeKind -- | Requested cave groups for particular levels. The second component is -- the Escape feature on the level. True means it's -- represented by <, False, by >. type Caves = IntMap (GroupName CaveKind) -- | The specification of players for the game mode. data Roster Roster :: [(Player, [(Int, Dice, GroupName ItemKind)])] -> [(Text, Text)] -> [(Text, Text)] -> Roster -- | players in the particular team and levels, numbers and groups of their -- initial members [rosterList] :: Roster -> [(Player, [(Int, Dice, GroupName ItemKind)])] -- | the initial enmity matrix [rosterEnemy] :: Roster -> [(Text, Text)] -- | the initial aliance matrix [rosterAlly] :: Roster -> [(Text, Text)] -- | 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 -- | Conditional polynomial representing score calculation for this player. type HiCondPoly = [HiSummand] type HiSummand = (HiPolynomial, [Outcome]) type HiPolynomial = [(HiIndeterminant, Double)] data HiIndeterminant HiConst :: HiIndeterminant HiLoot :: HiIndeterminant HiBlitz :: HiIndeterminant HiSurvival :: HiIndeterminant HiKill :: HiIndeterminant HiLoss :: HiIndeterminant -- | Properties of a particular player. data Player Player :: Text -> [GroupName ItemKind] -> Skills -> Bool -> Bool -> HiCondPoly -> Bool -> Tactic -> LeaderMode -> Bool -> Player -- | name of the player [fname] :: Player -> Text -- | names of actor groups that may naturally fall under player's control, -- e.g., upon spawning or summoning [fgroups] :: Player -> [GroupName ItemKind] -- | fixed skill modifiers to the non-leader actors; also summed with -- skills implied by ftactic (which is not fixed) [fskillsOther] :: Player -> Skills -- | the player can escape the dungeon [fcanEscape] :: Player -> Bool -- | the faction declared killed if no actors [fneverEmpty] :: Player -> Bool -- | score polynomial for the player [fhiCondPoly] :: Player -> HiCondPoly -- | whether actors have gender [fhasGender] :: Player -> Bool -- | non-leaders behave according to this tactic; can be changed during the -- game [ftactic] :: Player -> Tactic -- | the mode of switching the leader [fleaderMode] :: Player -> LeaderMode -- | does the faction have a UI client (for control or passive observation) [fhasUI] :: Player -> Bool -- | If a faction with LeaderUI and LeaderAI has any -- actor, it has a leader. data LeaderMode -- | faction can have no leader, is whole under AI control LeaderNull :: LeaderMode -- | leader under AI control LeaderAI :: AutoLeader -> LeaderMode -- | leader under UI control, assumes fhasUI LeaderUI :: AutoLeader -> LeaderMode data AutoLeader AutoLeader :: Bool -> Bool -> AutoLeader -- | leader switching between levels is automatically done by the server -- and client is not permitted to change to leaders from other levels -- (the frequency of leader level switching done by the server is -- controlled by RuleKind.rleadLevelClips); if the flag is -- False, server still does a subset of the automatic switching, -- e.g., when the old leader dies and no other actor of the faction -- resides on his level, but the client (particularly UI) is expected to -- do changes as well [autoDungeon] :: AutoLeader -> Bool -- | client is discouraged from leader switching (e.g., because non-leader -- actors have the same skills as leader); server is guaranteed to switch -- leader within a level very rarely, e.g., when the old leader dies; if -- the flag is False, server still does a subset of the -- automatic switching, but the client is expected to do more, because -- it's advantageous for that kind of a faction [autoLevel] :: AutoLeader -> Bool nameOfHorrorFact :: GroupName ItemKind -- | Catch invalid game mode kind definitions. validateSingle :: ModeKind -> [Text] -- | Validate game mode kinds together. validateAll :: ContentData CaveKind -> ContentData ItemKind -> [ModeKind] -> ContentData ModeKind -> [Text] -- | Checks, in particular, that there is at least one faction with -- fneverEmpty or the game would get stuck as soon as the dungeon is -- devoid of actors. validateSingleRoster :: Caves -> Roster -> [Text] validateSinglePlayer :: Player -> [Text] hardwiredModeGroups :: [GroupName ModeKind] instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.ModeKind instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.ModeKind instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.Roster instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.Roster instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.Player instance GHC.Classes.Eq Game.LambdaHack.Content.ModeKind.Player instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.Player instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.LeaderMode instance GHC.Classes.Ord Game.LambdaHack.Content.ModeKind.LeaderMode instance GHC.Classes.Eq Game.LambdaHack.Content.ModeKind.LeaderMode instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.LeaderMode instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.AutoLeader instance GHC.Classes.Ord Game.LambdaHack.Content.ModeKind.AutoLeader instance GHC.Classes.Eq Game.LambdaHack.Content.ModeKind.AutoLeader instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.AutoLeader instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.HiIndeterminant instance GHC.Classes.Ord Game.LambdaHack.Content.ModeKind.HiIndeterminant instance GHC.Classes.Eq Game.LambdaHack.Content.ModeKind.HiIndeterminant instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.HiIndeterminant instance GHC.Generics.Generic Game.LambdaHack.Content.ModeKind.Outcome instance GHC.Enum.Bounded Game.LambdaHack.Content.ModeKind.Outcome instance GHC.Enum.Enum Game.LambdaHack.Content.ModeKind.Outcome instance GHC.Classes.Ord Game.LambdaHack.Content.ModeKind.Outcome instance GHC.Classes.Eq Game.LambdaHack.Content.ModeKind.Outcome instance GHC.Show.Show Game.LambdaHack.Content.ModeKind.Outcome instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.ModeKind instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.Roster instance Data.Binary.Class.Binary Game.LambdaHack.Content.ModeKind.Player instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.Player instance Data.Binary.Class.Binary Game.LambdaHack.Content.ModeKind.LeaderMode instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.LeaderMode instance Data.Binary.Class.Binary Game.LambdaHack.Content.ModeKind.AutoLeader instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.AutoLeader instance Data.Binary.Class.Binary Game.LambdaHack.Content.ModeKind.HiIndeterminant instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.HiIndeterminant instance Data.Binary.Class.Binary Game.LambdaHack.Content.ModeKind.Outcome instance Control.DeepSeq.NFData Game.LambdaHack.Content.ModeKind.Outcome -- | 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 speedupTile :: Bool -> ContentData TileKind -> TileSpeedup -- | Whether a tile does not block vision. Essential for efficiency of -- FOV, hence tabulated. isClear :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether a tile has ambient light --- is lit on its own. Essential for -- efficiency of Perception, hence tabulated. isLit :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether actors can walk into a tile. Essential for efficiency of -- pathfinding, hence tabulated. isWalkable :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether a tile is a door, open or closed. Essential for efficiency of -- pathfinding, hence tabulated. isDoor :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether a tile is changable. isChangable :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether a tile is suspect. Essential for efficiency of pathfinding, -- hence tabulated. isSuspect :: TileSpeedup -> ContentId TileKind -> Bool isHideAs :: TileSpeedup -> ContentId TileKind -> Bool consideredByAI :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether one can easily explore a tile, possibly finding a treasure, -- either spawned there or dropped there by a (dying from poison) foe. -- Doors can't be explorable since revealing a secret tile should not -- change it's (walkable and) explorable status. Door status should not -- depend on whether they are open or not so that a foe opening a door -- doesn't force us to backtrack to explore it. Still, a foe that digs -- through a wall will affect our exploration counter and if content lets -- walls contain threasure, such backtraking makes sense. isExplorable :: TileSpeedup -> ContentId TileKind -> Bool isOftenItem :: TileSpeedup -> ContentId TileKind -> Bool isOftenActor :: TileSpeedup -> ContentId TileKind -> Bool isNoItem :: TileSpeedup -> ContentId TileKind -> Bool isNoActor :: TileSpeedup -> ContentId TileKind -> Bool -- | Whether a tile kind (specified by its id) has an OpenTo feature and -- reasonable alter min skill. isEasyOpen :: TileSpeedup -> ContentId TileKind -> Bool alterMinSkill :: TileSpeedup -> ContentId TileKind -> Int alterMinWalk :: TileSpeedup -> ContentId TileKind -> Int -- | Whether a tile kind has the given feature. kindHasFeature :: Feature -> TileKind -> Bool -- | Whether a tile kind (specified by its id) has the given feature. hasFeature :: ContentData TileKind -> Feature -> ContentId TileKind -> Bool openTo :: ContentData TileKind -> ContentId TileKind -> Rnd (ContentId TileKind) closeTo :: ContentData TileKind -> ContentId TileKind -> Rnd (ContentId TileKind) embeddedItems :: ContentData TileKind -> ContentId TileKind -> [GroupName ItemKind] revealAs :: ContentData TileKind -> ContentId TileKind -> Rnd (ContentId TileKind) obscureAs :: ContentData TileKind -> ContentId TileKind -> Rnd (ContentId TileKind) hideAs :: ContentData TileKind -> ContentId TileKind -> Maybe (ContentId TileKind) buildAs :: ContentData TileKind -> ContentId TileKind -> ContentId TileKind isEasyOpenKind :: TileKind -> Bool -- | Whether a tile kind (specified by its id) has an OpenTo feature. isOpenable :: ContentData TileKind -> ContentId TileKind -> Bool -- | Whether a tile kind (specified by its id) has a CloseTo feature. isClosable :: ContentData TileKind -> ContentId TileKind -> Bool createTab :: Unbox a => ContentData TileKind -> (TileKind -> a) -> Tab a createTabWithKey :: Unbox a => ContentData TileKind -> (ContentId TileKind -> TileKind -> a) -> Tab a accessTab :: Unbox a => Tab a -> ContentId TileKind -> a alterMinSkillKind :: ContentId TileKind -> TileKind -> Word8 alterMinWalkKind :: ContentId TileKind -> TileKind -> Word8 -- | General content types and operations. module Game.LambdaHack.Common.Kind -- | Content identifiers for the content type c. data ContentId c -- | Verified and preprocessed content data of a particular kind. data ContentData c -- | Operations for all content types, gathered together. data COps COps :: ContentData CaveKind -> ContentData ItemKind -> ContentData ModeKind -> ContentData PlaceKind -> ContentData RuleKind -> ContentData TileKind -> ItemSpeedup -> TileSpeedup -> COps [cocave] :: COps -> ContentData CaveKind [coitem] :: COps -> ContentData ItemKind [comode] :: COps -> ContentData ModeKind [coplace] :: COps -> ContentData PlaceKind [corule] :: COps -> ContentData RuleKind [cotile] :: COps -> ContentData TileKind [coItemSpeedup] :: COps -> ItemSpeedup [coTileSpeedup] :: COps -> TileSpeedup emptyCOps :: COps -- | The standard ruleset used for level operations. getStdRuleset :: COps -> RuleKind -- | Content element at given id. okind :: ContentData a -> ContentId a -> a -- | The id of the unique member of a singleton content group. ouniqGroup :: Show a => ContentData a -> GroupName a -> ContentId a -- | Pick a random id belonging to a group and satisfying a predicate. opick :: Show a => ContentData a -> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a)) -- | Fold over all content elements of a. ofoldrWithKey :: ContentData a -> (ContentId a -> a -> b -> b) -> b -> b -- | Fold strictly over all content a. ofoldlWithKey' :: ContentData a -> (b -> ContentId a -> a -> b) -> b -> b -- | Fold over the given group only. ofoldlGroup' :: ContentData a -> GroupName a -> (b -> Int -> ContentId a -> a -> b) -> b -> b omapVector :: ContentData a -> (a -> b) -> Vector b oimapVector :: ContentData a -> (ContentId a -> a -> b) -> Vector b -- | Size of content a. olength :: ContentData a -> Int instance GHC.Generics.Generic Game.LambdaHack.Common.Kind.COps instance GHC.Show.Show Game.LambdaHack.Common.Kind.COps instance GHC.Classes.Eq Game.LambdaHack.Common.Kind.COps -- | Weapons, treasure and all the other items in the game. module Game.LambdaHack.Common.Item -- | A unique identifier of an item in the dungeon. data ItemId -- | Game items in actor possesion or strewn around the dungeon. The -- information contained in this time is available to the player from the -- moment the item is first seen and is never mutated. -- -- Some items are not created identified (IdentityCovered). Then -- they are presented as having a template kind that is really not their -- own, though usually close. Full kind information about item's kind is -- available through the ItemKindIx index once the item is -- identified and full information about the value of item's aspects is -- available elsewhere (both IdentityObvious and -- IdentityCovered items may or may not need identification of -- their aspects). data Item Item :: ItemIdentity -> LevelId -> Maybe FactionId -> Flavour -> Item -- | the kind of the item, or an indiretion [jkind] :: Item -> ItemIdentity -- | lowest level the item was created at [jlid] :: Item -> LevelId -- | the faction that created the item, if any [jfid] :: Item -> Maybe FactionId -- | flavour, always the real one, not hidden; people may not recognize -- shape, but they remember colour and old vs fancy look [jflavour] :: Item -> Flavour -- | Either the explicit obvious kind of the item or the kind it's hidden -- under, with the details covered under the index indirection. data ItemIdentity IdentityObvious :: (ContentId ItemKind) -> ItemIdentity IdentityCovered :: ItemKindIx -> (ContentId ItemKind) -> ItemIdentity -- | An index of the kind identifier of an item. Clients have partial -- knowledge how these idexes map to kind ids. They gain knowledge by -- identifying items. The indexes and kind identifiers are 1-1. data ItemKindIx -- | The secret part of the information about an item. If a faction knows -- the aspects of the item (the kmConst flag is set or the -- itemAspect field is Left), this is a complete secret -- information. Items that don't need second identification may be -- identified or not and both cases are OK (their display flavour will -- differ and that may be the point). -- -- The itemAspect accessor it to be used unconditionally only on -- the server where it's guaranteed to be safe. data ItemDisco ItemDiscoMean :: KindMean -> ItemDisco ItemDiscoFull :: AspectRecord -> ItemDisco [itemAspect] :: ItemDisco -> AspectRecord -- | Full information about an item. data ItemFull ItemFull :: Item -> ContentId ItemKind -> ItemKind -> ItemDisco -> Bool -> ItemFull [itemBase] :: ItemFull -> Item [itemKindId] :: ItemFull -> ContentId ItemKind [itemKind] :: ItemFull -> ItemKind [itemDisco] :: ItemFull -> ItemDisco [itemSuspect] :: ItemFull -> Bool type ItemFullKit = (ItemFull, ItemQuant) -- | The map of item kind indexes to item kind ids. The full map, as known -- by the server, is 1-1. Because it's sparse and changes, we don't -- represent it as an (unboxed) vector, until it becomes a bottleneck (if -- ever, likely on JS, where only vectors are fast). type DiscoveryKind = EnumMap ItemKindIx (ContentId ItemKind) -- | The map of item ids to item aspects. The full map is known by the -- server. type DiscoveryAspect = EnumMap ItemId AspectRecord -- | The map of item kind indexes to identifiers of items that have that -- kind. Used to update data about items when their kinds become known, -- e.g., AI item use benefit data. type ItemIxMap = EnumMap ItemKindIx (EnumSet ItemId) -- | Fields are intentionally kept non-strict, because they are recomputed -- often, but not used every time. The fields are, in order: 1. whether -- the item should be kept in equipment (not in pack nor stash) 2. the -- total benefit from picking the item up (to use or to put in equipment) -- 3. the benefit of applying the item to self 4. the (usually negative) -- benefit of hitting a foe in meleeing with the item 5. the (usually -- negative) benefit of flinging an item at an opponent data Benefit Benefit :: ~Bool -> ~Double -> ~Double -> ~Double -> ~Double -> Benefit [benInEqp] :: Benefit -> ~Bool [benPickup] :: Benefit -> ~Double [benApply] :: Benefit -> ~Double [benMelee] :: Benefit -> ~Double [benFling] :: Benefit -> ~Double type DiscoveryBenefit = EnumMap ItemId Benefit type ItemTimer = [Time] -- | Number of items in a bag, together with recharging timer, in case of -- items that need recharging, exists only temporarily or auto-activate -- at regular intervals. type ItemQuant = (Int, ItemTimer) -- | A bag of items, e.g., one of the stores of an actor or the items on a -- particular floor position or embedded in a particular map tile. type ItemBag = EnumMap ItemId ItemQuant -- | All items in the dungeon (including in actor inventories), indexed by -- item identifier. type ItemDict = EnumMap ItemId Item itemToFull6 :: COps -> DiscoveryKind -> DiscoveryAspect -> ItemId -> Item -> ItemFull aspectRecordFull :: ItemFull -> AspectRecord strongestSlot :: DiscoveryBenefit -> EqpSlot -> [(ItemId, ItemFullKit)] -> [(Int, (ItemId, ItemFullKit))] hasCharge :: Time -> ItemFull -> ItemQuant -> Bool strongestMelee :: Maybe DiscoveryBenefit -> Time -> [(ItemId, ItemFullKit)] -> [(Double, (ItemId, ItemFullKit))] unknownMeleeBonus :: [ItemFull] -> Bool tmpMeleeBonus :: [ItemFullKit] -> Int unknownAspect :: (Aspect -> [Dice]) -> ItemFull -> Bool instance GHC.Generics.Generic Game.LambdaHack.Common.Item.Benefit instance GHC.Show.Show Game.LambdaHack.Common.Item.Benefit instance GHC.Show.Show Game.LambdaHack.Common.Item.ItemFull instance GHC.Classes.Ord Game.LambdaHack.Common.Item.ItemDisco instance GHC.Classes.Eq Game.LambdaHack.Common.Item.ItemDisco instance GHC.Show.Show Game.LambdaHack.Common.Item.ItemDisco instance GHC.Generics.Generic Game.LambdaHack.Common.Item.Item instance GHC.Classes.Eq Game.LambdaHack.Common.Item.Item instance GHC.Show.Show Game.LambdaHack.Common.Item.Item instance GHC.Generics.Generic Game.LambdaHack.Common.Item.ItemIdentity instance GHC.Classes.Eq Game.LambdaHack.Common.Item.ItemIdentity instance GHC.Show.Show Game.LambdaHack.Common.Item.ItemIdentity instance Data.Binary.Class.Binary Game.LambdaHack.Common.Item.ItemKindIx instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Item.ItemKindIx instance GHC.Arr.Ix Game.LambdaHack.Common.Item.ItemKindIx instance GHC.Enum.Enum Game.LambdaHack.Common.Item.ItemKindIx instance GHC.Classes.Ord Game.LambdaHack.Common.Item.ItemKindIx instance GHC.Classes.Eq Game.LambdaHack.Common.Item.ItemKindIx instance GHC.Show.Show Game.LambdaHack.Common.Item.ItemKindIx instance Data.Binary.Class.Binary Game.LambdaHack.Common.Item.ItemId instance GHC.Enum.Enum Game.LambdaHack.Common.Item.ItemId instance GHC.Classes.Ord Game.LambdaHack.Common.Item.ItemId instance GHC.Classes.Eq Game.LambdaHack.Common.Item.ItemId instance GHC.Show.Show Game.LambdaHack.Common.Item.ItemId instance Data.Binary.Class.Binary Game.LambdaHack.Common.Item.Benefit instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Item.Item instance Data.Binary.Class.Binary Game.LambdaHack.Common.Item.Item instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.Item.ItemIdentity instance Data.Binary.Class.Binary Game.LambdaHack.Common.Item.ItemIdentity -- | Possible causes of failure of request. module Game.LambdaHack.Common.ReqFailure -- | Possible causes of failure of request. data ReqFailure MoveNothing :: ReqFailure MeleeSelf :: ReqFailure MeleeDistant :: ReqFailure DisplaceDistant :: ReqFailure DisplaceAccess :: ReqFailure DisplaceProjectiles :: ReqFailure DisplaceDying :: ReqFailure DisplaceBraced :: ReqFailure DisplaceImmobile :: ReqFailure DisplaceSupported :: ReqFailure AlterUnskilled :: ReqFailure AlterUnwalked :: ReqFailure AlterDistant :: ReqFailure AlterBlockActor :: ReqFailure AlterBlockItem :: ReqFailure AlterNothing :: ReqFailure EqpOverfull :: ReqFailure EqpStackFull :: ReqFailure ApplyUnskilled :: ReqFailure ApplyRead :: ReqFailure ApplyOutOfReach :: ReqFailure ApplyCharging :: ReqFailure ApplyNoEffects :: ReqFailure ItemNothing :: ReqFailure ItemNotCalm :: ReqFailure NotCalmPrecious :: ReqFailure ProjectUnskilled :: ReqFailure ProjectAimOnself :: ReqFailure ProjectBlockTerrain :: ReqFailure ProjectBlockActor :: ReqFailure ProjectLobable :: ReqFailure ProjectOutOfReach :: ReqFailure TriggerNothing :: ReqFailure NoChangeDunLeader :: ReqFailure impossibleReqFailure :: ReqFailure -> Bool showReqFailure :: ReqFailure -> Text permittedPrecious :: Bool -> Bool -> ItemFull -> Either ReqFailure Bool permittedProject :: Bool -> Int -> Bool -> ItemFull -> Either ReqFailure Bool permittedProjectAI :: Int -> Bool -> ItemFull -> Bool permittedApply :: Time -> Int -> Bool -> ItemFull -> ItemQuant -> Either ReqFailure Bool instance GHC.Generics.Generic Game.LambdaHack.Common.ReqFailure.ReqFailure instance GHC.Classes.Eq Game.LambdaHack.Common.ReqFailure.ReqFailure instance GHC.Show.Show Game.LambdaHack.Common.ReqFailure.ReqFailure instance Data.Binary.Class.Binary Game.LambdaHack.Common.ReqFailure.ReqFailure -- | Actors in the game: heroes, monsters, etc. module Game.LambdaHack.Common.Actor -- | A unique identifier of an actor in the dungeon. data ActorId -- | Actor properties that are changing throughout the game. If they appear -- dublets of properties of actor kinds, e.g. HP, they may be results of -- casting the dice specified in their respective actor kind and/or may -- be modified temporarily, but return to the original value from their -- respective kind over time. data Actor Actor :: ItemId -> Int64 -> ResDelta -> Int64 -> ResDelta -> Point -> Maybe Point -> LevelId -> FactionId -> Maybe ([Vector], Speed) -> ItemBag -> ItemBag -> ItemBag -> Int -> Bool -> Bool -> Actor -- | the trunk organ of the actor's body [btrunk] :: Actor -> ItemId -- | current hit points * 1M [bhp] :: Actor -> Int64 -- | HP delta this turn * 1M [bhpDelta] :: Actor -> ResDelta -- | current calm * 1M [bcalm] :: Actor -> Int64 -- | calm delta this turn * 1M [bcalmDelta] :: Actor -> ResDelta -- | current position [bpos] :: Actor -> Point -- | previous position, if any [boldpos] :: Actor -> Maybe Point -- | current level [blid] :: Actor -> LevelId -- | faction the actor currently belongs to [bfid] :: Actor -> FactionId -- | trajectory the actor must travel and his travel speed [btrajectory] :: Actor -> Maybe ([Vector], Speed) -- | organs [borgan] :: Actor -> ItemBag -- | personal equipment [beqp] :: Actor -> ItemBag -- | personal inventory pack [binv] :: Actor -> ItemBag -- | number of weapons among eqp and organs [bweapon] :: Actor -> Int -- | is the actor waiting right now? [bwait] :: Actor -> Bool -- | is a projectile? affects being able to fly through other projectiles, -- etc. [bproj] :: Actor -> Bool data ResDelta ResDelta :: (Int64, Int64) -> (Int64, Int64) -> ResDelta -- | resource change this player turn [resCurrentTurn] :: ResDelta -> (Int64, Int64) -- | resource change last player turn [resPreviousTurn] :: ResDelta -> (Int64, Int64) type ActorAspect = EnumMap ActorId AspectRecord deltaSerious :: ResDelta -> Bool deltaMild :: ResDelta -> Bool actorCanMelee :: ActorAspect -> ActorId -> Actor -> Bool -- | Current physical speed, whether from being pushed or from organs and -- gear. momentarySpeed :: Actor -> AspectRecord -> Speed -- | The speed from organs and gear; being pushed is ignored. gearSpeed :: AspectRecord -> Speed -- | Whether an actor is braced for combat this clip. braced :: Actor -> Bool actorTemplate :: ItemId -> Int64 -> Int64 -> Point -> LevelId -> FactionId -> Bool -> Actor waitedLastTurn :: Actor -> Bool actorDying :: Actor -> Bool hpTooLow :: Actor -> AspectRecord -> Bool calmEnough :: Actor -> AspectRecord -> Bool hpEnough :: Actor -> AspectRecord -> Bool checkAdjacent :: Actor -> Actor -> Bool eqpOverfull :: Actor -> Int -> Bool eqpFreeN :: Actor -> Int -- | All actors on the level, indexed by actor identifier. type ActorDict = EnumMap ActorId Actor -- | Chance that a new monster is generated. Depends on the number of -- monsters already present, and on the level depth and its cave kind. monsterGenChance :: AbsDepth -> AbsDepth -> Int -> Int -> Rnd Bool -- | How long until an actor's smell vanishes from a tile. smellTimeout :: Delta Time instance GHC.Generics.Generic Game.LambdaHack.Common.Actor.Actor instance GHC.Classes.Eq Game.LambdaHack.Common.Actor.Actor instance GHC.Show.Show Game.LambdaHack.Common.Actor.Actor instance GHC.Generics.Generic Game.LambdaHack.Common.Actor.ResDelta instance GHC.Classes.Eq Game.LambdaHack.Common.Actor.ResDelta instance GHC.Show.Show Game.LambdaHack.Common.Actor.ResDelta instance Data.Binary.Class.Binary Game.LambdaHack.Common.Actor.Actor instance Data.Binary.Class.Binary Game.LambdaHack.Common.Actor.ResDelta -- | 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 identifiers to levels. type Dungeon = EnumMap LevelId Level -- | Levels in the current branch, one level up (or down) from the current. ascendInBranch :: Dungeon -> Bool -> LevelId -> [LevelId] -- | Compute the level identifier and stair position on the new level, -- after a level change. -- -- We assume there is never a staircase up and down at the same position. whereTo :: LevelId -> Point -> Maybe Bool -> Dungeon -> (LevelId, Point) -- | Items located on map tiles. type ItemFloor = EnumMap Point ItemBag -- | Items located on map tiles. type ActorMap = EnumMap Point [ActorId] -- | Tile kinds on the map. type TileMap = Array (ContentId TileKind) -- | Current smell on map tiles. type SmellMap = EnumMap Point Time -- | A view on single, inhabited dungeon level. Remembered fields -- carry a subset of the info in the client copies of levels. data Level Level :: ContentId CaveKind -> AbsDepth -> ItemFloor -> ItemFloor -> ActorMap -> TileMap -> X -> Y -> SmellMap -> ([Point], [Point]) -> [Point] -> Int -> Int -> Time -> Bool -> Level -- | the kind of cave the level is an instance of [lkind] :: Level -> ContentId CaveKind -- | absolute depth of the level [ldepth] :: Level -> AbsDepth -- | remembered items lying on the floor [lfloor] :: Level -> ItemFloor -- | remembered items embedded in the tile [lembed] :: Level -> ItemFloor -- | seen actors at positions on the level; could be recomputed at resume, -- but small enough [lactor] :: Level -> ActorMap -- | 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 -- | positions of (up, down) stairs [lstair] :: Level -> ([Point], [Point]) -- | positions of IK.Escape tiles [lescape] :: Level -> [Point] -- | currently remembered clear tiles [lseen] :: Level -> Int -- | total number of explorable tiles [lexpl] :: Level -> Int -- | local time on the level (possibly frozen) [ltime] :: Level -> Time -- | whether the level is covered in darkness [lnight] :: Level -> Bool updateFloor :: (ItemFloor -> ItemFloor) -> Level -> Level updateEmbed :: (ItemFloor -> ItemFloor) -> Level -> Level updateActorMap :: (ActorMap -> ActorMap) -> Level -> Level updateTile :: (TileMap -> TileMap) -> Level -> Level updateSmell :: (SmellMap -> SmellMap) -> Level -> Level -- | Query for tile kinds on the map. at :: Level -> Point -> ContentId TileKind -- | Find a random position on the map satisfying a predicate. findPoint :: X -> Y -> (Point -> Maybe Point) -> Rnd Point -- | Find a random position on the map satisfying a predicate. findPos :: TileMap -> (Point -> ContentId TileKind -> Bool) -> Rnd Point -- | Try to find a random position on the map satisfying conjunction of the -- mandatory and an optional predicate. If the permitted number of -- attempts is not enough, try again the same number of times without the -- next optional predicate, and fall back to trying as many times, as -- needed, with only the mandatory predicate. findPosTry :: Int -> TileMap -> (Point -> ContentId TileKind -> Bool) -> [Point -> ContentId TileKind -> Bool] -> Rnd Point findPosTry2 :: Int -> TileMap -> (Point -> ContentId TileKind -> Bool) -> [Point -> ContentId TileKind -> Bool] -> (Point -> ContentId TileKind -> Bool) -> [Point -> ContentId TileKind -> Bool] -> Rnd Point assertSparseItems :: ItemFloor -> ItemFloor assertSparseActors :: ActorMap -> ActorMap instance GHC.Classes.Eq Game.LambdaHack.Common.Level.Level instance GHC.Show.Show Game.LambdaHack.Common.Level.Level instance Data.Binary.Class.Binary Game.LambdaHack.Common.Level.Level -- | Factions taking part in the game, e.g., a hero faction, a monster -- faction and an animal faction. 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 -- | The faction datatype. data Faction Faction :: Text -> Color -> Player -> [(Int, Int, GroupName ItemKind)] -> Dipl -> Maybe Status -> Maybe ActorId -> ItemBag -> EnumMap (ContentId ItemKind) Int -> EnumMap (ContentId ModeKind) (IntMap (EnumMap (ContentId ItemKind) Int)) -> Faction -- | individual name [gname] :: Faction -> Text -- | color of actors or their frames [gcolor] :: Faction -> Color -- | the player spec for this faction [gplayer] :: Faction -> Player -- | initial actors [ginitial] :: Faction -> [(Int, Int, GroupName ItemKind)] -- | diplomatic mode [gdipl] :: Faction -> Dipl -- | cause of game end/exit [gquit] :: Faction -> Maybe Status -- | the leader of the faction; don't use in place of sleader on clients [_gleader] :: Faction -> Maybe ActorId -- | faction's shared inventory [gsha] :: Faction -> ItemBag -- | members killed [gvictims] :: Faction -> EnumMap (ContentId ItemKind) Int -- | members killed in the past, by game mode and difficulty level [gvictimsD] :: Faction -> EnumMap (ContentId ModeKind) (IntMap (EnumMap (ContentId ItemKind) Int)) -- | Diplomacy states. Higher overwrite lower in case of asymmetric -- content. data Diplomacy Unknown :: Diplomacy Neutral :: Diplomacy Alliance :: Diplomacy War :: Diplomacy -- | Current game status. data Status Status :: Outcome -> Int -> Maybe (GroupName ModeKind) -> Status -- | current game outcome [stOutcome] :: Status -> Outcome -- | depth of the final encounter [stDepth] :: Status -> Int -- | new game group to start, if any [stNewGame] :: Status -> Maybe (GroupName ModeKind) -- | The type of na actor target. data Target -- | target an actor; cycle only trough seen foes, unless the flag is set TEnemy :: ActorId -> Bool -> Target -- | target a concrete spot TPoint :: TGoal -> LevelId -> Point -> Target -- | target position relative to actor TVector :: Vector -> Target -- | The goal of an actor. data TGoal -- | last seen position of the targeted actor TEnemyPos :: ActorId -> Bool -> TGoal -- | embedded item that can be triggered; in TPoint (TEmbed bag p) _ -- q usually bag is embbedded in p and q -- is an adjacent open tile TEmbed :: ItemBag -> Point -> TGoal -- | item lying on the ground TItem :: ItemBag -> TGoal -- | smell potentially left by enemies TSmell :: TGoal -- | an unknown tile to be explored TUnknown :: TGoal -- | a known tile to be patrolled TKnown :: TGoal -- | an unspecified goal TAny :: TGoal data Challenge Challenge :: Int -> Bool -> Bool -> Challenge -- | game difficulty level (HP bonus or malus) [cdiff] :: Challenge -> Int -- | lone wolf challenge (only one starting character) [cwolf] :: Challenge -> Bool -- | cold fish challenge (no healing from enemies) [cfish] :: Challenge -> Bool gleader :: Faction -> Maybe ActorId tgtKindDescription :: Target -> Text -- | Tell whether the faction consists of summoned horrors only. -- -- Horror player is special, for summoned actors that don't belong to any -- of the main players of a given game. E.g., animals summoned during a -- skirmish game between two hero factions land in the horror faction. In -- every game, either all factions for which summoning items exist should -- be present or a horror player should be added to host them. isHorrorFact :: Faction -> Bool noRunWithMulti :: Faction -> Bool isAIFact :: Faction -> Bool autoDungeonLevel :: Faction -> (Bool, Bool) automatePlayer :: Bool -> Player -> Player -- | Check if factions are at war. Assumes symmetry. isFoe :: FactionId -> Faction -> FactionId -> Bool -- | Check if factions are allied or are the same faction. Assumes -- symmetry. isFriend :: FactionId -> Faction -> FactionId -> Bool difficultyBound :: Int difficultyDefault :: Int difficultyCoeff :: Int -> Int difficultyInverse :: Int -> Int defaultChallenge :: Challenge type Dipl = EnumMap FactionId Diplomacy instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.Challenge instance GHC.Classes.Ord Game.LambdaHack.Common.Faction.Challenge instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.Challenge instance GHC.Show.Show Game.LambdaHack.Common.Faction.Challenge instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.Target instance GHC.Classes.Ord Game.LambdaHack.Common.Faction.Target instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.Target instance GHC.Show.Show Game.LambdaHack.Common.Faction.Target instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.TGoal instance GHC.Classes.Ord Game.LambdaHack.Common.Faction.TGoal instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.TGoal instance GHC.Show.Show Game.LambdaHack.Common.Faction.TGoal instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.Faction instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.Faction instance GHC.Show.Show Game.LambdaHack.Common.Faction.Faction instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.Status instance GHC.Classes.Ord Game.LambdaHack.Common.Faction.Status instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.Status instance GHC.Show.Show Game.LambdaHack.Common.Faction.Status instance GHC.Generics.Generic Game.LambdaHack.Common.Faction.Diplomacy instance GHC.Enum.Enum Game.LambdaHack.Common.Faction.Diplomacy instance GHC.Classes.Ord Game.LambdaHack.Common.Faction.Diplomacy instance GHC.Classes.Eq Game.LambdaHack.Common.Faction.Diplomacy instance GHC.Show.Show Game.LambdaHack.Common.Faction.Diplomacy instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.Challenge instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.Target instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.TGoal instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.Faction instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.Status instance Data.Binary.Class.Binary Game.LambdaHack.Common.Faction.Diplomacy -- | Actors perceiving other actors and the dungeon level. -- -- Visibility works according to KISS. Everything that player sees is -- real. There are no unmarked hidden tiles and only solid tiles can be -- marked, so there are no invisible walls and to pass through an -- illusory wall, you have to use a turn bumping into it first. Only -- tiles marked with Suspect can turn out to be another tile. (So, if all -- tiles are marked with Suspect, the player knows nothing for sure, but -- this should be avoided, because searching becomes too time-consuming.) -- Each actor sees adjacent tiles, even when blind, so adjacent tiles are -- known, so the actor can decide accurately whether to pass thorugh or -- alter, etc. -- -- Items are always real and visible. Actors are real, but can be -- invisible. Invisible actors in walls can't be hit, but are hinted at -- when altering the tile, so the player can flee or block. Invisible -- actors in open space can be hit. module Game.LambdaHack.Common.Perception -- | Visible positions. newtype PerVisible PerVisible :: EnumSet Point -> PerVisible [pvisible] :: PerVisible -> EnumSet Point -- | Smelled positions. newtype PerSmelled PerSmelled :: EnumSet Point -> PerSmelled [psmelled] :: PerSmelled -> EnumSet Point -- | The type representing the perception of a faction on a level. data Perception Perception :: PerVisible -> PerSmelled -> Perception [psight] :: Perception -> PerVisible [psmell] :: Perception -> PerSmelled -- | Perception of a single faction, indexed by level identifier. type PerLid = EnumMap LevelId Perception -- | Perception indexed by faction identifier. This can't be added to -- FactionDict, because clients can't see it for other factions. type PerFid = EnumMap FactionId PerLid -- | The set of tiles visible by at least one hero. totalVisible :: Perception -> EnumSet Point -- | The set of tiles smelt by at least one hero. totalSmelled :: Perception -> EnumSet Point emptyPer :: Perception nullPer :: Perception -> Bool addPer :: Perception -> Perception -> Perception diffPer :: Perception -> Perception -> Perception instance GHC.Generics.Generic Game.LambdaHack.Common.Perception.Perception instance GHC.Classes.Eq Game.LambdaHack.Common.Perception.Perception instance GHC.Show.Show Game.LambdaHack.Common.Perception.Perception instance Data.Binary.Class.Binary Game.LambdaHack.Common.Perception.PerSmelled instance GHC.Classes.Eq Game.LambdaHack.Common.Perception.PerSmelled instance GHC.Show.Show Game.LambdaHack.Common.Perception.PerSmelled instance Data.Binary.Class.Binary Game.LambdaHack.Common.Perception.PerVisible instance GHC.Classes.Eq Game.LambdaHack.Common.Perception.PerVisible instance GHC.Show.Show Game.LambdaHack.Common.Perception.PerVisible instance Data.Binary.Class.Binary Game.LambdaHack.Common.Perception.Perception -- | High score table operations. module Game.LambdaHack.Common.HighScore -- | The list of scores, in decreasing order. data ScoreTable -- | A dictionary from game mode IDs to scores tables. type ScoreDict = EnumMap (ContentId ModeKind) ScoreTable -- | Empty score table empty :: ScoreDict -- | Register a new score in a score table. register :: ScoreTable -> Int -> Int -> Time -> Status -> POSIXTime -> Challenge -> Text -> EnumMap (ContentId ItemKind) Int -> EnumMap (ContentId ItemKind) Int -> HiCondPoly -> (Bool, (ScoreTable, Int)) -- | Show a single high score, from the given ranking in the high score -- table. showScore :: TimeZone -> (Int, ScoreRecord) -> [Text] getTable :: ContentId ModeKind -> ScoreDict -> ScoreTable getRecord :: Int -> ScoreTable -> ScoreRecord -- | Generate a slideshow with the current and previous scores. highSlideshow :: ScoreTable -> Int -> Text -> TimeZone -> (Text, [[Text]]) -- | A single score record. Records are ordered in the highscore table, -- from the best to the worst, in lexicographic ordering wrt the fields -- below. data ScoreRecord -- | Insert a new score into the table, Return new table and the ranking. -- Make sure the table doesn't grow too large. insertPos :: ScoreRecord -> ScoreTable -> (ScoreTable, Int) -- | Show a screenful of the high scores table. Parameter height is the -- number of (3-line) scores to be shown. showTable :: TimeZone -> ScoreTable -> Int -> Int -> [Text] -- | Produce a couple of renderings of the high scores table. showNearbyScores :: TimeZone -> Int -> ScoreTable -> Int -> [[Text]] instance Data.Binary.Class.Binary Game.LambdaHack.Common.HighScore.ScoreTable instance GHC.Classes.Eq Game.LambdaHack.Common.HighScore.ScoreTable instance GHC.Generics.Generic Game.LambdaHack.Common.HighScore.ScoreRecord instance GHC.Classes.Ord Game.LambdaHack.Common.HighScore.ScoreRecord instance GHC.Classes.Eq Game.LambdaHack.Common.HighScore.ScoreRecord instance GHC.Show.Show Game.LambdaHack.Common.HighScore.ScoreRecord instance GHC.Show.Show Game.LambdaHack.Common.HighScore.ScoreTable instance Data.Binary.Class.Binary Game.LambdaHack.Common.HighScore.ScoreRecord -- | The common server and client basic game state type and its operations. module Game.LambdaHack.Common.State -- | View on the basic game state. The remembered fields, in -- client copies of the state, carry only a subset of the full -- information that the server keeps. Clients never directly change their -- State, but apply atomic actions sent by the server to do so -- (and/or the server applies the actions to each client state in turn). data State sdungeon :: State -> Dungeon stotalDepth :: State -> AbsDepth sactorD :: State -> ActorDict sitemD :: State -> ItemDict sitemIxMap :: State -> ItemIxMap sfactionD :: State -> FactionDict stime :: State -> Time scops :: State -> COps sgold :: State -> Int shigh :: State -> ScoreDict sgameModeId :: State -> ContentId ModeKind sdiscoKind :: State -> DiscoveryKind sdiscoAspect :: State -> DiscoveryAspect sactorAspect :: State -> ActorAspect -- | Initial complete global game state. defStateGlobal :: Dungeon -> AbsDepth -> FactionDict -> COps -> ScoreDict -> ContentId ModeKind -> DiscoveryKind -> 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 :: (AbsDepth -> AbsDepth) -> State -> State -- | Update the actor dictionary. updateActorD :: (ActorDict -> ActorDict) -> State -> State -- | Update the item dictionary. updateItemD :: (ItemDict -> ItemDict) -> State -> State -- | Update the item kind index map. updateItemIxMap :: (ItemIxMap -> ItemIxMap) -> State -> State -- | Update faction data within state. updateFactionD :: (FactionDict -> FactionDict) -> State -> State -- | Update global time within state. updateTime :: (Time -> Time) -> State -> State -- | Update content data within state and recompute the cached data. updateCOpsAndCachedData :: (COps -> COps) -> State -> State -- | Update total gold value in the dungeon. updateGold :: (Int -> Int) -> State -> State updateDiscoKind :: (DiscoveryKind -> DiscoveryKind) -> State -> State updateDiscoAspect :: (DiscoveryAspect -> DiscoveryAspect) -> State -> State updateActorAspect :: (ActorAspect -> ActorAspect) -> State -> State getItemBody :: ItemId -> State -> Item aspectRecordFromItem :: ItemId -> Item -> State -> AspectRecord aspectRecordFromIid :: ItemId -> State -> AspectRecord aspectRecordFromActor :: Actor -> State -> AspectRecord actorAspectInDungeon :: State -> ActorAspect unknownLevel :: COps -> ContentId CaveKind -> AbsDepth -> X -> Y -> ([Point], [Point]) -> [Point] -> Int -> Bool -> Level unknownTileMap :: ContentId TileKind -> Int -> Int -> TileMap instance GHC.Classes.Eq Game.LambdaHack.Common.State.State instance GHC.Show.Show Game.LambdaHack.Common.State.State instance Data.Binary.Class.Binary Game.LambdaHack.Common.State.State -- | UI aspects of actors. module Game.LambdaHack.Client.UI.ActorUI data ActorUI ActorUI :: Char -> Text -> Text -> Color -> ActorUI -- | individual map symbol [bsymbol] :: ActorUI -> Char -- | individual name [bname] :: ActorUI -> Text -- | individual pronoun [bpronoun] :: ActorUI -> Text -- | individual map color [bcolor] :: ActorUI -> Color type ActorDictUI = EnumMap ActorId ActorUI keySelected :: (ActorId, Actor, ActorUI) -> (Bool, Bool, Char, Color, ActorId) -- | The part of speech describing the actor. partActor :: ActorUI -> Part -- | The part of speech containing the actor pronoun. partPronoun :: ActorUI -> Part ppContainer :: Container -> Text ppCStore :: CStore -> (Text, Text) ppCStoreIn :: CStore -> Text ppCStoreWownW :: Bool -> CStore -> Part -> [Part] ppContainerWownW :: (ActorId -> Part) -> Bool -> Container -> [Part] verbCStore :: CStore -> Text tryFindActor :: State -> (ActorId -> Actor -> Bool) -> Maybe (ActorId, Actor) tryFindHeroK :: ActorDictUI -> FactionId -> Int -> State -> Maybe (ActorId, Actor) instance GHC.Generics.Generic Game.LambdaHack.Client.UI.ActorUI.ActorUI instance GHC.Classes.Eq Game.LambdaHack.Client.UI.ActorUI.ActorUI instance GHC.Show.Show Game.LambdaHack.Client.UI.ActorUI.ActorUI instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.ActorUI.ActorUI -- | Description of effects. module Game.LambdaHack.Client.UI.EffectDescription data DetailLevel DetailLow :: DetailLevel DetailMedium :: DetailLevel DetailHigh :: DetailLevel DetailAll :: DetailLevel -- | Suffix to append to a basic content name if the content causes the -- effect. -- -- We show absolute time in seconds, not moves, because actors -- can have different speeds (and actions can potentially take different -- time intervals). We call the time taken by one player move, when -- walking, a move. Turn and clip are used -- mostly internally, the former as an absolute time unit. We show -- distances in steps, because one step, from a tile to another -- tile, is always 1 meter. We don't call steps tiles, reserving -- that term for the context of terrain kinds or units of area. effectToSuffix :: DetailLevel -> Effect -> Text detectToObject :: DetectKind -> Text detectToVerb :: DetectKind -> Text slotToSentence :: EqpSlot -> Text slotToName :: EqpSlot -> Text slotToDesc :: EqpSlot -> Text slotToDecorator :: EqpSlot -> Actor -> Int -> Text statSlots :: [EqpSlot] kindAspectToSuffix :: Aspect -> Text featureToSuff :: Feature -> Text featureToSentence :: Feature -> Maybe Text affixDice :: Dice -> Text tmodToSuff :: Text -> ThrowMod -> Text affixBonus :: Int -> Text wrapInParens :: Text -> Text wrapInChevrons :: Text -> Text instance GHC.Enum.Bounded Game.LambdaHack.Client.UI.EffectDescription.DetailLevel instance GHC.Enum.Enum Game.LambdaHack.Client.UI.EffectDescription.DetailLevel instance GHC.Classes.Ord Game.LambdaHack.Client.UI.EffectDescription.DetailLevel instance GHC.Classes.Eq Game.LambdaHack.Client.UI.EffectDescription.DetailLevel -- | Descripitons of items. module Game.LambdaHack.Client.UI.ItemDescription -- | The part of speech describing the item. partItem :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> (Bool, Bool, Part, Part) partItemShort :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> (Bool, Bool, Part, Part) partItemShortest :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> (Bool, Bool, Part, Part) partItemHigh :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> (Bool, Bool, Part, Part) partItemWs :: FactionId -> FactionDict -> Int -> Time -> ItemFull -> ItemQuant -> (Bool, Part) partItemWsRanged :: FactionId -> FactionDict -> Int -> Time -> ItemFull -> ItemQuant -> (Bool, Part) partItemShortAW :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> Part partItemMediumAW :: FactionId -> FactionDict -> Time -> ItemFull -> ItemQuant -> Part partItemShortWownW :: FactionId -> FactionDict -> Part -> Time -> ItemFull -> ItemQuant -> Part viewItem :: ItemFull -> AttrCharW32 itemDesc :: Bool -> FactionId -> FactionDict -> Int -> CStore -> Time -> ItemFull -> ItemQuant -> AttrLine show64With2 :: Int64 -> Text -- | The part of speech describing the item parameterized by the number of -- effects/aspects to show. partItemN :: FactionId -> FactionDict -> Bool -> DetailLevel -> Int -> Time -> ItemFull -> ItemQuant -> (Bool, Bool, Part, Part) textAllAE :: DetailLevel -> Bool -> ItemFull -> ([Text], [Text]) partItemWsR :: FactionId -> FactionDict -> Bool -> Int -> Time -> ItemFull -> ItemQuant -> (Bool, Part) -- | Abstract syntax of requests. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Client.Request -- | Requests sent by AI clients to the server. If faction leader is to be -- changed, it's included as the second component. type RequestAI = (ReqAI, Maybe ActorId) -- | Possible forms of requests sent by AI clients. data ReqAI ReqAINop :: ReqAI ReqAITimed :: RequestAnyAbility -> ReqAI -- | Requests sent by UI clients to the server. If faction leader is to be -- changed, it's included as the second component. type RequestUI = (ReqUI, Maybe ActorId) -- | Possible forms of requests sent by UI clients. data ReqUI ReqUINop :: ReqUI ReqUITimed :: RequestAnyAbility -> ReqUI ReqUIGameRestart :: (GroupName ModeKind) -> Challenge -> ReqUI ReqUIGameDropAndExit :: ReqUI ReqUIGameSaveAndExit :: ReqUI ReqUIGameSave :: ReqUI ReqUITactic :: Tactic -> ReqUI ReqUIAutomate :: ReqUI -- | Basic form of requests, sent by both AI and UI clients to the server. data RequestAnyAbility RequestAnyAbility :: (RequestTimed a) -> RequestAnyAbility -- | Requests that take game time, indexed by actor ability that is needed -- for performing the corresponding actions. data RequestTimed :: Ability -> * [ReqMove] :: Vector -> RequestTimed 'AbMove [ReqMelee] :: ActorId -> ItemId -> CStore -> RequestTimed 'AbMelee [ReqDisplace] :: ActorId -> RequestTimed 'AbDisplace [ReqAlter] :: Point -> RequestTimed 'AbAlter [ReqWait] :: RequestTimed 'AbWait [ReqWait10] :: RequestTimed 'AbWait [ReqMoveItems] :: [(ItemId, Int, CStore, CStore)] -> RequestTimed 'AbMoveItem [ReqProject] :: Point -> Int -> ItemId -> CStore -> RequestTimed 'AbProject [ReqApply] :: ItemId -> CStore -> RequestTimed 'AbApply instance GHC.Show.Show Game.LambdaHack.Client.Request.ReqAI instance GHC.Show.Show Game.LambdaHack.Client.Request.ReqUI instance GHC.Show.Show Game.LambdaHack.Client.Request.RequestAnyAbility instance GHC.Show.Show (Game.LambdaHack.Client.Request.RequestTimed a) -- | Actor preferences for targets and actions, based on actor attributes. module Game.LambdaHack.Client.Preferences -- | Compute the whole Benefit structure, containing various facets -- of AI item preference, for an item with the given effects and aspects. -- -- Note: result has non-strict fields, so arguments are forced to avoid -- leaks. When AI looks at items (including organs) more often, force the -- fields. totalUsefulness :: COps -> Faction -> ItemFull -> Benefit -- | How much AI benefits from applying the effect. The first component is -- benefit when applied to self, the second is benefit (preferably -- negative) when applied to enemy. This represents benefit from using -- the effect every avgItemDelay turns, so if the item is not -- durable, the value is adjusted down elsewhere. The benefit includes -- the drawback of having to use the actor's turn, except when there is -- battle and item is a weapon and so there is usually nothing better to -- do than to melee, or when the actor is stuck or idle or laying in wait -- or luring an enemy from a safe distance. So there is less than -- averageTurnValue included in each benefit, so in case when -- turn is not spent, e.g, periodic or conditions, the difference in -- value is only slight. effectToBenefit :: COps -> Faction -> Bool -> Effect -> (Double, Double) averageTurnValue :: Double avgItemDelay :: Double avgItemLife :: Double durabilityMult :: Double organBenefit :: Double -> GroupName ItemKind -> COps -> Faction -> (Double, Int) recBenefit :: GroupName ItemKind -> COps -> Faction -> (Double, Int) fakeItem :: ContentId ItemKind -> ItemKind -> KindMean -> ItemFull aspectToBenefit :: Aspect -> Double recordToBenefit :: AspectRecord -> [Double] -- | Operations on the Actor type, and related, that need the -- State type, but not our custom monad types. module Game.LambdaHack.Common.ActorState fidActorNotProjAssocs :: FactionId -> State -> [(ActorId, Actor)] actorAssocs :: (FactionId -> Bool) -> LevelId -> State -> [(ActorId, Actor)] fidActorRegularAssocs :: FactionId -> LevelId -> State -> [(ActorId, Actor)] fidActorRegularIds :: FactionId -> LevelId -> State -> [ActorId] foeRegularAssocs :: FactionId -> LevelId -> State -> [(ActorId, Actor)] foeRegularList :: FactionId -> LevelId -> State -> [Actor] friendRegularAssocs :: FactionId -> LevelId -> State -> [(ActorId, Actor)] friendRegularList :: FactionId -> LevelId -> State -> [Actor] bagAssocs :: State -> ItemBag -> [(ItemId, Item)] bagAssocsK :: State -> ItemBag -> [(ItemId, (Item, ItemQuant))] posToAidsLvl :: Point -> Level -> [ActorId] posToAids :: Point -> LevelId -> State -> [ActorId] posToAssocs :: Point -> LevelId -> State -> [(ActorId, Actor)] nearbyFreePoints :: (ContentId TileKind -> Bool) -> Point -> LevelId -> State -> [Point] -- | Calculate loot's worth for a given faction. calculateTotal :: FactionId -> State -> (ItemBag, Int) -- | Price an item, taking count into consideration. itemPrice :: Int -> ItemKind -> Int mergeItemQuant :: ItemQuant -> ItemQuant -> ItemQuant findIid :: ActorId -> FactionId -> ItemId -> State -> [(ActorId, (Actor, CStore))] combinedInv :: FactionId -> State -> ItemBag combinedEqp :: FactionId -> State -> ItemBag combinedOrgan :: FactionId -> State -> ItemBag combinedItems :: FactionId -> State -> ItemBag combinedFromLore :: SLore -> FactionId -> State -> ItemBag getActorBody :: ActorId -> State -> Actor getActorAspect :: ActorId -> State -> AspectRecord canTraverse :: ActorId -> State -> Bool getCarriedAssocsAndTrunk :: Actor -> State -> [(ItemId, Item)] getCarriedIidCStore :: Actor -> [(ItemId, CStore)] getContainerBag :: Container -> State -> ItemBag getFloorBag :: LevelId -> Point -> State -> ItemBag getEmbedBag :: LevelId -> Point -> State -> ItemBag getBodyStoreBag :: Actor -> CStore -> State -> ItemBag mapActorItems_ :: Monad m => (CStore -> ItemId -> ItemQuant -> m a) -> Actor -> State -> m () getActorAssocs :: ActorId -> CStore -> State -> [(ItemId, Item)] getActorAssocsK :: ActorId -> CStore -> State -> [(ItemId, (Item, ItemQuant))] -- | 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 -- | Get current time from the dungeon data. getLocalTime :: LevelId -> State -> Time regenCalmDelta :: ActorId -> Actor -> State -> Int64 actorInAmbient :: Actor -> State -> Bool canDeAmbientList :: Actor -> State -> [Point] actorSkills :: Maybe ActorId -> ActorId -> State -> Skills dispEnemy :: ActorId -> ActorId -> Skills -> State -> Bool itemToFull :: ItemId -> State -> ItemFull fullAssocs :: ActorId -> [CStore] -> State -> [(ItemId, ItemFull)] kitAssocs :: ActorId -> [CStore] -> State -> [(ItemId, ItemFullKit)] getItemKindId :: Item -> State -> ContentId ItemKind getIidKindId :: ItemId -> State -> ContentId ItemKind getItemKind :: Item -> State -> ItemKind getIidKind :: ItemId -> State -> ItemKind getItemKindIdServer :: Item -> State -> ContentId ItemKind getIidKindIdServer :: ItemId -> State -> ContentId ItemKind getItemKindServer :: Item -> State -> ItemKind getIidKindServer :: ItemId -> State -> ItemKind storeFromC :: Container -> CStore aidFromC :: Container -> Maybe ActorId -- | Determine the dungeon level of the container. If the item is in a -- shared stash, the level depends on which actor asks. lidFromC :: Container -> State -> LevelId posFromC :: Container -> State -> Point isStair :: LevelId -> Point -> State -> Bool -- | Require that any non-dying foe is adjacent. We include even -- projectiles that explode when stricken down, because they can be -- caught and then they don't explode, so it makes sense to focus on -- handling them. If there are many projectiles in a single adjacent -- position, we only test the first one, the one that would be hit in -- melee (this is not optimal if the actor would need to flee instead of -- meleeing, but fleeing with *many* projectiles adjacent is a possible -- waste of a move anyway). anyFoeAdj :: ActorId -> State -> Bool actorAdjacentAssocs :: Actor -> State -> [(ActorId, Actor)] armorHurtBonus :: ActorId -> ActorId -> State -> Int -- | Check if any non-dying foe (projectile or not) is adjacent to any of -- our normal actors (whether they can melee or just need to flee, in -- which case alert is needed so that they are not slowed down by -- others). This is needed only by AI and computed as lazily as possible. inMelee :: FactionId -> LevelId -> State -> Bool -- | Game state reading monad and basic operations. module Game.LambdaHack.Common.MonadStateRead -- | Monad for reading game state. A state monad with state modification -- disallowed (another constraint is needed to permit that). The basic -- server and client monads are like that, because server and clients -- freely modify their internal session data, but don't modify the main -- game state, except in very restricted and synchronized way. class (Monad m, Functor m, Applicative m) => MonadStateRead m getsState :: MonadStateRead m => (State -> a) -> m a getState :: MonadStateRead m => m State getLevel :: MonadStateRead m => LevelId -> m Level nUI :: MonadStateRead m => m Int getGameMode :: MonadStateRead m => m ModeKind isNoConfirmsGame :: MonadStateRead m => m Bool getEntryArena :: MonadStateRead m => Faction -> m LevelId pickWeaponM :: MonadStateRead m => Maybe DiscoveryBenefit -> [(ItemId, ItemFullKit)] -> Skills -> ActorId -> m [(Double, (ItemId, ItemFullKit))] -- | Item slots for UI and AI item collections. module Game.LambdaHack.Client.UI.ItemSlot -- | Slot label. Usually just a character. Sometimes with a numerical -- prefix. data SlotChar SlotChar :: Int -> Char -> SlotChar [slotPrefix] :: SlotChar -> Int [slotChar] :: SlotChar -> Char -- | A collection of mappings from slot labels to item identifiers. newtype ItemSlots ItemSlots :: (EnumMap SLore SingleItemSlots) -> ItemSlots type SingleItemSlots = EnumMap SlotChar ItemId allSlots :: [SlotChar] intSlots :: [SlotChar] slotLabel :: SlotChar -> Text -- | Assigns a slot to an item, e.g., for inclusion in the inventory of a -- hero. assignSlot :: EnumSet ItemId -> SLore -> ItemSlots -> SlotChar partyItemSet :: SLore -> FactionId -> Maybe Actor -> State -> EnumSet ItemId sortSlotMap :: (ItemId -> ItemFull) -> EnumSet ItemId -> SingleItemSlots -> SingleItemSlots mergeItemSlots :: (ItemId -> ItemFull) -> EnumSet ItemId -> [SingleItemSlots] -> SingleItemSlots instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.ItemSlot.ItemSlots instance GHC.Show.Show Game.LambdaHack.Client.UI.ItemSlot.ItemSlots instance GHC.Classes.Eq Game.LambdaHack.Client.UI.ItemSlot.SlotChar instance GHC.Show.Show Game.LambdaHack.Client.UI.ItemSlot.SlotChar instance GHC.Classes.Ord Game.LambdaHack.Client.UI.ItemSlot.SlotChar instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.ItemSlot.SlotChar instance GHC.Enum.Enum Game.LambdaHack.Client.UI.ItemSlot.SlotChar -- | Slideshows. module Game.LambdaHack.Client.UI.Slideshow -- | A key or an item slot label at a given position on the screen. type KYX = (Either [KM] SlotChar, (Y, X, X)) -- | An Overlay of text with an associated list of keys or slots that -- activated when the specified screen position is pointed at. The list -- should be sorted wrt rows and then columns. type OKX = (Overlay, [KYX]) -- | A list of active screenfulls to be shown one after another. Each -- screenful has an independent numbering of rows and columns. data Slideshow emptySlideshow :: Slideshow unsnoc :: Slideshow -> Maybe (Slideshow, OKX) toSlideshow :: [OKX] -> Slideshow menuToSlideshow :: OKX -> Slideshow wrapOKX :: Y -> X -> X -> [(KM, String)] -> OKX splitOverlay :: X -> Y -> Report -> [KM] -> OKX -> Slideshow splitOKX :: X -> Y -> AttrLine -> [KM] -> OKX -> [OKX] moreMsg :: String endMsg :: String keysOKX :: Y -> X -> X -> [KM] -> OKX instance GHC.Classes.Eq Game.LambdaHack.Client.UI.Slideshow.Slideshow instance GHC.Show.Show Game.LambdaHack.Client.UI.Slideshow.Slideshow -- | The monad for writing to the main game state. module Game.LambdaHack.Atomic.MonadStateWrite -- | The monad for writing to the main game state. Atomic updates -- (UpdAtomic) are given semantics in this monad. class MonadStateRead m => MonadStateWrite m modifyState :: MonadStateWrite m => (State -> State) -> m () -- | Exception signifying that atomic action failed because the information -- it carries is inconsistent with the client's state, (e.g., because the -- client knows too little to understand the command or already deduced -- the state change from earlier commands or is confused, amnesiac or -- sees illusory actors or tiles). Whenever we know the failure is -- logically impossible, we don't throw the AtomicFail -- exception, but insert a normal assertion or error call, which -- are never caught nor handled. newtype AtomicFail AtomicFail :: String -> AtomicFail atomicFail :: String -> a putState :: MonadStateWrite m => State -> m () updateLevel :: MonadStateWrite m => LevelId -> (Level -> Level) -> m () updateActor :: MonadStateWrite m => ActorId -> (Actor -> Actor) -> m () updateFaction :: MonadStateWrite m => FactionId -> (Faction -> Faction) -> m () moveActorMap :: MonadStateWrite m => ActorId -> Actor -> Actor -> m () insertBagContainer :: MonadStateWrite m => ItemBag -> Container -> m () insertItemContainer :: MonadStateWrite m => ItemId -> ItemQuant -> Container -> m () insertItemActor :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> CStore -> m () deleteBagContainer :: MonadStateWrite m => ItemBag -> Container -> m () deleteItemContainer :: MonadStateWrite m => ItemId -> ItemQuant -> Container -> m () deleteItemActor :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> CStore -> m () addAis :: MonadStateWrite m => [(ItemId, Item)] -> m () itemsMatch :: Item -> Item -> Bool addItemToActorAspect :: MonadStateWrite m => ItemId -> Item -> Int -> ActorId -> m () resetActorAspect :: MonadStateWrite m => m () insertItemFloor :: MonadStateWrite m => ItemId -> ItemQuant -> LevelId -> Point -> m () insertItemEmbed :: MonadStateWrite m => ItemId -> ItemQuant -> LevelId -> Point -> m () insertItemOrgan :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () insertItemEqp :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () insertItemInv :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () insertItemSha :: MonadStateWrite m => ItemId -> ItemQuant -> FactionId -> m () deleteItemFloor :: MonadStateWrite m => ItemId -> ItemQuant -> LevelId -> Point -> m () deleteItemEmbed :: MonadStateWrite m => ItemId -> ItemQuant -> LevelId -> Point -> m () deleteItemOrgan :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () deleteItemEqp :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () deleteItemInv :: MonadStateWrite m => ItemId -> ItemQuant -> ActorId -> m () deleteItemSha :: MonadStateWrite m => ItemId -> ItemQuant -> FactionId -> m () rmFromBag :: ItemQuant -> ItemId -> ItemBag -> ItemBag instance GHC.Show.Show Game.LambdaHack.Atomic.MonadStateWrite.AtomicFail instance GHC.Exception.Exception Game.LambdaHack.Atomic.MonadStateWrite.AtomicFail -- | Abstract syntax of human player commands. module Game.LambdaHack.Client.UI.HumanCmd data CmdCategory CmdMainMenu :: CmdCategory CmdDashboard :: CmdCategory CmdItemMenu :: CmdCategory CmdMove :: CmdCategory CmdItem :: CmdCategory CmdAim :: CmdCategory CmdMeta :: CmdCategory CmdMouse :: CmdCategory CmdInternal :: CmdCategory CmdNoHelp :: CmdCategory CmdDebug :: CmdCategory CmdMinimal :: CmdCategory categoryDescription :: CmdCategory -> Text -- | Symbolic representation of areas of the screen used to define the -- meaning of mouse button presses relative to where the mouse points to. data CmdArea CaMessage :: CmdArea CaMapLeader :: CmdArea CaMapParty :: CmdArea CaMap :: CmdArea CaLevelNumber :: CmdArea CaArenaName :: CmdArea CaPercentSeen :: CmdArea CaXhairDesc :: CmdArea CaSelected :: CmdArea CaCalmGauge :: CmdArea CaHPGauge :: CmdArea CaTargetDesc :: CmdArea areaDescription :: CmdArea -> Text -- | This triple of command categories, description and the command term -- itself defines the meaning of a human command as entered via a -- keypress, mouse click or chosen from a menu. type CmdTriple = ([CmdCategory], Text, HumanCmd) -- | Abstract syntax of human player commands. data HumanCmd Macro :: [String] -> HumanCmd ByArea :: [(CmdArea, HumanCmd)] -> HumanCmd ByAimMode :: HumanCmd -> HumanCmd -> HumanCmd [exploration] :: HumanCmd -> HumanCmd [aiming] :: HumanCmd -> HumanCmd ComposeIfLocal :: HumanCmd -> HumanCmd -> HumanCmd ComposeUnlessError :: HumanCmd -> HumanCmd -> HumanCmd Compose2ndLocal :: HumanCmd -> HumanCmd -> HumanCmd LoopOnNothing :: HumanCmd -> HumanCmd ExecuteIfClear :: HumanCmd -> HumanCmd Wait :: HumanCmd Wait10 :: HumanCmd MoveDir :: Vector -> HumanCmd RunDir :: Vector -> HumanCmd RunOnceAhead :: HumanCmd MoveOnceToXhair :: HumanCmd RunOnceToXhair :: HumanCmd ContinueToXhair :: HumanCmd MoveItem :: [CStore] -> CStore -> (Maybe Part) -> Bool -> HumanCmd Project :: HumanCmd Apply :: HumanCmd AlterDir :: [TriggerTile] -> HumanCmd AlterWithPointer :: [TriggerTile] -> HumanCmd Help :: HumanCmd Hint :: HumanCmd ItemMenu :: HumanCmd MainMenu :: HumanCmd Dashboard :: HumanCmd GameDifficultyIncr :: HumanCmd GameWolfToggle :: HumanCmd GameFishToggle :: HumanCmd GameScenarioIncr :: HumanCmd GameRestart :: HumanCmd GameExit :: HumanCmd GameSave :: HumanCmd Tactic :: HumanCmd Automate :: HumanCmd SortSlots :: HumanCmd ChooseItem :: ItemDialogMode -> HumanCmd ChooseItemMenu :: ItemDialogMode -> HumanCmd ChooseItemProject :: [TriggerItem] -> HumanCmd ChooseItemApply :: [TriggerItem] -> HumanCmd PickLeader :: Int -> HumanCmd PickLeaderWithPointer :: HumanCmd MemberCycle :: HumanCmd MemberBack :: HumanCmd SelectActor :: HumanCmd SelectNone :: HumanCmd SelectWithPointer :: HumanCmd Repeat :: Int -> HumanCmd Record :: HumanCmd History :: HumanCmd MarkVision :: HumanCmd MarkSmell :: HumanCmd MarkSuspect :: HumanCmd SettingsMenu :: HumanCmd ChallengesMenu :: HumanCmd PrintScreen :: HumanCmd Cancel :: HumanCmd Accept :: HumanCmd TgtClear :: HumanCmd ItemClear :: HumanCmd MoveXhair :: Vector -> Int -> HumanCmd AimTgt :: HumanCmd AimFloor :: HumanCmd AimEnemy :: HumanCmd AimItem :: HumanCmd AimAscend :: Int -> HumanCmd EpsIncr :: Bool -> HumanCmd XhairUnknown :: HumanCmd XhairItem :: HumanCmd XhairStair :: Bool -> HumanCmd XhairPointerFloor :: HumanCmd XhairPointerEnemy :: HumanCmd AimPointerFloor :: HumanCmd AimPointerEnemy :: HumanCmd -- | Description of how item manipulation is triggered and communicated to -- the player. data TriggerItem TriggerItem :: Part -> Part -> [Char] -> TriggerItem [tiverb] :: TriggerItem -> Part [tiobject] :: TriggerItem -> Part [tisymbols] :: TriggerItem -> [Char] -- | Description of how tile altering is triggered and communicated to the -- player. data TriggerTile TriggerTile :: Part -> Part -> Feature -> TriggerTile [ttverb] :: TriggerTile -> Part [ttobject] :: TriggerTile -> Part [ttfeature] :: TriggerTile -> Feature instance GHC.Generics.Generic Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Classes.Ord Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Classes.Eq Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Read.Read Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Show.Show Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Generics.Generic Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance GHC.Classes.Ord Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance GHC.Classes.Eq Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance GHC.Show.Show Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance GHC.Generics.Generic Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance GHC.Classes.Ord Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance GHC.Classes.Eq Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance GHC.Show.Show Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance GHC.Generics.Generic Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance GHC.Classes.Ord Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance GHC.Classes.Eq Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance GHC.Read.Read Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance GHC.Show.Show Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance GHC.Generics.Generic Game.LambdaHack.Client.UI.HumanCmd.CmdCategory instance GHC.Classes.Eq Game.LambdaHack.Client.UI.HumanCmd.CmdCategory instance GHC.Read.Read Game.LambdaHack.Client.UI.HumanCmd.CmdCategory instance GHC.Show.Show Game.LambdaHack.Client.UI.HumanCmd.CmdCategory instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.HumanCmd.HumanCmd instance GHC.Read.Read Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.HumanCmd.TriggerTile instance GHC.Read.Read Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.HumanCmd.TriggerItem instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.HumanCmd.CmdArea instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.HumanCmd.CmdCategory instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.HumanCmd.CmdCategory -- | UI client options. module Game.LambdaHack.Client.UI.UIOptions -- | Options that affect the UI of the client. data UIOptions UIOptions :: [(KM, CmdTriple)] -> [(Int, (Text, Text))] -> Bool -> Bool -> Text -> Text -> Int -> Int -> Int -> Bool -> Int -> Int -> Bool -> Bool -> Int -> [String] -> UIOptions [uCommands] :: UIOptions -> [(KM, CmdTriple)] [uHeroNames] :: UIOptions -> [(Int, (Text, Text))] -- | the option for Vi keys takes precendence [uVi] :: UIOptions -> Bool -- | because the laptop keys are the default [uLaptop] :: UIOptions -> Bool [uGtkFontFamily] :: UIOptions -> Text [uSdlFontFile] :: UIOptions -> Text [uSdlTtfSizeAdd] :: UIOptions -> Int [uSdlFonSizeAdd] :: UIOptions -> Int [uFontSize] :: UIOptions -> Int [uColorIsBold] :: UIOptions -> Bool [uHistoryMax] :: UIOptions -> Int [uMaxFps] :: UIOptions -> Int [uNoAnim] :: UIOptions -> Bool [uRunStopMsgs] :: UIOptions -> Bool -- | HP percent at which warning is emitted. [uhpWarningPercent] :: UIOptions -> Int -- | Hardwired commandline arguments to process. [uCmdline] :: UIOptions -> [String] -- | Read and parse UI config file. mkUIOptions :: COps -> Bool -> IO UIOptions -- | Modify client options with UI options. applyUIOptions :: COps -> UIOptions -> ClientOptions -> ClientOptions parseConfig :: Config -> UIOptions instance GHC.Generics.Generic Game.LambdaHack.Client.UI.UIOptions.UIOptions instance GHC.Show.Show Game.LambdaHack.Client.UI.UIOptions.UIOptions instance Control.DeepSeq.NFData Game.LambdaHack.Client.UI.UIOptions.UIOptions instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.UIOptions.UIOptions -- | The type of definitions of key-command mappings to be used for the UI -- and shorthands for specifying command triples in the content files. module Game.LambdaHack.Client.UI.Content.KeyKind -- | Key-command mappings to be specified in content and used for the UI. newtype KeyKind -- | default client UI commands KeyKind :: [(KM, CmdTriple)] -> KeyKind evalKeyDef :: (String, CmdTriple) -> (KM, CmdTriple) addCmdCategory :: CmdCategory -> CmdTriple -> CmdTriple replaceDesc :: Text -> CmdTriple -> CmdTriple moveItemTriple :: [CStore] -> CStore -> Part -> Bool -> CmdTriple repeatTriple :: Int -> CmdTriple mouseLMB :: CmdTriple mouseMMB :: CmdTriple mouseRMB :: CmdTriple goToCmd :: HumanCmd runToAllCmd :: HumanCmd autoexploreCmd :: HumanCmd autoexplore25Cmd :: HumanCmd aimFlingCmd :: HumanCmd projectI :: [TriggerItem] -> CmdTriple projectA :: [TriggerItem] -> CmdTriple flingTs :: [TriggerItem] applyIK :: [TriggerItem] -> CmdTriple applyI :: [TriggerItem] -> CmdTriple grabItems :: Text -> CmdTriple dropItems :: Text -> CmdTriple descIs :: [TriggerItem] -> Text descTs :: [TriggerTile] -> Text defaultHeroSelect :: Int -> (String, CmdTriple) replaceCmd :: HumanCmd -> CmdTriple -> CmdTriple projectICmd :: [TriggerItem] -> HumanCmd grabCmd :: HumanCmd dropCmd :: HumanCmd -- | Verifying, aggregating and displaying binding of keys to commands. module Game.LambdaHack.Client.UI.KeyBindings -- | Bindings and other information about human player commands. data Binding Binding :: Map KM CmdTriple -> [(KM, CmdTriple)] -> Map HumanCmd [KM] -> Binding -- | binding of keys to commands [bcmdMap] :: Binding -> Map KM CmdTriple -- | the properly ordered list of commands for the help menu [bcmdList] :: Binding -> [(KM, CmdTriple)] -- | and from commands to their keys [brevMap] :: Binding -> Map HumanCmd [KM] -- | Create binding of keys to movement and other standard commands, as -- well as commands defined in the config file. stdBinding :: KeyKind -> UIOptions -> Binding -- | Produce a set of help/menu screens from the key bindings. keyHelp :: COps -> Binding -> Int -> [(Text, OKX)] -- | Turn the specified portion of bindings into a menu. okxsN :: Binding -> Int -> Int -> (HumanCmd -> Bool) -> Bool -> CmdCategory -> [Text] -> [Text] -> OKX -- | The client UI session state. module Game.LambdaHack.Client.UI.SessionUI -- | The information that is used across a client playing session, -- including many consecutive games in a single session. Some of it is -- saved, some is reset when a new playing session starts. An important -- component is the frontend session. data SessionUI SessionUI :: Target -> ActorDictUI -> ItemSlots -> Maybe (CStore, CStore) -> ChanFrontend -> Binding -> UIOptions -> Maybe AimMode -> Bool -> Maybe (ItemId, CStore, Bool) -> EnumSet ActorId -> Maybe RunParams -> History -> Point -> LastRecord -> [KM] -> EnumSet ActorId -> Int -> Bool -> Bool -> Map String Int -> Bool -> HintMode -> Bool -> POSIXTime -> POSIXTime -> Time -> Int -> Int -> SessionUI -- | the common xhair [sxhair] :: SessionUI -> Target -- | assigned actor UI presentations [sactorUI] :: SessionUI -> ActorDictUI -- | map from slots to items [sslots] :: SessionUI -> ItemSlots -- | last item move stores [slastItemMove] :: SessionUI -> Maybe (CStore, CStore) -- | connection with the frontend [schanF] :: SessionUI -> ChanFrontend -- | binding of keys to commands [sbinding] :: SessionUI -> Binding -- | UI options as set by the player [sUIOptions] :: SessionUI -> UIOptions -- | aiming mode [saimMode] :: SessionUI -> Maybe AimMode -- | last mouse aiming not vacuus [sxhairMoused] :: SessionUI -> Bool -- | selected item, if any, it's store and whether to override suitability -- check [sitemSel] :: SessionUI -> Maybe (ItemId, CStore, Bool) -- | the set of currently selected actors [sselected] :: SessionUI -> EnumSet ActorId -- | parameters of the current run, if any [srunning] :: SessionUI -> Maybe RunParams -- | history of messages [shistory] :: SessionUI -> History -- | mouse pointer position [spointer] :: SessionUI -> Point -- | state of key sequence recording [slastRecord] :: SessionUI -> LastRecord -- | state of key sequence playback [slastPlay] :: SessionUI -> [KM] -- | actors that just got out of sight [slastLost] :: SessionUI -> EnumSet ActorId -- | player just waited this many times [swaitTimes] :: SessionUI -> Int -- | mark leader and party FOV [smarkVision] :: SessionUI -> Bool -- | mark smell, if the leader can smell [smarkSmell] :: SessionUI -> Bool -- | indices of last used menu items [smenuIxMap] :: SessionUI -> Map String Int -- | current level needs displaying [sdisplayNeeded] :: SessionUI -> Bool -- | how to show keys hints when no messages [shintMode] :: SessionUI -> HintMode -- | whether no report created last UI turn [sreportNull] :: SessionUI -> Bool -- | this session start time [sstart] :: SessionUI -> POSIXTime -- | this game start time [sgstart] :: SessionUI -> POSIXTime -- | clips from start of session to current game start [sallTime] :: SessionUI -> Time -- | this game current frame count [snframes] :: SessionUI -> Int -- | frame count from start of session to current game start [sallNframes] :: SessionUI -> Int -- | Current aiming mode of a client. newtype AimMode AimMode :: LevelId -> AimMode [aimLevelId] :: AimMode -> LevelId -- | Parameters of the current run. data RunParams RunParams :: ActorId -> [ActorId] -> Bool -> Maybe Text -> Int -> RunParams -- | the original leader from run start [runLeader] :: RunParams -> ActorId -- | the list of actors that take part [runMembers] :: RunParams -> [ActorId] -- | initial run continuation by any run participant, including run leader [runInitial] :: RunParams -> Bool -- | message with the next stop reason [runStopMsg] :: RunParams -> Maybe Text -- | waiting for others to move out of the way [runWaiting] :: RunParams -> Int -- | State of last recorded and currently being recorded key sequences. data LastRecord LastRecord :: [KM] -> [KM] -> Int -> LastRecord -- | accumulated keys of the current command [currentKeys] :: LastRecord -> [KM] -- | keys of the rest of the recorded command batch [previousKeys] :: LastRecord -> [KM] -- | space left for commands to record in this batch [freeSpace] :: LastRecord -> Int data HintMode HintAbsent :: HintMode HintShown :: HintMode HintWiped :: HintMode emptySessionUI :: UIOptions -> SessionUI toggleMarkVision :: SessionUI -> SessionUI toggleMarkSmell :: SessionUI -> SessionUI getActorUI :: ActorId -> SessionUI -> ActorUI instance GHC.Enum.Bounded Game.LambdaHack.Client.UI.SessionUI.HintMode instance GHC.Enum.Enum Game.LambdaHack.Client.UI.SessionUI.HintMode instance GHC.Classes.Eq Game.LambdaHack.Client.UI.SessionUI.HintMode instance GHC.Show.Show Game.LambdaHack.Client.UI.SessionUI.RunParams instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.SessionUI.AimMode instance GHC.Classes.Eq Game.LambdaHack.Client.UI.SessionUI.AimMode instance GHC.Show.Show Game.LambdaHack.Client.UI.SessionUI.AimMode instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.SessionUI.SessionUI instance Data.Binary.Class.Binary Game.LambdaHack.Client.UI.SessionUI.RunParams -- | 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/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Atomic.CmdAtomic -- | Abstract syntax of atomic commands, that is, atomic game state -- transformations. data CmdAtomic -- | atomic updates UpdAtomic :: UpdAtomic -> CmdAtomic -- | atomic special effects SfxAtomic :: SfxAtomic -> CmdAtomic -- | Abstract syntax of atomic updates, that is, atomic commands that -- really change the State. Most of them are an encoding of a game -- state diff, though they also carry some intentional hints that help -- clients determine whether and how to communicate it to players. data UpdAtomic UpdCreateActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdDestroyActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdCreateItem :: ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdDestroyItem :: ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdSpotActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdLoseActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdSpotItem :: Bool -> ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdLoseItem :: Bool -> ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdSpotItemBag :: Container -> ItemBag -> [(ItemId, Item)] -> UpdAtomic UpdLoseItemBag :: Container -> ItemBag -> [(ItemId, Item)] -> UpdAtomic UpdMoveActor :: ActorId -> Point -> Point -> UpdAtomic UpdWaitActor :: ActorId -> Bool -> UpdAtomic UpdDisplaceActor :: ActorId -> ActorId -> UpdAtomic UpdMoveItem :: ItemId -> Int -> ActorId -> CStore -> CStore -> UpdAtomic UpdRefillHP :: ActorId -> Int64 -> UpdAtomic UpdRefillCalm :: ActorId -> Int64 -> UpdAtomic UpdTrajectory :: ActorId -> (Maybe ([Vector], Speed)) -> (Maybe ([Vector], Speed)) -> UpdAtomic UpdQuitFaction :: FactionId -> (Maybe Status) -> (Maybe Status) -> UpdAtomic UpdLeadFaction :: FactionId -> (Maybe ActorId) -> (Maybe ActorId) -> UpdAtomic UpdDiplFaction :: FactionId -> FactionId -> Diplomacy -> Diplomacy -> UpdAtomic UpdTacticFaction :: FactionId -> Tactic -> Tactic -> UpdAtomic UpdAutoFaction :: FactionId -> Bool -> UpdAtomic UpdRecordKill :: ActorId -> (ContentId ItemKind) -> Int -> UpdAtomic UpdAlterTile :: LevelId -> Point -> (ContentId TileKind) -> (ContentId TileKind) -> UpdAtomic UpdAlterExplorable :: LevelId -> Int -> UpdAtomic UpdAlterGold :: Int -> UpdAtomic UpdSearchTile :: ActorId -> Point -> (ContentId TileKind) -> UpdAtomic UpdHideTile :: ActorId -> Point -> (ContentId TileKind) -> UpdAtomic UpdSpotTile :: LevelId -> [(Point, ContentId TileKind)] -> UpdAtomic UpdLoseTile :: LevelId -> [(Point, ContentId TileKind)] -> UpdAtomic UpdAlterSmell :: LevelId -> Point -> Time -> Time -> UpdAtomic UpdSpotSmell :: LevelId -> [(Point, Time)] -> UpdAtomic UpdLoseSmell :: LevelId -> [(Point, Time)] -> UpdAtomic UpdTimeItem :: ItemId -> Container -> ItemTimer -> ItemTimer -> UpdAtomic UpdAgeGame :: [LevelId] -> UpdAtomic UpdUnAgeGame :: [LevelId] -> UpdAtomic UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic UpdDiscoverKind :: Container -> ItemKindIx -> (ContentId ItemKind) -> UpdAtomic UpdCoverKind :: Container -> ItemKindIx -> (ContentId ItemKind) -> UpdAtomic UpdDiscoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic UpdCoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic UpdDiscoverServer :: ItemId -> AspectRecord -> UpdAtomic UpdCoverServer :: ItemId -> AspectRecord -> UpdAtomic UpdPerception :: LevelId -> Perception -> Perception -> UpdAtomic UpdRestart :: FactionId -> PerLid -> State -> Challenge -> ClientOptions -> UpdAtomic UpdRestartServer :: State -> UpdAtomic UpdResume :: FactionId -> PerLid -> UpdAtomic UpdResumeServer :: State -> UpdAtomic UpdKillExit :: FactionId -> UpdAtomic UpdWriteSave :: UpdAtomic -- | Abstract syntax of atomic special effects, that is, atomic commands -- that only display special effects and don't change State. data SfxAtomic SfxStrike :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxRecoil :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxSteal :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxRelease :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxProject :: ActorId -> ItemId -> CStore -> SfxAtomic SfxReceive :: ActorId -> ItemId -> CStore -> SfxAtomic SfxApply :: ActorId -> ItemId -> CStore -> SfxAtomic SfxCheck :: ActorId -> ItemId -> CStore -> SfxAtomic SfxTrigger :: ActorId -> Point -> SfxAtomic SfxShun :: ActorId -> Point -> SfxAtomic SfxEffect :: FactionId -> ActorId -> Effect -> Int64 -> SfxAtomic SfxMsgFid :: FactionId -> SfxMsg -> SfxAtomic SfxSortSlots :: SfxAtomic SfxCollideTile :: ActorId -> Point -> SfxAtomic -- | Symbolic representation of text messages sent by server to clients and -- shown to players. data SfxMsg SfxUnexpected :: ReqFailure -> SfxMsg SfxExpected :: Text -> ReqFailure -> SfxMsg SfxLoudUpd :: Bool -> UpdAtomic -> SfxMsg SfxLoudStrike :: Bool -> (ContentId ItemKind) -> Int -> SfxMsg SfxLoudSummon :: Bool -> (GroupName ItemKind) -> Dice -> SfxMsg SfxFizzles :: SfxMsg SfxNothingHappens :: SfxMsg SfxVoidDetection :: DetectKind -> SfxMsg SfxUnimpressed :: ActorId -> SfxMsg SfxSummonLackCalm :: ActorId -> SfxMsg SfxLevelNoMore :: SfxMsg SfxLevelPushed :: SfxMsg SfxBracedImmune :: ActorId -> SfxMsg SfxEscapeImpossible :: SfxMsg SfxStasisProtects :: SfxMsg SfxTransImpossible :: SfxMsg SfxIdentifyNothing :: SfxMsg SfxPurposeNothing :: CStore -> SfxMsg SfxPurposeTooFew :: Int -> Int -> SfxMsg SfxPurposeUnique :: SfxMsg SfxPurposeNotCommon :: SfxMsg SfxColdFish :: SfxMsg SfxTimerExtended :: LevelId -> ActorId -> ItemId -> CStore -> SfxMsg SfxCollideActor :: LevelId -> ActorId -> ActorId -> SfxMsg undoUpdAtomic :: UpdAtomic -> Maybe UpdAtomic undoSfxAtomic :: SfxAtomic -> SfxAtomic undoCmdAtomic :: CmdAtomic -> Maybe CmdAtomic instance GHC.Generics.Generic Game.LambdaHack.Atomic.CmdAtomic.CmdAtomic instance GHC.Classes.Eq Game.LambdaHack.Atomic.CmdAtomic.CmdAtomic instance GHC.Show.Show Game.LambdaHack.Atomic.CmdAtomic.CmdAtomic instance GHC.Generics.Generic Game.LambdaHack.Atomic.CmdAtomic.SfxAtomic instance GHC.Classes.Eq Game.LambdaHack.Atomic.CmdAtomic.SfxAtomic instance GHC.Show.Show Game.LambdaHack.Atomic.CmdAtomic.SfxAtomic instance GHC.Generics.Generic Game.LambdaHack.Atomic.CmdAtomic.SfxMsg instance GHC.Classes.Eq Game.LambdaHack.Atomic.CmdAtomic.SfxMsg instance GHC.Show.Show Game.LambdaHack.Atomic.CmdAtomic.SfxMsg instance GHC.Generics.Generic Game.LambdaHack.Atomic.CmdAtomic.UpdAtomic instance GHC.Classes.Eq Game.LambdaHack.Atomic.CmdAtomic.UpdAtomic instance GHC.Show.Show Game.LambdaHack.Atomic.CmdAtomic.UpdAtomic instance Data.Binary.Class.Binary Game.LambdaHack.Atomic.CmdAtomic.CmdAtomic instance Data.Binary.Class.Binary Game.LambdaHack.Atomic.CmdAtomic.SfxAtomic instance Data.Binary.Class.Binary Game.LambdaHack.Atomic.CmdAtomic.SfxMsg instance Data.Binary.Class.Binary Game.LambdaHack.Atomic.CmdAtomic.UpdAtomic -- | Representation and computation of visiblity of atomic commands by -- clients. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Atomic.PosAtomicRead -- | The type representing visibility of atomic commands to factions, based -- on the position of the command, etc. Note that the server sees and -- smells all positions. 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, server doesn't PosFid :: FactionId -> PosAtomic -- | faction and server notices PosFidAndSer :: (Maybe LevelId) -> FactionId -> PosAtomic -- | only the server notices PosSer :: PosAtomic -- | everybody notices PosAll :: PosAtomic -- | never broadcasted, but sent manually PosNone :: PosAtomic -- | Produce the positions where the atomic update takes place or, more -- generally, the conditions under which the update can be noticed by a -- client. -- -- The goal of this mechanics is to ensure that atomic commands involving -- some positions visible by a client convey similar information as the -- client would get by directly observing the changes of the portion of -- server state limited to the visible positions. Consequently, when the -- visible commands are later applied to the client's state, the state -- stays consistent --- in sync with the server state and correctly -- limited by visiblity. There is some wiggle room both in what "in sync" -- and "visible" means and how they propagate through time. -- -- E.g., UpdDisplaceActor in a black room between two enemy -- actors, with only one actor carrying a 0-radius light would not be -- distinguishable by looking at the state (or the screen) from -- UpdMoveActor of the illuminated actor, hence such -- UpdDisplaceActor should not be observable, but -- UpdMoveActor in similar cotext would be (or the former should -- be perceived as the latter). However, to simplify, we assign as strict -- visibility requirements to UpdMoveActor as to -- UpdDisplaceActor and fall back to UpdSpotActor -- (which provides minimal information that does not contradict state) if -- the visibility is lower. posUpdAtomic :: MonadStateRead m => UpdAtomic -> m PosAtomic -- | Produce the positions where the atomic special effect takes place. posSfxAtomic :: MonadStateRead m => SfxAtomic -> m PosAtomic -- | Decompose an atomic action that is outside a client's visiblity. The -- decomposed actions give less information that the original command, -- but some of them may fall within the visibility range of the client. -- The original action may give more information than even the total sum -- of all actions it's broken into. E.g., UpdMoveActor informs -- about the continued existence of the actor between moves vs popping -- out of existence and then back in. -- -- This is computed in server's State from before performing the -- command. breakUpdAtomic :: MonadStateRead m => UpdAtomic -> m [UpdAtomic] -- | Given the client, its perception and an atomic command, determine if -- the client notices the command. seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool -- | Determine whether the server would see a command that has the given -- visibilty conditions. seenAtomicSer :: PosAtomic -> Bool posProjBody :: Actor -> PosAtomic singleAid :: MonadStateRead m => ActorId -> m PosAtomic doubleAid :: MonadStateRead m => ActorId -> ActorId -> m PosAtomic singleContainer :: MonadStateRead m => Container -> m PosAtomic instance GHC.Classes.Eq Game.LambdaHack.Atomic.PosAtomicRead.PosAtomic instance GHC.Show.Show Game.LambdaHack.Atomic.PosAtomicRead.PosAtomic -- | Semantics of atomic commands shared by client and server. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Atomic.HandleAtomicWrite -- | The game-state semantics of atomic game commands. There is no -- corresponding definition for special effects (SfxAtomic), -- because they don't modify State. -- -- For each of the commands, we are guaranteed that the client, the -- command is addressed to, perceives all the positions the command -- affects (as computed by posUpdAtomic). In the code for each -- semantic function we additonally verify the client is aware of any -- relevant items and/or actors and we throw the AtomicFail -- exception if it's not. The server keeps copies of all clients' states -- and, before sending a command to a client, applies it to the client's -- state copy. If AtomicFail is signalled, the command is -- ignored for that client. This enables simpler server code that -- addresses commands to all clients that can see it, even though not all -- are able to process it. handleUpdAtomic :: MonadStateWrite m => UpdAtomic -> m () updCreateActor :: MonadStateWrite m => ActorId -> Actor -> [(ItemId, Item)] -> m () updDestroyActor :: MonadStateWrite m => ActorId -> Actor -> [(ItemId, Item)] -> m () updCreateItem :: MonadStateWrite m => ItemId -> Item -> ItemQuant -> Container -> m () updDestroyItem :: MonadStateWrite m => ItemId -> Item -> ItemQuant -> Container -> m () updSpotItemBag :: MonadStateWrite m => Container -> ItemBag -> [(ItemId, Item)] -> m () updLoseItemBag :: MonadStateWrite m => Container -> ItemBag -> [(ItemId, Item)] -> m () updMoveActor :: MonadStateWrite m => ActorId -> Point -> Point -> m () updWaitActor :: MonadStateWrite m => ActorId -> Bool -> m () updDisplaceActor :: MonadStateWrite m => ActorId -> ActorId -> m () updMoveItem :: MonadStateWrite m => ItemId -> Int -> ActorId -> CStore -> CStore -> m () updRefillHP :: MonadStateWrite m => ActorId -> Int64 -> m () updRefillCalm :: MonadStateWrite m => ActorId -> Int64 -> m () updTrajectory :: MonadStateWrite m => ActorId -> Maybe ([Vector], Speed) -> Maybe ([Vector], Speed) -> m () updQuitFaction :: MonadStateWrite m => FactionId -> Maybe Status -> Maybe Status -> m () updLeadFaction :: MonadStateWrite m => FactionId -> Maybe ActorId -> Maybe ActorId -> m () updDiplFaction :: MonadStateWrite m => FactionId -> FactionId -> Diplomacy -> Diplomacy -> m () updTacticFaction :: MonadStateWrite m => FactionId -> Tactic -> Tactic -> m () updAutoFaction :: MonadStateWrite m => FactionId -> Bool -> m () updRecordKill :: MonadStateWrite m => ActorId -> ContentId ItemKind -> Int -> m () updAlterTile :: MonadStateWrite m => LevelId -> Point -> ContentId TileKind -> ContentId TileKind -> m () updAlterExplorable :: MonadStateWrite m => LevelId -> Int -> m () updSearchTile :: MonadStateWrite m => ActorId -> Point -> ContentId TileKind -> m () updSpotTile :: MonadStateWrite m => LevelId -> [(Point, ContentId TileKind)] -> m () updLoseTile :: MonadStateWrite m => LevelId -> [(Point, ContentId TileKind)] -> m () updAlterSmell :: MonadStateWrite m => LevelId -> Point -> Time -> Time -> m () updSpotSmell :: MonadStateWrite m => LevelId -> [(Point, Time)] -> m () updLoseSmell :: MonadStateWrite m => LevelId -> [(Point, Time)] -> m () updTimeItem :: MonadStateWrite m => ItemId -> Container -> ItemTimer -> ItemTimer -> m () updAgeGame :: MonadStateWrite m => [LevelId] -> m () updUnAgeGame :: MonadStateWrite m => [LevelId] -> m () ageLevel :: MonadStateWrite m => Delta Time -> LevelId -> m () updDiscover :: MonadStateWrite m => Container -> ItemId -> ContentId ItemKind -> ItemSeed -> m () updCover :: Container -> ItemId -> ContentId ItemKind -> ItemSeed -> m () updDiscoverKind :: MonadStateWrite m => Container -> ItemKindIx -> ContentId ItemKind -> m () discoverKind :: MonadStateWrite m => ItemKindIx -> ContentId ItemKind -> m () updCoverKind :: Container -> ItemKindIx -> ContentId ItemKind -> m () updDiscoverSeed :: MonadStateWrite m => Container -> ItemId -> ItemSeed -> m () discoverSeed :: MonadStateWrite m => ItemId -> ItemSeed -> m () updCoverSeed :: Container -> ItemId -> ItemSeed -> m () updDiscoverServer :: MonadStateWrite m => ItemId -> AspectRecord -> m () updCoverServer :: MonadStateWrite m => ItemId -> AspectRecord -> m () updRestart :: MonadStateWrite m => State -> m () updRestartServer :: MonadStateWrite m => State -> m () updResumeServer :: MonadStateWrite m => State -> m () -- | Atomic game state transformations, their representation and semantics. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Atomic -- | Abstract syntax of atomic commands, that is, atomic game state -- transformations. data CmdAtomic -- | atomic updates UpdAtomic :: UpdAtomic -> CmdAtomic -- | atomic special effects SfxAtomic :: SfxAtomic -> CmdAtomic -- | Abstract syntax of atomic updates, that is, atomic commands that -- really change the State. Most of them are an encoding of a game -- state diff, though they also carry some intentional hints that help -- clients determine whether and how to communicate it to players. data UpdAtomic UpdCreateActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdDestroyActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdCreateItem :: ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdDestroyItem :: ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdSpotActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdLoseActor :: ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic UpdSpotItem :: Bool -> ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdLoseItem :: Bool -> ItemId -> Item -> ItemQuant -> Container -> UpdAtomic UpdSpotItemBag :: Container -> ItemBag -> [(ItemId, Item)] -> UpdAtomic UpdLoseItemBag :: Container -> ItemBag -> [(ItemId, Item)] -> UpdAtomic UpdMoveActor :: ActorId -> Point -> Point -> UpdAtomic UpdWaitActor :: ActorId -> Bool -> UpdAtomic UpdDisplaceActor :: ActorId -> ActorId -> UpdAtomic UpdMoveItem :: ItemId -> Int -> ActorId -> CStore -> CStore -> UpdAtomic UpdRefillHP :: ActorId -> Int64 -> UpdAtomic UpdRefillCalm :: ActorId -> Int64 -> UpdAtomic UpdTrajectory :: ActorId -> (Maybe ([Vector], Speed)) -> (Maybe ([Vector], Speed)) -> UpdAtomic UpdQuitFaction :: FactionId -> (Maybe Status) -> (Maybe Status) -> UpdAtomic UpdLeadFaction :: FactionId -> (Maybe ActorId) -> (Maybe ActorId) -> UpdAtomic UpdDiplFaction :: FactionId -> FactionId -> Diplomacy -> Diplomacy -> UpdAtomic UpdTacticFaction :: FactionId -> Tactic -> Tactic -> UpdAtomic UpdAutoFaction :: FactionId -> Bool -> UpdAtomic UpdRecordKill :: ActorId -> (ContentId ItemKind) -> Int -> UpdAtomic UpdAlterTile :: LevelId -> Point -> (ContentId TileKind) -> (ContentId TileKind) -> UpdAtomic UpdAlterExplorable :: LevelId -> Int -> UpdAtomic UpdAlterGold :: Int -> UpdAtomic UpdSearchTile :: ActorId -> Point -> (ContentId TileKind) -> UpdAtomic UpdHideTile :: ActorId -> Point -> (ContentId TileKind) -> UpdAtomic UpdSpotTile :: LevelId -> [(Point, ContentId TileKind)] -> UpdAtomic UpdLoseTile :: LevelId -> [(Point, ContentId TileKind)] -> UpdAtomic UpdAlterSmell :: LevelId -> Point -> Time -> Time -> UpdAtomic UpdSpotSmell :: LevelId -> [(Point, Time)] -> UpdAtomic UpdLoseSmell :: LevelId -> [(Point, Time)] -> UpdAtomic UpdTimeItem :: ItemId -> Container -> ItemTimer -> ItemTimer -> UpdAtomic UpdAgeGame :: [LevelId] -> UpdAtomic UpdUnAgeGame :: [LevelId] -> UpdAtomic UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic UpdDiscoverKind :: Container -> ItemKindIx -> (ContentId ItemKind) -> UpdAtomic UpdCoverKind :: Container -> ItemKindIx -> (ContentId ItemKind) -> UpdAtomic UpdDiscoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic UpdCoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic UpdDiscoverServer :: ItemId -> AspectRecord -> UpdAtomic UpdCoverServer :: ItemId -> AspectRecord -> UpdAtomic UpdPerception :: LevelId -> Perception -> Perception -> UpdAtomic UpdRestart :: FactionId -> PerLid -> State -> Challenge -> ClientOptions -> UpdAtomic UpdRestartServer :: State -> UpdAtomic UpdResume :: FactionId -> PerLid -> UpdAtomic UpdResumeServer :: State -> UpdAtomic UpdKillExit :: FactionId -> UpdAtomic UpdWriteSave :: UpdAtomic -- | Abstract syntax of atomic special effects, that is, atomic commands -- that only display special effects and don't change State. data SfxAtomic SfxStrike :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxRecoil :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxSteal :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxRelease :: ActorId -> ActorId -> ItemId -> CStore -> SfxAtomic SfxProject :: ActorId -> ItemId -> CStore -> SfxAtomic SfxReceive :: ActorId -> ItemId -> CStore -> SfxAtomic SfxApply :: ActorId -> ItemId -> CStore -> SfxAtomic SfxCheck :: ActorId -> ItemId -> CStore -> SfxAtomic SfxTrigger :: ActorId -> Point -> SfxAtomic SfxShun :: ActorId -> Point -> SfxAtomic SfxEffect :: FactionId -> ActorId -> Effect -> Int64 -> SfxAtomic SfxMsgFid :: FactionId -> SfxMsg -> SfxAtomic SfxSortSlots :: SfxAtomic SfxCollideTile :: ActorId -> Point -> SfxAtomic -- | Symbolic representation of text messages sent by server to clients and -- shown to players. data SfxMsg SfxUnexpected :: ReqFailure -> SfxMsg SfxExpected :: Text -> ReqFailure -> SfxMsg SfxLoudUpd :: Bool -> UpdAtomic -> SfxMsg SfxLoudStrike :: Bool -> (ContentId ItemKind) -> Int -> SfxMsg SfxLoudSummon :: Bool -> (GroupName ItemKind) -> Dice -> SfxMsg SfxFizzles :: SfxMsg SfxNothingHappens :: SfxMsg SfxVoidDetection :: DetectKind -> SfxMsg SfxUnimpressed :: ActorId -> SfxMsg SfxSummonLackCalm :: ActorId -> SfxMsg SfxLevelNoMore :: SfxMsg SfxLevelPushed :: SfxMsg SfxBracedImmune :: ActorId -> SfxMsg SfxEscapeImpossible :: SfxMsg SfxStasisProtects :: SfxMsg SfxTransImpossible :: SfxMsg SfxIdentifyNothing :: SfxMsg SfxPurposeNothing :: CStore -> SfxMsg SfxPurposeTooFew :: Int -> Int -> SfxMsg SfxPurposeUnique :: SfxMsg SfxPurposeNotCommon :: SfxMsg SfxColdFish :: SfxMsg SfxTimerExtended :: LevelId -> ActorId -> ItemId -> CStore -> SfxMsg SfxCollideActor :: LevelId -> ActorId -> ActorId -> SfxMsg -- | The game-state semantics of atomic game commands. There is no -- corresponding definition for special effects (SfxAtomic), -- because they don't modify State. -- -- For each of the commands, we are guaranteed that the client, the -- command is addressed to, perceives all the positions the command -- affects (as computed by posUpdAtomic). In the code for each -- semantic function we additonally verify the client is aware of any -- relevant items and/or actors and we throw the AtomicFail -- exception if it's not. The server keeps copies of all clients' states -- and, before sending a command to a client, applies it to the client's -- state copy. If AtomicFail is signalled, the command is -- ignored for that client. This enables simpler server code that -- addresses commands to all clients that can see it, even though not all -- are able to process it. handleUpdAtomic :: MonadStateWrite m => UpdAtomic -> m () -- | The type representing visibility of atomic commands to factions, based -- on the position of the command, etc. Note that the server sees and -- smells all positions. 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, server doesn't PosFid :: FactionId -> PosAtomic -- | faction and server notices PosFidAndSer :: (Maybe LevelId) -> FactionId -> PosAtomic -- | only the server notices PosSer :: PosAtomic -- | everybody notices PosAll :: PosAtomic -- | never broadcasted, but sent manually PosNone :: PosAtomic -- | Produce the positions where the atomic update takes place or, more -- generally, the conditions under which the update can be noticed by a -- client. -- -- The goal of this mechanics is to ensure that atomic commands involving -- some positions visible by a client convey similar information as the -- client would get by directly observing the changes of the portion of -- server state limited to the visible positions. Consequently, when the -- visible commands are later applied to the client's state, the state -- stays consistent --- in sync with the server state and correctly -- limited by visiblity. There is some wiggle room both in what "in sync" -- and "visible" means and how they propagate through time. -- -- E.g., UpdDisplaceActor in a black room between two enemy -- actors, with only one actor carrying a 0-radius light would not be -- distinguishable by looking at the state (or the screen) from -- UpdMoveActor of the illuminated actor, hence such -- UpdDisplaceActor should not be observable, but -- UpdMoveActor in similar cotext would be (or the former should -- be perceived as the latter). However, to simplify, we assign as strict -- visibility requirements to UpdMoveActor as to -- UpdDisplaceActor and fall back to UpdSpotActor -- (which provides minimal information that does not contradict state) if -- the visibility is lower. posUpdAtomic :: MonadStateRead m => UpdAtomic -> m PosAtomic -- | Produce the positions where the atomic special effect takes place. posSfxAtomic :: MonadStateRead m => SfxAtomic -> m PosAtomic -- | Decompose an atomic action that is outside a client's visiblity. The -- decomposed actions give less information that the original command, -- but some of them may fall within the visibility range of the client. -- The original action may give more information than even the total sum -- of all actions it's broken into. E.g., UpdMoveActor informs -- about the continued existence of the actor between moves vs popping -- out of existence and then back in. -- -- This is computed in server's State from before performing the -- command. breakUpdAtomic :: MonadStateRead m => UpdAtomic -> m [UpdAtomic] -- | Given the client, its perception and an atomic command, determine if -- the client notices the command. seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool -- | Determine whether the server would see a command that has the given -- visibilty conditions. seenAtomicSer :: PosAtomic -> Bool -- | The monad for writing to the main game state. Atomic updates -- (UpdAtomic) are given semantics in this monad. class MonadStateRead m => MonadStateWrite m modifyState :: MonadStateWrite m => (State -> State) -> m () -- | Exception signifying that atomic action failed because the information -- it carries is inconsistent with the client's state, (e.g., because the -- client knows too little to understand the command or already deduced -- the state change from earlier commands or is confused, amnesiac or -- sees illusory actors or tiles). Whenever we know the failure is -- logically impossible, we don't throw the AtomicFail -- exception, but insert a normal assertion or error call, which -- are never caught nor handled. newtype AtomicFail AtomicFail :: String -> AtomicFail putState :: MonadStateWrite m => State -> m () -- | Client-specific game state components. module Game.LambdaHack.Client.State -- | Client state, belonging to a single faction. data StateClient StateClient :: Int -> EnumMap ActorId TgtAndPath -> EnumMap ActorId Point -> EnumSet LevelId -> EnumMap ActorId BfsAndPath -> [CmdAtomic] -> DiscoveryBenefit -> PerLid -> AlterLid -> StdGen -> Maybe ActorId -> FactionId -> Bool -> Challenge -> Challenge -> Int -> Int -> EnumMap LevelId Bool -> EnumMap (ContentId ModeKind) (Map Challenge Int) -> ClientOptions -> StateClient -- | a parameter of the aiming digital line [seps] :: StateClient -> Int -- | targets of our actors in the dungeon [stargetD] :: StateClient -> EnumMap ActorId TgtAndPath -- | the position when fleeing requested [sfleeD] :: StateClient -> EnumMap ActorId Point -- | the set of fully explored levels [sexplored] :: StateClient -> EnumSet LevelId -- | pathfinding data for our actors [sbfsD] :: StateClient -> EnumMap ActorId BfsAndPath -- | atomic commands performed to date [sundo] :: StateClient -> [CmdAtomic] -- | remembered AI benefits of items; could be recomputed at resume, but -- they are costly to generate and not too large [sdiscoBenefit] :: StateClient -> DiscoveryBenefit -- | faction perception indexed by level [sfper] :: StateClient -> PerLid -- | cached alter ability data for positions [salter] :: StateClient -> AlterLid -- | current random generator [srandom] :: StateClient -> StdGen -- | candidate new leader of the faction; Faction.gleader is the old leader [_sleader] :: StateClient -> Maybe ActorId -- | faction controlled by the client [_sside] :: StateClient -> FactionId -- | exit the game loop [squit] :: StateClient -> Bool -- | current game challenge setup [scurChal] :: StateClient -> Challenge -- | next game challenge setup [snxtChal] :: StateClient -> Challenge -- | next game scenario number [snxtScenario] :: StateClient -> Int -- | whether to mark suspect features [smarkSuspect] :: StateClient -> Int -- | whether we are in melee, per level [scondInMelee] :: StateClient -> EnumMap LevelId Bool -- | won games at particular difficulty lvls [svictories] :: StateClient -> EnumMap (ContentId ModeKind) (Map Challenge Int) -- | client options [soptions] :: StateClient -> ClientOptions type AlterLid = EnumMap LevelId (Array Word8) -- | Pathfinding distances to all reachable positions of an actor and a -- shortest paths to some of the positions. data BfsAndPath BfsInvalid :: BfsAndPath BfsAndPath :: Array BfsDistance -> EnumMap Point AndPath -> BfsAndPath [bfsArr] :: BfsAndPath -> Array BfsDistance [bfsPath] :: BfsAndPath -> EnumMap Point AndPath -- | Actor's target and a path to it, if any. data TgtAndPath TgtAndPath :: Target -> AndPath -> TgtAndPath [tapTgt] :: TgtAndPath -> Target [tapPath] :: TgtAndPath -> AndPath -- | Initial empty game client state. emptyStateClient :: FactionId -> StateClient -- | Cycle the smarkSuspect setting. cycleMarkSuspect :: StateClient -> StateClient -- | 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 picked leader within state. Verify actor's faction. updateLeader :: ActorId -> State -> StateClient -> StateClient sside :: StateClient -> FactionId sleader :: StateClient -> Maybe ActorId instance GHC.Show.Show Game.LambdaHack.Client.State.StateClient instance GHC.Generics.Generic Game.LambdaHack.Client.State.TgtAndPath instance GHC.Show.Show Game.LambdaHack.Client.State.TgtAndPath instance GHC.Show.Show Game.LambdaHack.Client.State.BfsAndPath instance Data.Binary.Class.Binary Game.LambdaHack.Client.State.StateClient instance Data.Binary.Class.Binary Game.LambdaHack.Client.State.TgtAndPath -- | Basic client monad and related operations. module Game.LambdaHack.Client.MonadClient -- | Monad for writing to client state. class MonadStateRead m => MonadClient m getsClient :: MonadClient m => (StateClient -> a) -> m a modifyClient :: MonadClient m => (StateClient -> StateClient) -> m () liftIO :: MonadClient m => IO a -> m a getClient :: MonadClient m => m StateClient putClient :: MonadClient m => StateClient -> m () debugPossiblyPrint :: MonadClient m => Text -> m () -- | Invoke pseudo-random computation with the generator kept in the state. rndToAction :: MonadClient m => Rnd a -> m a -- | Invoke pseudo-random computation, don't change generator kept in -- state. rndToActionForget :: MonadClient m => Rnd a -> m a -- | Common client monad operations. module Game.LambdaHack.Client.CommonM -- | Get the current perception of a client. getPerFid :: MonadClient m => LevelId -> m Perception -- | Calculate the position of an actor's target. aidTgtToPos :: ActorId -> LevelId -> Target -> State -> Maybe Point -- | Counts the number of steps until the projectile would hit an actor or -- obstacle. Starts searching with the given eps and returns the first -- found eps for which the number reaches the distance between actor and -- target position, or Nothing if none can be found. makeLine :: MonadStateRead m => Bool -> Actor -> Point -> Int -> m (Maybe Int) maxActorSkillsClient :: MonadClient m => ActorId -> m Skills currentSkillsClient :: MonadClient m => ActorId -> m Skills pickWeaponClient :: MonadClient m => ActorId -> ActorId -> m (Maybe (RequestTimed 'AbMelee)) updateSalter :: MonadClient m => LevelId -> [(Point, ContentId TileKind)] -> m () createSalter :: State -> AlterLid -- | Breadth first search and related algorithms using the client monad. module Game.LambdaHack.Client.BfsM invalidateBfsAid :: MonadClient m => ActorId -> m () invalidateBfsLid :: MonadClient m => LevelId -> m () invalidateBfsAll :: MonadClient m => m () createBfs :: MonadClient m => Bool -> Word8 -> ActorId -> m (Array BfsDistance) -- | Get cached BFS array and path or, if not stored, generate and store -- first. getCacheBfsAndPath :: forall m. MonadClient m => ActorId -> Point -> m (Array BfsDistance, AndPath) -- | Get cached BFS array or, if not stored, generate and store first. getCacheBfs :: MonadClient m => ActorId -> m (Array BfsDistance) -- | Get cached BFS path or, if not stored, generate and store first. getCachePath :: MonadClient m => ActorId -> Point -> m AndPath createPath :: MonadClient m => ActorId -> Target -> m TgtAndPath condBFS :: MonadClient m => ActorId -> m (Bool, Word8) -- | Furthest (wrt paths) known position. furthestKnown :: MonadClient m => ActorId -> m Point -- | Closest reachable unknown tile position, if any. -- -- Note: some of these tiles are behind suspect tiles and they are chosen -- in preference to more distant directly accessible unknown tiles. This -- is in principle OK, but in dungeons with few hidden doors AI is at a -- disadvantage (and with many hidden doors, it fares as well as a human -- that deduced the dungeon properties). Changing Bfs to accomodate all -- dungeon styles would be complex and would slow down the engine. -- -- If the level has inaccessible open areas (at least from the stairs AI -- used) the level will be nevertheless here finally marked explored, to -- enable transition to other levels. We should generally avoid such -- levels, because digging and/or trying to find other stairs leading to -- disconnected areas is not KISS so we don't do this in AI, so AI is at -- a disadvantage. closestUnknown :: MonadClient m => ActorId -> m (Maybe Point) -- | Finds smells closest to the actor, except under the actor, because -- actors consume smell only moving over them, not standing. Of the -- closest, prefers the newest smell. closestSmell :: MonadClient m => ActorId -> m [(Int, (Point, Time))] data FleeViaStairsOrEscape ViaStairs :: FleeViaStairsOrEscape ViaStairsUp :: FleeViaStairsOrEscape ViaStairsDown :: FleeViaStairsOrEscape ViaEscape :: FleeViaStairsOrEscape ViaNothing :: FleeViaStairsOrEscape ViaAnything :: FleeViaStairsOrEscape embedBenefit :: MonadClient m => FleeViaStairsOrEscape -> ActorId -> [(Point, ItemBag)] -> m [(Double, (Point, ItemBag))] -- | Closest (wrt paths) AI-triggerable tiles with embedded items. In AI, -- the level the actor is on is either explored or the actor already has -- a weapon equipped, so no need to explore further, he tries to find -- enemies on other levels, but before that, he triggers other tiles in -- hope of some loot or beneficial effect to enter next level with. closestTriggers :: MonadClient m => FleeViaStairsOrEscape -> ActorId -> m [(Int, (Point, (Point, ItemBag)))] -- | Check whether the actor has enough gear to go look for enemies. We -- assume weapons in equipment are better than any among organs or at -- least provide some essential diversity. Disabled if, due to tactic, -- actors follow leader and so would repeatedly move towards and away -- form stairs at leader change, depending on current leader's gear. -- Number of items of a single kind is ignored, because variety is -- needed. condEnoughGearM :: MonadClient m => ActorId -> m Bool -- | Closest (wrt paths) items. closestItems :: MonadClient m => ActorId -> m [(Int, (Point, ItemBag))] -- | Closest (wrt paths) enemy actors. closestFoes :: MonadClient m => [(ActorId, Actor)] -> ActorId -> m [(Int, (ActorId, Actor))] unexploredDepth :: MonadClient m => Bool -> LevelId -> m Bool updatePathFromBfs :: MonadClient m => Bool -> BfsAndPath -> ActorId -> Point -> m (Array BfsDistance, AndPath) instance GHC.Classes.Eq Game.LambdaHack.Client.BfsM.FleeViaStairsOrEscape instance GHC.Show.Show Game.LambdaHack.Client.BfsM.FleeViaStairsOrEscape -- | Assorted conditions used later on in AI logic. module Game.LambdaHack.Client.AI.ConditionM -- | Require that the target enemy is visible by the party. condAimEnemyPresentM :: MonadClient m => ActorId -> m Bool -- | Require that the target enemy is remembered on the actor's level. condAimEnemyRememberedM :: MonadClient m => ActorId -> m Bool -- | Check if the target is nonmoving. condTgtNonmovingM :: MonadClient m => ActorId -> m Bool -- | Require that any non-dying foe is adjacent, except projectiles that -- (possibly) explode upon contact. condAnyFoeAdjM :: MonadStateRead m => ActorId -> m Bool -- | Require the actor stands adjacent to a triggerable tile (e.g., -- stairs). condAdjTriggerableM :: MonadStateRead m => ActorId -> m Bool -- | Produce the chess-distance-sorted list of non-low-HP, melee-cabable -- foes on the level. We don't consider path-distance, because we are -- interested in how soon the foe can close in to hit us, which can -- diverge greately from path distance for short distances, e.g., when -- terrain gets revealed. We don't consider non-moving actors, because -- they can't chase us and also because they can't be aggresive so to -- resolve the stalemate, the opposing AI has to be aggresive by ignoring -- them and closing in to melee distance. meleeThreatDistList :: ActorId -> State -> [(Int, (ActorId, Actor))] -- | Require the actor blocks the paths of any of his party members. condBlocksFriendsM :: MonadClient m => ActorId -> m Bool -- | Require the actor stands over a weapon that would be auto-equipped. condFloorWeaponM :: MonadStateRead m => ActorId -> m Bool -- | Check whether the actor has no weapon in equipment. condNoEqpWeaponM :: MonadStateRead m => ActorId -> m Bool -- | Require that the actor can project any items. condCanProjectM :: MonadClient m => Int -> ActorId -> m Bool condProjectListM :: MonadClient m => Int -> ActorId -> m [(Benefit, CStore, ItemId, ItemFull, ItemQuant)] -- | Produce the list of items with a given property available to the actor -- and the items' values. benAvailableItems :: DiscoveryBenefit -> ActorId -> [CStore] -> State -> [(Benefit, CStore, ItemId, ItemFull, ItemQuant)] hinders :: Bool -> Bool -> Bool -> Bool -> AspectRecord -> ItemFull -> Bool -- | Require that the actor stands over a desirable item. condDesirableFloorItemM :: MonadClient m => ActorId -> m Bool -- | Produce the list of items on the ground beneath the actor that are -- worth picking up. benGroundItems :: MonadClient m => ActorId -> m [(Benefit, CStore, ItemId, ItemFull, ItemQuant)] desirableItem :: Bool -> Double -> ItemKind -> Bool condSupport :: MonadClient m => Int -> ActorId -> m Bool condSoloM :: MonadClient m => ActorId -> m Bool -- | Require that the actor stands in the dark and so would be betrayed by -- his own equipped light, condShineWouldBetrayM :: MonadStateRead m => ActorId -> m Bool -- | Produce a list of acceptable adjacent points to flee to. fleeList :: MonadClient m => ActorId -> m ([(Int, Point)], [(Int, Point)]) -- | Let AI pick the best target for an actor. module Game.LambdaHack.Client.AI.PickTargetM -- | Verify and possibly change the target of an actor. This function both -- updates the target in the client state and returns the new target -- explicitly. refreshTarget :: MonadClient m => (ActorId, Actor) -> m (Maybe TgtAndPath) computeTarget :: forall m. MonadClient m => ActorId -> m (Maybe TgtAndPath) -- | Picking the AI actor to move and refreshing leader and non-leader -- targets. module Game.LambdaHack.Client.AI.PickActorM -- | Pick a new leader from among the actors on the current level. Refresh -- the target of the new leader, even if unchanged. pickActorToMove :: MonadClient m => Maybe ActorId -> m ActorId -- | Inspect the tactics of the actor and set his target according to it. setTargetFromTactics :: MonadClient m => ActorId -> m () -- | AI procedure for picking the best action for an actor. module Game.LambdaHack.Client.AI.HandleAbilityM -- | Pick the most desirable AI ation for the actor. pickAction :: MonadClient m => ActorId -> Bool -> m RequestAnyAbility actionStrategy :: forall m. MonadClient m => ActorId -> Bool -> m (Strategy RequestAnyAbility) waitBlockNow :: MonadClient m => m (Strategy (RequestTimed 'AbWait)) pickup :: MonadClient m => ActorId -> Bool -> m (Strategy (RequestTimed 'AbMoveItem)) equipItems :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem)) toShare :: EqpSlot -> Bool yieldUnneeded :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem)) unEquipItems :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem)) groupByEqpSlot :: [(ItemId, ItemFullKit)] -> EnumMap EqpSlot [(ItemId, ItemFullKit)] bestByEqpSlot :: DiscoveryBenefit -> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)] -> [(EqpSlot, ([(Int, (ItemId, ItemFullKit))], [(Int, (ItemId, ItemFullKit))], [(Int, (ItemId, ItemFullKit))]))] harmful :: DiscoveryBenefit -> ItemId -> Bool meleeBlocker :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee)) meleeAny :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee)) trigger :: MonadClient m => ActorId -> FleeViaStairsOrEscape -> m (Strategy (RequestTimed 'AbAlter)) projectItem :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbProject)) data ApplyItemGroup applyItem :: MonadClient m => ActorId -> ApplyItemGroup -> m (Strategy (RequestTimed 'AbApply)) flee :: MonadClient m => ActorId -> [(Int, Point)] -> m (Strategy RequestAnyAbility) displaceFoe :: MonadClient m => ActorId -> m (Strategy RequestAnyAbility) displaceBlocker :: MonadClient m => ActorId -> Bool -> m (Strategy RequestAnyAbility) displaceTowards :: MonadClient m => ActorId -> Point -> Bool -> m (Strategy Vector) chase :: MonadClient m => ActorId -> Bool -> Bool -> m (Strategy RequestAnyAbility) moveTowards :: MonadClient m => ActorId -> Point -> Point -> Bool -> m (Strategy Vector) moveOrRunAid :: MonadClient m => ActorId -> Vector -> m (Maybe RequestAnyAbility) instance GHC.Classes.Eq Game.LambdaHack.Client.AI.HandleAbilityM.ApplyItemGroup -- | Ways for the client to use AI to produce server requests, based on the -- client's view of the game state. module Game.LambdaHack.Client.AI -- | Handle the move of an actor under AI control (regardless if the whole -- faction is under human or computer control). queryAI :: MonadClient m => ActorId -> m RequestAI -- | Pick an actor to move and an action for him to perform, given an -- optional previous candidate actor and action and the server-proposed -- actor. pickActorAndAction :: MonadClient m => Maybe (ActorId, RequestAnyAbility) -> ActorId -> m (ActorId, RequestAnyAbility, Maybe Point) -- | Abstract syntax of responses. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Client.Response -- | Abstract syntax of responses sent by server to an AI or UI client (or -- a universal client that can handle both roles, which is why this type -- is not separated into distinct AI and UI types). A response tells a -- client how to update game state or what information to send to the -- server. data Response -- | change State by performing this atomic update RespUpdAtomicNoState :: UpdAtomic -> Response -- | put the given State, which results from performing the atomic -- update RespUpdAtomic :: State -> UpdAtomic -> Response -- | compute an AI move for the actor and send (the semantics of) it RespQueryAI :: ActorId -> Response -- | perform special effects (animations, messages, etc.) RespSfxAtomic :: SfxAtomic -> Response -- | prompt the human player for a command and send (the semantics of) it RespQueryUI :: Response instance GHC.Show.Show Game.LambdaHack.Client.Response.Response -- | Handle atomic commands received by the client. module Game.LambdaHack.Client.HandleAtomicM -- | Client monad for saving and restarting games. class MonadClient m => MonadClientSetup m saveClient :: MonadClientSetup m => m () restartClient :: MonadClientSetup m => m () -- | Effect of atomic actions on client state. It is calculated with the -- global state from after the command is executed (except where the -- supplied oldState is used). cmdAtomicSemCli :: MonadClientSetup m => State -> UpdAtomic -> m () wipeBfsIfItemAffectsSkills :: MonadClient m => [CStore] -> ActorId -> m () tileChangeAffectsBfs :: COps -> ContentId TileKind -> ContentId TileKind -> Bool createActor :: MonadClient m => ActorId -> Actor -> [(ItemId, Item)] -> m () destroyActor :: MonadClient m => ActorId -> Actor -> Bool -> m () addItemToDiscoBenefit :: MonadClient m => ItemId -> m () perception :: MonadClient m => LevelId -> Perception -> Perception -> m () discoverKind :: MonadClient m => Container -> ItemKindIx -> ContentId ItemKind -> m () coverKind :: Container -> ItemKindIx -> ContentId ItemKind -> m () discoverSeed :: MonadClient m => Container -> ItemId -> ItemSeed -> m () coverSeed :: Container -> ItemId -> ItemSeed -> m () killExit :: MonadClient m => m () -- | Rectangular areas of levels and their basic operations. module Game.LambdaHack.Server.DungeonGen.Area -- | The type of areas. The bottom left and the top right points. data Area -- | Checks if it's an area with at least one field. toArea :: (X, Y, X, Y) -> Maybe Area fromArea :: Area -> (X, Y, X, Y) trivialArea :: Point -> Area isTrivialArea :: Area -> Bool mkFixed :: (X, Y) -> Area -> Point -> Area data SpecialArea SpecialArea :: Area -> SpecialArea SpecialFixed :: Point -> (GroupName PlaceKind) -> Area -> SpecialArea SpecialMerged :: SpecialArea -> Point -> SpecialArea -- | Divide uniformly a larger area into the given number of smaller areas -- overlapping at the edges. -- -- When a list of fixed centers (some important points inside) of -- (non-overlapping) areas is given, incorporate those, with as little -- disruption, as possible. grid :: EnumMap Point (GroupName PlaceKind) -> [Point] -> (X, Y) -> Area -> ((X, Y), EnumMap Point SpecialArea) -- | Shrink the given area on all fours sides by the amount. shrink :: Area -> Maybe Area expand :: Area -> Area sumAreas :: Area -> Area -> Area instance GHC.Show.Show Game.LambdaHack.Server.DungeonGen.Area.SpecialArea instance GHC.Classes.Eq Game.LambdaHack.Server.DungeonGen.Area.Area instance GHC.Show.Show Game.LambdaHack.Server.DungeonGen.Area.Area instance Data.Binary.Class.Binary Game.LambdaHack.Server.DungeonGen.Area.Area -- | 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 Point -- | Create a void room, i.e., a single point area within the designated -- area. mkVoidRoom :: Area -> Rnd Area -- | Create a random room according to given parameters. mkRoom :: (X, Y) -> (X, Y) -> 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 :: EnumSet Point -> (X, Y) -> Rnd [(Point, Point)] -- | Pick a single random connection between adjacent areas within a grid. randomConnection :: (X, Y) -> Rnd (Point, Point) -- | The choice of horizontal and vertical orientation. data HV Horiz :: HV Vert :: HV -- | The coordinates of consecutive fields of a corridor. type Corridor = [Point] -- | Try to connect two interiors of places with a corridor. Choose -- entrances some steps away from the edges, if the place is big enough. -- Note that with pfence == FNone, the inner area considered is -- the strict interior of the place, without the outermost tiles. -- -- The corridor connects (touches) the inner areas and the turning point -- of the corridor (if any) is outside of the outer areas and inside the -- grid areas. connectPlaces :: (Area, Fence, Area) -> (Area, Fence, Area) -> Rnd (Maybe Corridor) connectGrid' :: EnumSet Point -> (X, Y) -> EnumSet Point -> EnumSet Point -> [(Point, Point)] -> Rnd [(Point, Point)] -- | Sort the sequence of two points, in the derived lexicographic order. sortPoint :: (Point, Point) -> (Point, Point) -- | Create a corridor, either horizontal or vertical, with a possible -- intermediate part that is in the opposite direction. There might not -- always exist a good intermediate point if the places are allowed to be -- close together and then we let the intermediate part degenerate. mkCorridor :: HV -> Point -> Bool -> Point -> Bool -> Area -> Rnd Corridor borderPlace :: Area -> Fence -> (Area, Area) instance GHC.Classes.Eq Game.LambdaHack.Server.DungeonGen.AreaRnd.HV -- | Generation of places from place kinds. module Game.LambdaHack.Server.DungeonGen.Place -- | The parameters of a place. All are immutable and rolled and fixed at -- the time when a place is generated. data Place Place :: ContentId PlaceKind -> Area -> Bool -> GroupName TileKind -> ContentId TileKind -> ContentId TileKind -> ContentId TileKind -> Place [qkind] :: Place -> ContentId PlaceKind [qarea] :: Place -> Area [qseen] :: Place -> Bool [qlegend] :: Place -> GroupName TileKind [qFWall] :: Place -> ContentId TileKind [qFFloor] :: Place -> ContentId TileKind [qFGround] :: Place -> ContentId TileKind -- | 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 TileMapEM = EnumMap Point (ContentId 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. placeCheck :: Area -> PlaceKind -> Bool -- | Given a few parameters, roll and construct a Place -- datastructure and fill a cave section acccording to it. buildPlace :: COps -> CaveKind -> Bool -> ContentId TileKind -> ContentId TileKind -> AbsDepth -> AbsDepth -> Int -> Area -> Maybe (GroupName PlaceKind) -> Rnd (TileMapEM, Place) isChancePos :: Int -> Int -> Point -> Bool -- | Construct a fence around an area, with the given tile group. buildFenceRnd :: COps -> GroupName TileKind -> Area -> Rnd TileMapEM -- | Calculate interior room area according to fence type, based on the -- total area for the room and it's fence. This is used for checking if -- the room fits in the area, for digging up the place and the fence and -- for deciding if the room is dark or lit later in the dungeon -- generation process. interiorArea :: PlaceKind -> Area -> Maybe Area -- | Roll a legend of a place plan: a map from plan symbols to tile kinds. olegend :: COps -> GroupName TileKind -> Rnd (EnumMap Char (Int, ContentId TileKind), EnumMap Char (ContentId TileKind)) ooverride :: COps -> [(Char, GroupName TileKind)] -> Rnd (EnumMap Char (Int, ContentId TileKind), EnumMap Char (ContentId TileKind)) -- | Construct a fence around an area, with the given tile kind. buildFence :: ContentId TileKind -> Area -> TileMapEM -- | Create a place by tiling patterns. tilePlace :: Area -> PlaceKind -> Rnd (EnumMap Point Char) instance GHC.Show.Show Game.LambdaHack.Server.DungeonGen.Place.Place instance Data.Binary.Class.Binary Game.LambdaHack.Server.DungeonGen.Place.Place -- | Generation of caves (not yet inhabited dungeon levels) from cave -- kinds. module Game.LambdaHack.Server.DungeonGen.Cave -- | The type of caves (not yet inhabited dungeon levels). data Cave Cave :: ContentId CaveKind -> Int -> TileMapEM -> [Place] -> Bool -> Cave -- | the kind of the cave [dkind] :: Cave -> ContentId CaveKind -- | secret tile seed [dsecret] :: Cave -> Int -- | tile kinds in the cave [dmap] :: Cave -> TileMapEM -- | places generated in the cave [dplaces] :: Cave -> [Place] -- | whether the cave is dark [dnight] :: Cave -> Bool anchorDown :: Y bootFixedCenters :: CaveKind -> [Point] -- | Generate a cave using an algorithm inspired by the original Rogue, as -- follows (in gross simplification): -- -- buildCave :: COps -> AbsDepth -> AbsDepth -> Int -> ContentId CaveKind -> EnumMap Point (GroupName PlaceKind) -> Rnd Cave pickOpening :: COps -> CaveKind -> TileMapEM -> ContentId TileKind -> Int -> Point -> (ContentId TileKind, ContentId TileKind) -> Rnd (ContentId TileKind) digCorridors :: ContentId TileKind -> Corridor -> TileMapEM instance GHC.Show.Show Game.LambdaHack.Server.DungeonGen.Cave.Cave -- | The dungeon generation routine. It creates empty dungeons, without -- actors and without items, either lying on the floor or embedded inside -- tiles. module Game.LambdaHack.Server.DungeonGen -- | Freshly generated and not yet populated dungeon. data FreshDungeon FreshDungeon :: Dungeon -> AbsDepth -> FreshDungeon -- | maps for all levels [freshDungeon] :: FreshDungeon -> Dungeon -- | absolute dungeon depth [freshTotalDepth] :: FreshDungeon -> AbsDepth -- | Generate the dungeon for a new game. dungeonGen :: COps -> Caves -> Rnd FreshDungeon convertTileMaps :: COps -> Bool -> Rnd (ContentId TileKind) -> Maybe (Rnd (ContentId TileKind)) -> Int -> Int -> TileMapEM -> Rnd TileMap buildTileMap :: COps -> Cave -> Rnd TileMap buildLevel :: COps -> Int -> GroupName CaveKind -> Int -> AbsDepth -> [Point] -> Rnd (Level, [Point]) placeDownStairs :: CaveKind -> [Point] -> Rnd Point levelFromCaveKind :: COps -> ContentId CaveKind -> AbsDepth -> TileMap -> ([Point], [Point]) -> [Point] -> Bool -> Level -- | 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.FovDigital -- | Calculates the list of tiles, in Bump coordinates, visible -- from (0, 0), within the given sight range. scan :: EnumSet Point -> Distance -> Array Bool -> (Bump -> Point) -> EnumSet Point -- | 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. data Bump B :: Int -> Int -> Bump [bx] :: Bump -> Int [by] :: Bump -> Int -- | 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 -- | Straight line between points. data Line Line :: Bump -> Bump -> Line -- | 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) -- | 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 -> Ordering -- | 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 -> Ordering) -> Bump -> ConvexHull -> ConvexHull -- | 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 -> Ordering -- | 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 -> Ordering -- | Debug: check if a view border line for DFOV is legal. _debugLine :: Line -> (Bool, String) instance GHC.Show.Show Game.LambdaHack.Server.FovDigital.Line instance GHC.Show.Show Game.LambdaHack.Server.FovDigital.Bump -- | Field Of View scanning. -- -- See https://github.com/LambdaHack/LambdaHack/wiki/Fov-and-los -- for discussion. module Game.LambdaHack.Server.Fov data FovValid a FovValid :: a -> FovValid a FovInvalid :: FovValid a -- | Main perception validity map, for all factions. type PerValidFid = EnumMap FactionId (EnumMap LevelId Bool) -- | Visually reachable positions (light passes through them to the actor). -- They need to be intersected with lucid positions to obtain visible -- positions. newtype PerReachable PerReachable :: EnumSet Point -> PerReachable [preachable] :: PerReachable -> EnumSet Point data CacheBeforeLucid CacheBeforeLucid :: PerReachable -> PerVisible -> PerSmelled -> CacheBeforeLucid [creachable] :: CacheBeforeLucid -> PerReachable [cnocto] :: CacheBeforeLucid -> PerVisible [csmell] :: CacheBeforeLucid -> PerSmelled type PerActor = EnumMap ActorId (FovValid CacheBeforeLucid) data PerceptionCache PerceptionCache :: FovValid CacheBeforeLucid -> PerActor -> PerceptionCache [ptotal] :: PerceptionCache -> FovValid CacheBeforeLucid [perActor] :: PerceptionCache -> PerActor -- | Server cache of perceptions of a single faction, indexed by level -- identifier. type PerCacheLid = EnumMap LevelId PerceptionCache -- | Server cache of perceptions, indexed by faction identifier. type PerCacheFid = EnumMap FactionId PerCacheLid -- | Map from level positions that currently hold item or actor(s) with -- shine to the maximum of radiuses of the shining lights. -- -- Note that floor and (many projectile) actors light on a single tile -- should be additive for FovShine to be incrementally updated. -- -- FovShine should not even be kept in StateServer, -- because it's cheap to compute, compared to FovLucid and -- invalidated almost as often (not invalidated only by -- UpdAlterTile). newtype FovShine FovShine :: EnumMap Point Int -> FovShine [fovShine] :: FovShine -> EnumMap Point Int -- | Level positions with either ambient light or shining items or actors. newtype FovLucid FovLucid :: EnumSet Point -> FovLucid [fovLucid] :: FovLucid -> EnumSet Point type FovLucidLid = EnumMap LevelId (FovValid FovLucid) -- | Level positions that pass through light and vision. newtype FovClear FovClear :: Array Bool -> FovClear [fovClear] :: FovClear -> Array Bool type FovClearLid = EnumMap LevelId FovClear -- | Level positions with tiles that have ambient light. newtype FovLit FovLit :: EnumSet Point -> FovLit [fovLit] :: FovLit -> EnumSet Point type FovLitLid = EnumMap LevelId FovLit -- | Compute positions visible (reachable and seen) by the party. A -- position is lucid, if it's lit by an ambient light or by a weak, -- portable light source, e.g,, carried by an actor. A reachable and -- lucid position is visible. Additionally, positions directly adjacent -- to an actor are assumed to be visible to him (through sound, touch, -- noctovision, whatever). perceptionFromPTotal :: FovLucid -> CacheBeforeLucid -> Perception perActorFromLevel :: PerActor -> (ActorId -> Actor) -> ActorAspect -> FovClear -> PerActor boundSightByCalm :: Int -> Int64 -> Int totalFromPerActor :: PerActor -> CacheBeforeLucid -- | Update lights on the level. This is needed every (even enemy) actor -- move to show thrown torches. We need to update lights even if cmd -- doesn't change any perception, so that for next cmd that does, but -- doesn't change lights, and operates on the same level, the lights are -- up to date. We could make lights lazy to ensure no computation is -- wasted, but it's rare that cmd changed them, but not the perception -- (e.g., earthquake in an uninhabited corner of the active arena, but -- the we'd probably want some feedback, at least sound). lucidFromLevel :: FovClearLid -> FovLitLid -> State -> LevelId -> Level -> FovLucid -- | Calculate the perception and its caches for the whole dungeon. perFidInDungeon :: State -> (FovLitLid, FovClearLid, FovLucidLid, PerValidFid, PerCacheFid, PerFid) -- | Compute positions reachable by the actor. Reachable are all fields on -- a visually unblocked path from the actor position. Also compute -- positions seen by noctovision and perceived by smell. cacheBeforeLucidFromActor :: FovClear -> Actor -> AspectRecord -> CacheBeforeLucid shineFromLevel :: State -> LevelId -> Level -> FovShine floorLightSources :: DiscoveryAspect -> Level -> [(Point, Int)] -- | Compute all dynamically lit positions on a level, whether lit by -- actors or shining floor items. Note that an actor can be blind, in -- which case he doesn't see his own light (but others, from his or other -- factions, possibly do). lucidFromItems :: FovClear -> [(Point, Int)] -> [FovLucid] litFromLevel :: COps -> Level -> FovLit litInDungeon :: State -> FovLitLid clearFromLevel :: COps -> Level -> FovClear clearInDungeon :: State -> FovClearLid lucidInDungeon :: FovClearLid -> FovLitLid -> State -> FovLucidLid -- | Calculate perception of a faction. perLidFromFaction :: FovLucidLid -> FovClearLid -> FactionId -> State -> (PerLid, PerCacheLid) perceptionCacheFromLevel :: FovClearLid -> FactionId -> LevelId -> State -> PerceptionCache type Matrix = (Int, Int, Int, Int) -- | 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 -- is passed in the second argument. The actor's own position is -- considred reachable by him. fullscan :: FovClear -> Int -> Point -> EnumSet Point instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.FovLit instance GHC.Show.Show Game.LambdaHack.Server.Fov.FovLit instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.FovClear instance GHC.Show.Show Game.LambdaHack.Server.Fov.FovClear instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.FovLucid instance GHC.Show.Show Game.LambdaHack.Server.Fov.FovLucid instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.FovShine instance GHC.Show.Show Game.LambdaHack.Server.Fov.FovShine instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.PerceptionCache instance GHC.Show.Show Game.LambdaHack.Server.Fov.PerceptionCache instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.CacheBeforeLucid instance GHC.Show.Show Game.LambdaHack.Server.Fov.CacheBeforeLucid instance GHC.Classes.Eq Game.LambdaHack.Server.Fov.PerReachable instance GHC.Show.Show Game.LambdaHack.Server.Fov.PerReachable instance GHC.Classes.Eq a => GHC.Classes.Eq (Game.LambdaHack.Server.Fov.FovValid a) instance GHC.Show.Show a => GHC.Show.Show (Game.LambdaHack.Server.Fov.FovValid a) -- | Creation of items on the server. Types and operations that don't -- involve server state nor our custom monads. module Game.LambdaHack.Server.ItemRev -- | The essential item properties, used for the ItemRev hash -- table from items to their ids, needed to assign ids to newly generated -- items. All the other meaningul properties can be derived from them. -- Note 1: jlid is not meaningful; it gets forgotten if items -- from different levels roll the same random properties and so are -- merged. However, the first item generated by the server wins, which in -- case of normal items (not organs), is most of the time the lower -- absolute jlid (shallower depth) item, which makes sense for -- the client. Note 2: ItemSeed instead of AspectRecord -- is not enough, becaused different seeds may result in the same -- AspectRecord and we don't want such items to be distinct in -- UI and elsewhere. type ItemKnown = (ItemIdentity, AspectRecord, Maybe FactionId) -- | Reverse item map, for item creation, to keep items and item -- identifiers in bijection. type ItemRev = HashMap ItemKnown ItemId type UniqueSet = EnumSet (ContentId ItemKind) -- | Build an item with the given stats. buildItem :: COps -> FlavourMap -> DiscoveryKindRev -> ContentId ItemKind -> ItemKind -> LevelId -> Item -- | Generate an item based on level. newItem :: COps -> FlavourMap -> DiscoveryKindRev -> UniqueSet -> Freqs ItemKind -> Int -> LevelId -> AbsDepth -> AbsDepth -> Rnd (Maybe (ItemKnown, ItemFullKit, ItemSeed, GroupName ItemKind)) -- | The reverse map to DiscoveryKind, needed for item creation. -- This is total and never changes, hence implemented as vector. Morally, -- it's indexed by ContentId ItemKind and elements are -- ItemKindIx. data DiscoveryKindRev -- | The map of item ids to item seeds, needed for item creation. type ItemSeedDict = EnumMap ItemId ItemSeed emptyDiscoveryKindRev :: DiscoveryKindRev serverDiscos :: COps -> Rnd (DiscoveryKind, DiscoveryKindRev) -- | Flavours assigned by the server to item kinds, in this particular -- game. This is total and never changes, hence implemented as vector. -- Morally, it's indexed by ContentId ItemKind and elements are -- Flavour. data FlavourMap emptyFlavourMap :: FlavourMap -- | Randomly chooses flavour for all item kinds for this game. dungeonFlavourMap :: COps -> Rnd FlavourMap instance Data.Binary.Class.Binary Game.LambdaHack.Server.ItemRev.FlavourMap instance GHC.Show.Show Game.LambdaHack.Server.ItemRev.FlavourMap instance Data.Binary.Class.Binary Game.LambdaHack.Server.ItemRev.DiscoveryKindRev instance GHC.Show.Show Game.LambdaHack.Server.ItemRev.DiscoveryKindRev -- | Saving and restoring game state, used by both server and clients. module Game.LambdaHack.Common.Save type ChanSave a = MVar (Maybe a) saveToChan :: ChanSave a -> a -> IO () wrapInSaves :: Binary a => COps -> (a -> FilePath) -> (ChanSave a -> IO ()) -> IO () -- | Restore a saved game, if it exists. Initialize directory structure and -- copy over data files, if needed. restoreGame :: Binary a => COps -> FilePath -> IO (Maybe a) saveNameCli :: COps -> FactionId -> String saveNameSer :: COps -> String -- | Repeatedly save serialized snapshots of current state. loopSave :: Binary a => COps -> (a -> FilePath) -> ChanSave a -> IO () vExevLib :: COps -> (Version, Version) showVersion2 :: (Version, Version) -> Text delayPrint :: Text -> IO () -- | Client monad for interacting with a human through UI. module Game.LambdaHack.Client.UI.MonadClientUI -- | The monad that gives the client access to UI operations. class MonadClient m => MonadClientUI m getsSession :: MonadClientUI m => (SessionUI -> a) -> m a modifySession :: MonadClientUI m => (SessionUI -> SessionUI) -> m () liftIO :: MonadClientUI m => IO a -> m a clientPrintUI :: MonadClientUI m => Text -> m () -- | The row where the dungeon map starts. mapStartY :: Y getSession :: MonadClientUI m => m SessionUI putSession :: MonadClientUI m => SessionUI -> m () -- | Push frames or delays to the frame queue. The frames depict the -- lid level. displayFrames :: MonadClientUI m => LevelId -> Frames -> m () -- | Write FrontKey UI request to the frontend, read the reply, set -- pointer, return key. connFrontendFrontKey :: MonadClientUI m => [KM] -> FrameForall -> m KM setFrontAutoYes :: MonadClientUI m => Bool -> m () frontendShutdown :: MonadClientUI m => m () printScreen :: MonadClientUI m => m () -- | Initialize the frontend chosen by the player via client options. chanFrontend :: MonadClientUI m => ClientOptions -> m ChanFrontend anyKeyPressed :: MonadClientUI m => m Bool discardPressedKey :: MonadClientUI m => m () addPressedEsc :: MonadClientUI m => m () revCmdMap :: MonadClientUI m => m (KM -> HumanCmd -> KM) getReportUI :: MonadClientUI m => m Report getLeaderUI :: MonadClientUI m => m ActorId getArenaUI :: MonadClientUI m => m LevelId viewedLevelUI :: MonadClientUI m => m LevelId leaderTgtToPos :: MonadClientUI m => m (Maybe Point) xhairToPos :: MonadClientUI m => m (Maybe Point) clearXhair :: MonadClientUI m => m () clearAimMode :: MonadClientUI m => m () scoreToSlideshow :: MonadClientUI m => Int -> Status -> m Slideshow defaultHistory :: MonadClientUI m => Int -> m History tellAllClipPS :: MonadClientUI m => m () tellGameClipPS :: MonadClientUI m => m () elapsedSessionTimeGT :: MonadClientUI m => Int -> m Bool resetSessionStart :: MonadClientUI m => m () resetGameStart :: MonadClientUI m => m () -- | The part of speech describing the actor or "you" if a leader of the -- client's faction. The actor may be not present in the dungeon. partActorLeader :: MonadClientUI m => ActorId -> ActorUI -> m Part partActorLeaderFun :: MonadClientUI m => m (ActorId -> Part) -- | The part of speech with the actor's pronoun or "you" if a leader of -- the client's faction. The actor may be not present in the dungeon. partPronounLeader :: MonadClient m => ActorId -> ActorUI -> m Part -- | 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 :: MonadClientUI m => ActorId -> m Part -- | Try to read saved client game state from the file system. tryRestore :: MonadClientUI m => m (Maybe (StateClient, Maybe SessionUI)) leaderSkillsClientUI :: MonadClientUI m => m Skills -- | Write a UI request to the frontend and read a corresponding reply. connFrontend :: MonadClientUI m => FrontReq a -> m a displayFrame :: MonadClientUI m => Maybe FrameForall -> m () addPressedKey :: MonadClientUI m => KMP -> m () -- | Running and disturbance. -- -- The general rule is: whatever is behind you (and so ignored -- previously), determines what you ignore moving forward. This is -- calcaulated separately for the tiles to the left, to the right and in -- the middle along the running direction. So, if you want to ignore -- something start running when you stand on it (or to the right or left, -- respectively) or by entering it (or passing to the right or left, -- respectively). -- -- Some things are never ignored, such as: enemies seen, imporant -- messages heard, solid tiles and actors in the way. module Game.LambdaHack.Client.UI.RunM -- | Continue running in the given direction. continueRun :: MonadClientUI m => LevelId -> RunParams -> m (Either Text RequestAnyAbility) -- | 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. -- -- Note that while goto-xhair commands ignore items on the way, here we -- stop wnenever we touch an item. Running is more cautious to compensate -- that the player cannot specify the end-point of running. It's also -- more suited to open, already explored terrain. Goto-xhair works better -- with unknown terrain, e.g., it stops whenever an item is spotted, but -- then ignores the item, leaving it to the player to mark the item -- position as a goal of the next goto. continueRunDir :: MonadClientUI m => RunParams -> m (Either Text Vector) enterableDir :: COps -> Level -> Point -> Vector -> Bool tryTurning :: MonadClient m => ActorId -> m (Either Text Vector) checkAndRun :: MonadClient m => ActorId -> Vector -> m (Either Text Vector) -- | Monadic operations on game messages. module Game.LambdaHack.Client.UI.MsgM -- | Add a message to the current report. msgAddDuplicate :: MonadClientUI m => Text -> m Bool -- | Add a message to the current report. Do not report if it was a -- duplicate. msgAdd :: MonadClientUI m => Text -> m () -- | Add a prompt to the current report. promptAddDuplicate :: MonadClientUI m => Text -> Int -> m Bool -- | Add a prompt to the current report. Do not report if it was a -- duplicate. promptAdd1 :: MonadClientUI m => Text -> m () -- | Add a prompt to the current report with 0 copies for the purpose of -- collating cuplicates. Do not report if it was a duplicate. promptAdd0 :: MonadClientUI m => Text -> m () -- | Add a prompt with basic keys description. promptMainKeys :: MonadClientUI m => m () -- | Store new report in the history and archive old report. recordHistory :: MonadClientUI m => m () -- | Display game data on the screen using one of the available frontends -- (determined at compile time with cabal flags). module Game.LambdaHack.Client.UI.DrawM targetDescLeader :: MonadClientUI m => ActorId -> m (Maybe Text, Maybe Text) -- | Draw the whole screen: level map and status area. drawBaseFrame :: MonadClientUI m => ColorMode -> LevelId -> m FrameForall targetDesc :: MonadClientUI m => Maybe Target -> m (Maybe Text, Maybe Text) targetDescXhair :: MonadClientUI m => m (Text, Maybe Text) drawFrameTerrain :: forall m. MonadClientUI m => LevelId -> m FrameForall drawFrameContent :: forall m. MonadClientUI m => LevelId -> m FrameForall drawFramePath :: forall m. MonadClientUI m => LevelId -> m FrameForall drawFrameActor :: forall m. MonadClientUI m => LevelId -> m FrameForall drawFrameExtra :: forall m. MonadClientUI m => ColorMode -> LevelId -> m FrameForall drawFrameStatus :: MonadClientUI m => LevelId -> m AttrLine drawArenaStatus :: COps -> Level -> Int -> AttrLine drawLeaderStatus :: MonadClientUI m => Int -> m AttrLine drawLeaderDamage :: MonadClientUI m => Int -> m AttrLine drawSelected :: MonadClientUI m => LevelId -> Int -> EnumSet ActorId -> m (Int, AttrLine) -- | A set of Frame monad operations. module Game.LambdaHack.Client.UI.FrameM -- | Push the frame depicting the current level to the frame queue. Only -- one line of the report is shown, as in animations, because it may not -- be our turn, so we can't clear the message to see what is underneath. pushFrame :: MonadClientUI m => m () promptGetKey :: MonadClientUI m => ColorMode -> Overlay -> Bool -> [KM] -> m KM stopPlayBack :: MonadClientUI m => m () -- | Render and display animations on top of the current screen frame. animate :: MonadClientUI m => LevelId -> Animation -> m () fadeOutOrIn :: MonadClientUI m => Bool -> m () -- | Draw the current level with the overlay on top. If the overlay is too -- long, it's truncated. Similarly, for each line of the overlay, if it's -- too wide, it's truncated. drawOverlay :: MonadClientUI m => ColorMode -> Bool -> Overlay -> LevelId -> m FrameForall -- | Render animations on top of the current screen frame. renderFrames :: MonadClientUI m => LevelId -> Animation -> m Frames -- | Monadic operations on slideshows and related data. module Game.LambdaHack.Client.UI.SlideshowM -- | Add current report to the overlay, split the result and produce, -- possibly, many slides. overlayToSlideshow :: MonadClientUI m => Y -> [KM] -> OKX -> m Slideshow -- | Split current report into a slideshow. reportToSlideshow :: MonadClientUI m => [KM] -> m Slideshow -- | Split current report into a slideshow. Keep report unchanged. reportToSlideshowKeep :: MonadClientUI m => [KM] -> m Slideshow -- | Display a message. Return value indicates if the player wants to -- continue. Feature: if many pages, only the last SPACE exits (but first -- ESC). displaySpaceEsc :: MonadClientUI m => ColorMode -> Text -> m Bool -- | Display a message. Ignore keypresses. Feature: if many pages, only the -- last SPACE exits (but first ESC). displayMore :: MonadClientUI m => ColorMode -> Text -> m () displayMoreKeep :: MonadClientUI m => ColorMode -> Text -> m () -- | 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 -> Text -> m Bool getConfirms :: MonadClientUI m => ColorMode -> [KM] -> Slideshow -> m KM -- | Display a, potentially, multi-screen menu and return the chosen key or -- item slot label (and the index in the whole menu so that the cursor -- can again be placed at that spot next time menu is displayed). -- -- This function is the only source of menus and so, effectively, UI -- modes. displayChoiceScreen :: forall m. MonadClientUI m => String -> ColorMode -> Bool -> Slideshow -> [KM] -> m (Either KM SlotChar) -- | Helper functions for both inventory management and human commands. module Game.LambdaHack.Client.UI.HandleHelperM -- | Message describing the cause of failure of human command. data FailError showFailError :: FailError -> Text type MError = Maybe FailError mergeMError :: MError -> MError -> MError type FailOrCmd a = Either FailError a failWith :: MonadClientUI m => Text -> m (FailOrCmd a) failSer :: MonadClientUI m => ReqFailure -> m (FailOrCmd a) failMsg :: MonadClientUI m => Text -> m MError weaveJust :: FailOrCmd a -> Either MError a ppSLore :: SLore -> Text loreFromMode :: ItemDialogMode -> SLore loreFromContainer :: ItemKind -> Container -> SLore sortSlots :: MonadClientUI m => FactionId -> Maybe Actor -> m () -- | Switches current member to the next on the level, if any, wrapping. memberCycle :: MonadClientUI m => Bool -> m MError -- | Switches current member to the previous in the whole dungeon, -- wrapping. memberBack :: MonadClientUI m => Bool -> m MError partyAfterLeader :: MonadClientUI m => ActorId -> m [(ActorId, Actor, ActorUI)] -- | Select a faction leader. False, if nothing to do. pickLeader :: MonadClientUI m => Bool -> ActorId -> m Bool pickLeaderWithPointer :: MonadClientUI m => m MError itemOverlay :: MonadClientUI m => SingleItemSlots -> LevelId -> ItemBag -> m OKX statsOverlay :: MonadClient m => ActorId -> m OKX pickNumber :: MonadClientUI m => Bool -> Int -> m (Either MError Int) -- | Produces a textual description of the tile at a position. lookAtTile :: MonadClientUI m => Bool -> Point -> ActorId -> LevelId -> m Text -- | Produces a textual description of actors at a position. lookAtActors :: MonadClientUI m => Point -> LevelId -> m Text -- | Produces a textual description of items at a position. lookAtItems :: MonadClientUI m => Bool -> Point -> ActorId -> m Text instance GHC.Show.Show Game.LambdaHack.Client.UI.HandleHelperM.FailError -- | UI of inventory management. module Game.LambdaHack.Client.UI.InventoryM data Suitability SuitsEverything :: Suitability SuitsSomething :: (ItemFull -> ItemQuant -> Bool) -> Suitability -- | Let the human player choose a single, preferably suitable, item from a -- list of items. Don't display stores empty for all actors. Start with a -- non-empty store. getFull :: MonadClientUI m => m Suitability -> (Actor -> ActorUI -> AspectRecord -> ItemDialogMode -> Text) -> (Actor -> ActorUI -> AspectRecord -> ItemDialogMode -> Text) -> [CStore] -> [CStore] -> Bool -> Bool -> m (Either Text ([(ItemId, ItemFullKit)], (ItemDialogMode, Either KM SlotChar))) -- | Let a human player choose any item from a given group. Note that this -- does not guarantee the chosen item belongs to the group, as the player -- can override the choice. Used e.g., for applying and projecting. getGroupItem :: MonadClientUI m => m Suitability -> Text -> Text -> [CStore] -> [CStore] -> m (Either Text ((ItemId, ItemFull), (ItemDialogMode, Either KM SlotChar))) -- | Display all items from a store and let the human player choose any or -- switch to any other store. Used, e.g., for viewing inventory and item -- descriptions. getStoreItem :: MonadClientUI m => (Actor -> ActorUI -> AspectRecord -> ItemDialogMode -> Text) -> ItemDialogMode -> m (Either Text (ItemId, ItemBag, SingleItemSlots), (ItemDialogMode, Either KM SlotChar)) ppItemDialogMode :: ItemDialogMode -> (Text, Text) ppItemDialogModeFrom :: ItemDialogMode -> Text instance GHC.Classes.Eq Game.LambdaHack.Client.UI.InventoryM.ItemDialogState instance GHC.Show.Show Game.LambdaHack.Client.UI.InventoryM.ItemDialogState -- | Semantics of Game.LambdaHack.Client.UI.HumanCmd client commands -- that do not return server requests,, but only change internal client -- state. None of such commands takes game time. module Game.LambdaHack.Client.UI.HandleHumanLocalM macroHuman :: MonadClientUI m => [String] -> m () sortSlotsHuman :: MonadClientUI m => m () -- | Display items from a given container store and possibly let the user -- chose one. chooseItemHuman :: MonadClientUI m => ItemDialogMode -> m MError chooseItemDialogMode :: MonadClientUI m => ItemDialogMode -> m (FailOrCmd ItemDialogMode) chooseItemProjectHuman :: forall m. MonadClientUI m => [TriggerItem] -> m MError chooseItemApplyHuman :: forall m. MonadClientUI m => [TriggerItem] -> m MError -- | On top of permittedProjectClient, it also checks LOS, -- legality of aiming at the target, projection range. psuitReq :: MonadClientUI m => m (Either Text (ItemFull -> Either ReqFailure (Point, Bool))) triggerSymbols :: [TriggerItem] -> [Char] permittedApplyClient :: MonadClientUI m => m (ItemFull -> ItemQuant -> Either ReqFailure Bool) pickLeaderHuman :: MonadClientUI m => Int -> m MError pickLeaderWithPointerHuman :: MonadClientUI m => m MError -- | Switch current member to the next on the viewed level, if any, -- wrapping. memberCycleHuman :: MonadClientUI m => m MError -- | Switch current member to the previous in the whole dungeon, wrapping. memberBackHuman :: MonadClientUI m => m MError selectActorHuman :: MonadClientUI m => m () selectNoneHuman :: MonadClientUI m => m () selectWithPointerHuman :: MonadClientUI m => m MError repeatHuman :: MonadClientUI m => Int -> m () recordHuman :: MonadClientUI m => m () historyHuman :: forall m. MonadClientUI m => m () markVisionHuman :: MonadClientUI m => m () markSmellHuman :: MonadClientUI m => m () markSuspectHuman :: MonadClientUI m => m () printScreenHuman :: MonadClientUI m => m () -- | End aiming mode, rejecting the current position. cancelHuman :: MonadClientUI m => m () -- | Accept the current x-hair position as target, ending aiming mode, if -- active. acceptHuman :: MonadClientUI m => m () tgtClearHuman :: MonadClientUI m => m () itemClearHuman :: MonadClientUI m => m () -- | Move the xhair. Assumes aiming mode. moveXhairHuman :: MonadClientUI m => Vector -> Int -> m MError -- | Start aiming. aimTgtHuman :: MonadClientUI m => m MError -- | Cycle aiming mode. Do not change position of the xhair, switch among -- things at that position. aimFloorHuman :: MonadClientUI m => m () aimEnemyHuman :: MonadClientUI m => m () aimItemHuman :: MonadClientUI m => m () -- | Change the displayed level in aiming mode to (at most) k levels -- shallower. Enters aiming mode, if not already in one. aimAscendHuman :: MonadClientUI m => Int -> m MError -- | Tweak the eps parameter of the aiming digital line. epsIncrHuman :: MonadClientUI m => Bool -> m () xhairUnknownHuman :: MonadClientUI m => m MError xhairItemHuman :: MonadClientUI m => m MError xhairStairHuman :: MonadClientUI m => Bool -> m MError xhairPointerFloorHuman :: MonadClientUI m => m () xhairPointerEnemyHuman :: MonadClientUI m => m () aimPointerFloorHuman :: MonadClientUI m => m () aimPointerEnemyHuman :: MonadClientUI m => m () permittedProjectClient :: MonadClientUI m => m (ItemFull -> Either ReqFailure Bool) projectCheck :: MonadClientUI m => Point -> m (Maybe ReqFailure) -- | Check whether one is permitted to aim (for projecting) at a target -- (this is only checked for actor targets so that the player doesn't -- miss enemy getting out of sight; but for positions we let player shoot -- at obstacles, e.g., to destroy them, and shoot at a lying item and -- then at its posision, after enemy picked up the item). Returns a -- different seps if needed to reach the target actor. -- -- Note: Perception is not enough for the check, because the target actor -- can be obscured by a glass wall or be out of sight range, but in -- weapon range. xhairLegalEps :: MonadClientUI m => m (Either Text Int) posFromXhair :: MonadClientUI m => m (Either Text Point) selectAid :: MonadClientUI m => ActorId -> m () -- | End aiming mode, accepting the current position. endAiming :: MonadClientUI m => m () endAimingMsg :: MonadClientUI m => m () -- | Perform look around in the current position of the xhair. Does nothing -- outside aiming mode. doLook :: MonadClientUI m => m () flashAiming :: MonadClientUI m => m () xhairPointerFloor :: MonadClientUI m => Bool -> m () xhairPointerEnemy :: MonadClientUI m => Bool -> m () -- | Display atomic commands received by the client. module Game.LambdaHack.Client.UI.DisplayAtomicM -- | Visualize atomic updates sent to the client. This is done in the -- global state after the command is executed and after the client state -- is modified by the command. displayRespUpdAtomicUI :: MonadClientUI m => Bool -> UpdAtomic -> m () -- | Display special effects (text, animation) sent to the client. displayRespSfxAtomicUI :: MonadClientUI m => Bool -> SfxAtomic -> m () updateItemSlot :: MonadClientUI m => Container -> ItemId -> m () markDisplayNeeded :: MonadClientUI m => LevelId -> m () lookAtMove :: MonadClientUI m => ActorId -> m () actorVerbMU :: MonadClientUI m => ActorId -> ActorUI -> Part -> m () aidVerbMU :: MonadClientUI m => ActorId -> Part -> m () aidVerbDuplicateMU :: MonadClientUI m => ActorId -> Part -> m Bool itemVerbMU :: MonadClientUI m => ItemId -> ItemQuant -> Part -> Container -> m () itemAidVerbMU :: MonadClientUI m => ActorId -> Part -> ItemId -> Either (Maybe Int) Int -> CStore -> m () createActorUI :: MonadClientUI m => Bool -> ActorId -> Actor -> m () destroyActorUI :: MonadClientUI m => Bool -> ActorId -> Actor -> m () spotItem :: MonadClientUI m => Bool -> ItemId -> ItemQuant -> Container -> m () moveActor :: MonadClientUI m => ActorId -> Point -> Point -> m () displaceActorUI :: MonadClientUI m => ActorId -> ActorId -> m () moveItemUI :: MonadClientUI m => ItemId -> Int -> ActorId -> CStore -> CStore -> m () quitFactionUI :: MonadClientUI m => FactionId -> Maybe Status -> m () discover :: MonadClientUI m => Container -> ItemId -> m () ppSfxMsg :: MonadClientUI m => SfxMsg -> m Text strike :: MonadClientUI m => Bool -> ActorId -> ActorId -> ItemId -> CStore -> m () -- | Semantics of Game.LambdaHack.Client.UI.HumanCmd client commands -- that return server requests. A couple of them do not take time, the -- rest does. Here prompts and menus are displayed, but any feedback -- resulting from the commands (e.g., from inventory manipulation) is -- generated later on, by the server, for all clients that witness the -- results of the commands. module Game.LambdaHack.Client.UI.HandleHumanGlobalM -- | Pick command depending on area the mouse pointer is in. The first -- matching area is chosen. If none match, only interrupt. byAreaHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> [(CmdArea, HumanCmd)] -> m (Either MError ReqUI) byAimModeHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) -> m (Either MError ReqUI) composeIfLocalHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) -> m (Either MError ReqUI) composeUnlessErrorHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) -> m (Either MError ReqUI) compose2ndLocalHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) -> m (Either MError ReqUI) loopOnNothingHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) executeIfClearHuman :: MonadClientUI m => m (Either MError ReqUI) -> m (Either MError ReqUI) -- | Leader waits a turn (and blocks, etc.). waitHuman :: MonadClientUI m => m (RequestTimed 'AbWait) -- | Leader waits a 1/10th of a turn (and doesn't block, etc.). waitHuman10 :: MonadClientUI m => m (RequestTimed 'AbWait) moveRunHuman :: MonadClientUI m => Bool -> Bool -> Bool -> Bool -> Vector -> m (FailOrCmd RequestAnyAbility) runOnceAheadHuman :: MonadClientUI m => m (Either MError ReqUI) moveOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility) runOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility) continueToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility) moveItemHuman :: forall m. MonadClientUI m => [CStore] -> CStore -> Maybe Part -> Bool -> m (FailOrCmd (RequestTimed 'AbMoveItem)) projectHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbProject)) applyHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbApply)) -- | Ask for a direction and alter a tile in the specified way, if -- possible. alterDirHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter)) -- | Try to alter a tile using a feature under the pointer. alterWithPointerHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter)) -- | Display command help. helpHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) -- | Display hint or, if already displayed, display help. hintHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) -- | Display the dashboard. dashboardHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) itemMenuHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) chooseItemMenuHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> ItemDialogMode -> m (Either MError ReqUI) -- | Display the main menu. mainMenuHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) -- | Display the settings menu. settingsMenuHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) -- | Display the challenges menu. challengesMenuHuman :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> m (Either MError ReqUI) gameScenarioIncr :: MonadClientUI m => m () gameDifficultyIncr :: MonadClientUI m => m () gameWolfToggle :: MonadClientUI m => m () gameFishToggle :: MonadClientUI m => m () gameRestartHuman :: MonadClientUI m => m (FailOrCmd ReqUI) gameExitHuman :: MonadClientUI m => m ReqUI gameSaveHuman :: MonadClientUI m => m ReqUI tacticHuman :: MonadClientUI m => m (FailOrCmd ReqUI) automateHuman :: MonadClientUI m => m (FailOrCmd ReqUI) areaToRectangles :: MonadClientUI m => CmdArea -> m [(X, Y, X, Y)] -- | Actor attacks an enemy actor or his own projectile. meleeAid :: MonadClientUI m => ActorId -> m (FailOrCmd (RequestTimed 'AbMelee)) -- | Actor swaps position with another. displaceAid :: MonadClientUI m => ActorId -> m (FailOrCmd (RequestTimed 'AbDisplace)) -- | Leader moves or searches or alters. No visible actor at the position. moveSearchAlter :: MonadClientUI m => Vector -> m (FailOrCmd RequestAnyAbility) goToXhair :: MonadClientUI m => Bool -> Bool -> m (FailOrCmd RequestAnyAbility) multiActorGoTo :: MonadClientUI m => LevelId -> Point -> RunParams -> m (FailOrCmd (Bool, Vector)) selectItemsToMove :: forall m. MonadClientUI m => [CStore] -> CStore -> Maybe Part -> Bool -> m (FailOrCmd (CStore, [(ItemId, ItemFullKit)])) moveItems :: forall m. MonadClientUI m => [CStore] -> (CStore, [(ItemId, ItemFullKit)]) -> CStore -> m (FailOrCmd (RequestTimed 'AbMoveItem)) projectItem :: MonadClientUI m => (CStore, (ItemId, ItemFull)) -> m (FailOrCmd (RequestTimed 'AbProject)) applyItem :: MonadClientUI m => (CStore, (ItemId, ItemFullKit)) -> m (FailOrCmd (RequestTimed 'AbApply)) -- | Try to alter a tile using a feature in the given direction. alterTile :: MonadClientUI m => [TriggerTile] -> Vector -> m (FailOrCmd (RequestTimed 'AbAlter)) -- | Try to alter a tile using a feature at the given position. -- -- We don't check if the tile is interesting, e.g., if any embedded item -- can be triggered, because the player explicitely requested the action. -- Consequently, even if all embedded items are recharching, the time -- will be wasted and the server will describe the failure in detail. alterTileAtPos :: MonadClientUI m => [TriggerTile] -> Point -> Text -> m (FailOrCmd (RequestTimed 'AbAlter)) -- | Verify important effects, such as fleeing the dungeon. -- -- This is contrived for now, the embedded items are not analyzed, but -- only recognized by name. verifyAlters :: MonadClientUI m => LevelId -> Point -> m (FailOrCmd ()) verifyEscape :: MonadClientUI m => m (FailOrCmd ()) -- | Guess and report why the bump command failed. guessAlter :: COps -> [TriggerTile] -> ContentId TileKind -> Text artWithVersion :: MonadClientUI m => m [String] generateMenu :: MonadClientUI m => (HumanCmd -> m (Either MError ReqUI)) -> [(KM, (Text, HumanCmd))] -> [String] -> String -> m (Either MError ReqUI) nxtGameMode :: COps -> Int -> ModeKind -- | Semantics of human player commands. module Game.LambdaHack.Client.UI.HandleHumanM -- | The semantics of human player commands in terms of the client monad. -- -- Some time cosuming commands are enabled even in aiming mode, but -- cannot be invoked in aiming mode on a remote level (level different -- than the level of the leader), which is caught here. cmdHumanSem :: MonadClientUI m => HumanCmd -> m (Either MError ReqUI) -- | Commands that are forbidden on a remote level, because they would -- usually take time when invoked on one, but not necessarily do what the -- player expects. Note that some commands that normally take time are -- not included, because they don't take time in aiming mode or their -- individual sanity conditions include a remote level check. noRemoteHumanCmd :: HumanCmd -> Bool cmdAction :: MonadClientUI m => HumanCmd -> m (Either MError ReqUI) addNoError :: Monad m => m () -> m (Either MError ReqUI) fmapTimedToUI :: Monad m => m (RequestTimed a) -> m ReqUI -- | Ways for the client to use player input via UI to produce server -- requests, based on the client's view (visualized for the player) of -- the game state. module Game.LambdaHack.Client.UI -- | Handle the move of a human player. queryUI :: MonadClientUI m => m RequestUI -- | The monad that gives the client access to UI operations. class MonadClient m => MonadClientUI m getsSession :: MonadClientUI m => (SessionUI -> a) -> m a modifySession :: MonadClientUI m => (SessionUI -> SessionUI) -> m () liftIO :: MonadClientUI m => IO a -> m a -- | The information that is used across a client playing session, -- including many consecutive games in a single session. Some of it is -- saved, some is reset when a new playing session starts. An important -- component is the frontend session. data SessionUI SessionUI :: Target -> ActorDictUI -> ItemSlots -> Maybe (CStore, CStore) -> ChanFrontend -> Binding -> UIOptions -> Maybe AimMode -> Bool -> Maybe (ItemId, CStore, Bool) -> EnumSet ActorId -> Maybe RunParams -> History -> Point -> LastRecord -> [KM] -> EnumSet ActorId -> Int -> Bool -> Bool -> Map String Int -> Bool -> HintMode -> Bool -> POSIXTime -> POSIXTime -> Time -> Int -> Int -> SessionUI -- | the common xhair [sxhair] :: SessionUI -> Target -- | assigned actor UI presentations [sactorUI] :: SessionUI -> ActorDictUI -- | map from slots to items [sslots] :: SessionUI -> ItemSlots -- | last item move stores [slastItemMove] :: SessionUI -> Maybe (CStore, CStore) -- | connection with the frontend [schanF] :: SessionUI -> ChanFrontend -- | binding of keys to commands [sbinding] :: SessionUI -> Binding -- | UI options as set by the player [sUIOptions] :: SessionUI -> UIOptions -- | aiming mode [saimMode] :: SessionUI -> Maybe AimMode -- | last mouse aiming not vacuus [sxhairMoused] :: SessionUI -> Bool -- | selected item, if any, it's store and whether to override suitability -- check [sitemSel] :: SessionUI -> Maybe (ItemId, CStore, Bool) -- | the set of currently selected actors [sselected] :: SessionUI -> EnumSet ActorId -- | parameters of the current run, if any [srunning] :: SessionUI -> Maybe RunParams -- | history of messages [shistory] :: SessionUI -> History -- | mouse pointer position [spointer] :: SessionUI -> Point -- | state of key sequence recording [slastRecord] :: SessionUI -> LastRecord -- | state of key sequence playback [slastPlay] :: SessionUI -> [KM] -- | actors that just got out of sight [slastLost] :: SessionUI -> EnumSet ActorId -- | player just waited this many times [swaitTimes] :: SessionUI -> Int -- | mark leader and party FOV [smarkVision] :: SessionUI -> Bool -- | mark smell, if the leader can smell [smarkSmell] :: SessionUI -> Bool -- | indices of last used menu items [smenuIxMap] :: SessionUI -> Map String Int -- | current level needs displaying [sdisplayNeeded] :: SessionUI -> Bool -- | how to show keys hints when no messages [shintMode] :: SessionUI -> HintMode -- | whether no report created last UI turn [sreportNull] :: SessionUI -> Bool -- | this session start time [sstart] :: SessionUI -> POSIXTime -- | this game start time [sgstart] :: SessionUI -> POSIXTime -- | clips from start of session to current game start [sallTime] :: SessionUI -> Time -- | this game current frame count [snframes] :: SessionUI -> Int -- | frame count from start of session to current game start [sallNframes] :: SessionUI -> Int -- | Visualize atomic updates sent to the client. This is done in the -- global state after the command is executed and after the client state -- is modified by the command. displayRespUpdAtomicUI :: MonadClientUI m => Bool -> UpdAtomic -> m () -- | Display special effects (text, animation) sent to the client. displayRespSfxAtomicUI :: MonadClientUI m => Bool -> SfxAtomic -> m () -- | Key-command mappings to be specified in content and used for the UI. data KeyKind -- | Options that affect the UI of the client. data UIOptions -- | Modify client options with UI options. applyUIOptions :: COps -> UIOptions -> ClientOptions -> ClientOptions -- | Hardwired commandline arguments to process. uCmdline :: UIOptions -> [String] -- | Read and parse UI config file. mkUIOptions :: COps -> Bool -> IO UIOptions -- | Connection channel between a frontend and a client. Frontend acts as a -- server, serving keys, etc., when given frames to display. data ChanFrontend -- | Initialize the frontend chosen by the player via client options. chanFrontend :: MonadClientUI m => ClientOptions -> m ChanFrontend -- | Add a message to the current report. Do not report if it was a -- duplicate. msgAdd :: MonadClientUI m => Text -> m () -- | Try to read saved client game state from the file system. tryRestore :: MonadClientUI m => m (Maybe (StateClient, Maybe SessionUI)) -- | Create binding of keys to movement and other standard commands, as -- well as commands defined in the config file. stdBinding :: KeyKind -> UIOptions -> Binding -- | Let the human player issue commands until any command takes time. humanCommand :: forall m. MonadClientUI m => m ReqUI -- | Semantics of responses sent by the server to clients. module Game.LambdaHack.Client.HandleResponseM -- | Client monad in which one can send requests to the client. class MonadClient m => MonadClientWriteRequest m sendRequestAI :: MonadClientWriteRequest m => RequestAI -> m () sendRequestUI :: MonadClientWriteRequest m => RequestUI -> m () clientHasUI :: MonadClientWriteRequest m => m Bool -- | Monad for executing atomic game state transformations on a client. class MonadClient m => MonadClientAtomic m -- | Execute an atomic update that changes the client's State. execUpdAtomic :: MonadClientAtomic m => UpdAtomic -> m () -- | Put state that is intended to be the result of performing an atomic -- update by the server on its copy of the client's State. execPutState :: MonadClientAtomic m => State -> m () -- | Handle server responses. -- -- Note that for clients communicating with the server over the net, -- RespUpdAtomicNoState should be used, because executing a -- single command is cheaper than sending the whole state over the net. -- However, for the standalone exe mode, with clients in the same process -- as the server, a pointer to the state set with execPutState -- is cheaper. handleResponse :: (MonadClientSetup m, MonadClientUI m, MonadClientAtomic m, MonadClientWriteRequest m) => Response -> m () -- | The main loop of the client, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Client.LoopM -- | Client monad in which one can receive responses from the server. class MonadClient m => MonadClientReadResponse m receiveResponse :: MonadClientReadResponse m => m Response -- | The main game loop for an AI or UI client. It receives responses from -- the server, changes internal client state accordingly, analyzes -- ensuing human or AI commands and sends resulting requests to the -- server. Depending on whether it's an AI or UI client, it sends AI or -- human player requests. -- -- The loop is started in client state that is empty except for the -- sside and seps fields, see emptyStateClient. loopCli :: (MonadClientSetup m, MonadClientUI m, MonadClientAtomic m, MonadClientReadResponse m, MonadClientWriteRequest m) => KeyKind -> UIOptions -> ClientOptions -> m () initAI :: MonadClient m => m () initUI :: MonadClientUI m => KeyKind -> UIOptions -> m () -- | Semantics of responses that are sent from server to clients, in terms -- of client state transformations, and semantics of human commands and -- AI moves, in terms of requests to be sent from the client to the -- server. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Client -- | The main game loop for an AI or UI client. It receives responses from -- the server, changes internal client state accordingly, analyzes -- ensuing human or AI commands and sends resulting requests to the -- server. Depending on whether it's an AI or UI client, it sends AI or -- human player requests. -- -- The loop is started in client state that is empty except for the -- sside and seps fields, see emptyStateClient. loopCli :: (MonadClientSetup m, MonadClientUI m, MonadClientAtomic m, MonadClientReadResponse m, MonadClientWriteRequest m) => KeyKind -> UIOptions -> ClientOptions -> m () -- | Requests sent by AI clients to the server. If faction leader is to be -- changed, it's included as the second component. type RequestAI = (ReqAI, Maybe ActorId) -- | Possible forms of requests sent by AI clients. data ReqAI ReqAINop :: ReqAI ReqAITimed :: RequestAnyAbility -> ReqAI -- | Requests sent by UI clients to the server. If faction leader is to be -- changed, it's included as the second component. type RequestUI = (ReqUI, Maybe ActorId) -- | Possible forms of requests sent by UI clients. data ReqUI ReqUINop :: ReqUI ReqUITimed :: RequestAnyAbility -> ReqUI ReqUIGameRestart :: (GroupName ModeKind) -> Challenge -> ReqUI ReqUIGameDropAndExit :: ReqUI ReqUIGameSaveAndExit :: ReqUI ReqUIGameSave :: ReqUI ReqUITactic :: Tactic -> ReqUI ReqUIAutomate :: ReqUI -- | Basic form of requests, sent by both AI and UI clients to the server. data RequestAnyAbility RequestAnyAbility :: (RequestTimed a) -> RequestAnyAbility -- | Requests that take game time, indexed by actor ability that is needed -- for performing the corresponding actions. data RequestTimed :: Ability -> * [ReqMove] :: Vector -> RequestTimed 'AbMove [ReqMelee] :: ActorId -> ItemId -> CStore -> RequestTimed 'AbMelee [ReqDisplace] :: ActorId -> RequestTimed 'AbDisplace [ReqAlter] :: Point -> RequestTimed 'AbAlter [ReqWait] :: RequestTimed 'AbWait [ReqWait10] :: RequestTimed 'AbWait [ReqMoveItems] :: [(ItemId, Int, CStore, CStore)] -> RequestTimed 'AbMoveItem [ReqProject] :: Point -> Int -> ItemId -> CStore -> RequestTimed 'AbProject [ReqApply] :: ItemId -> CStore -> RequestTimed 'AbApply -- | Abstract syntax of responses sent by server to an AI or UI client (or -- a universal client that can handle both roles, which is why this type -- is not separated into distinct AI and UI types). A response tells a -- client how to update game state or what information to send to the -- server. data Response -- | change State by performing this atomic update RespUpdAtomicNoState :: UpdAtomic -> Response -- | put the given State, which results from performing the atomic -- update RespUpdAtomic :: State -> UpdAtomic -> Response -- | compute an AI move for the actor and send (the semantics of) it RespQueryAI :: ActorId -> Response -- | perform special effects (animations, messages, etc.) RespSfxAtomic :: SfxAtomic -> Response -- | prompt the human player for a command and send (the semantics of) it RespQueryUI :: Response -- | Options that affect the behaviour of the client (but not game rules). data ClientOptions -- | Default value of client options. defClientOptions :: ClientOptions -- | Don't create directories and files and show time stats. sbenchmark :: ClientOptions -> Bool -- | Key-command mappings to be specified in content and used for the UI. data KeyKind -- | Options that affect the UI of the client. data UIOptions -- | Modify client options with UI options. applyUIOptions :: COps -> UIOptions -> ClientOptions -> ClientOptions -- | Hardwired commandline arguments to process. uCmdline :: UIOptions -> [String] -- | Read and parse UI config file. mkUIOptions :: COps -> Bool -> IO UIOptions -- | Server and client game state types and operations. module Game.LambdaHack.Server.ServerOptions -- | Options that affect the behaviour of the server (including game -- rules). data ServerOptions ServerOptions :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe (GroupName ModeKind) -> Bool -> Bool -> Maybe StdGen -> Maybe StdGen -> Bool -> Challenge -> Bool -> String -> Bool -> ClientOptions -> ServerOptions [sknowMap] :: ServerOptions -> Bool [sknowEvents] :: ServerOptions -> Bool [sknowItems] :: ServerOptions -> Bool [sniff] :: ServerOptions -> Bool [sallClear] :: ServerOptions -> Bool [sboostRandomItem] :: ServerOptions -> Bool [sgameMode] :: ServerOptions -> Maybe (GroupName ModeKind) [sautomateAll] :: ServerOptions -> Bool [skeepAutomated] :: ServerOptions -> Bool [sdungeonRng] :: ServerOptions -> Maybe StdGen [smainRng] :: ServerOptions -> Maybe StdGen [snewGameSer] :: ServerOptions -> Bool [scurChalSer] :: ServerOptions -> Challenge [sdumpInitRngs] :: ServerOptions -> Bool [ssavePrefixSer] :: ServerOptions -> String [sdbgMsgSer] :: ServerOptions -> Bool [sclientOptions] :: ServerOptions -> ClientOptions data RNGs RNGs :: Maybe StdGen -> Maybe StdGen -> RNGs [dungeonRandomGenerator] :: RNGs -> Maybe StdGen [startingRandomGenerator] :: RNGs -> Maybe StdGen -- | Default value of server options. defServerOptions :: ServerOptions instance GHC.Show.Show Game.LambdaHack.Server.ServerOptions.ServerOptions instance GHC.Show.Show Game.LambdaHack.Server.ServerOptions.RNGs instance Data.Binary.Class.Binary Game.LambdaHack.Server.ServerOptions.RNGs instance Data.Binary.Class.Binary Game.LambdaHack.Server.ServerOptions.ServerOptions -- | Server and client game state types and operations. module Game.LambdaHack.Server.State -- | State with server-specific data, including a copy of each client's -- basic game state, but not the server's basic state. data StateServer StateServer :: ActorTime -> EnumSet ActorId -> DiscoveryKindRev -> UniqueSet -> ItemSeedDict -> ItemRev -> FlavourMap -> ActorId -> ItemId -> EnumMap LevelId Int -> [CmdAtomic] -> EnumMap FactionId State -> PerFid -> PerValidFid -> PerCacheFid -> FovLucidLid -> FovClearLid -> FovLitLid -> [LevelId] -> Bool -> StdGen -> RNGs -> Bool -> Bool -> Bool -> ServerOptions -> ServerOptions -> StateServer -- | absolute times of next actions [sactorTime] :: StateServer -> ActorTime -- | actors currently in time stasis, invulnerable to time warps until move [sactorStasis] :: StateServer -> EnumSet ActorId -- | reverse map, used for item creation [sdiscoKindRev] :: StateServer -> DiscoveryKindRev -- | already generated unique items [suniqueSet] :: StateServer -> UniqueSet -- | map from item ids to item seeds [sitemSeedD] :: StateServer -> ItemSeedDict -- | 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 [snumSpawned] :: StateServer -> EnumMap LevelId Int -- | atomic commands performed to date [sundo] :: StateServer -> [CmdAtomic] -- | each faction state, as seen by clients [sclientStates] :: StateServer -> EnumMap FactionId State -- | perception of all factions [sperFid] :: StateServer -> PerFid -- | perception validity for all factions [sperValidFid] :: StateServer -> PerValidFid -- | perception cache of all factions [sperCacheFid] :: StateServer -> PerCacheFid -- | ambient or shining light positions [sfovLucidLid] :: StateServer -> FovLucidLid -- | clear tiles positions [sfovClearLid] :: StateServer -> FovClearLid -- | ambient light positions [sfovLitLid] :: StateServer -> FovLitLid -- | active arenas [sarenas] :: StateServer -> [LevelId] -- | whether active arenas valid [svalidArenas] :: StateServer -> Bool -- | current random generator [srandom] :: StateServer -> StdGen -- | initial random generators [srngs] :: StateServer -> RNGs -- | exit game loop after clip's end; usually no game save follows [sbreakLoop] :: StateServer -> Bool -- | exit game loop ASAP; usually with save [sbreakASAP] :: StateServer -> Bool -- | write savegame to file after loop exit [swriteSave] :: StateServer -> Bool -- | current commandline options [soptions] :: StateServer -> ServerOptions -- | options for the next game [soptionsNxt] :: StateServer -> ServerOptions -- | Position in time for each actor, grouped by level and by faction. type ActorTime = EnumMap FactionId (EnumMap LevelId (EnumMap ActorId Time)) -- | Initial, empty game server state. emptyStateServer :: StateServer updateActorTime :: FactionId -> LevelId -> ActorId -> Time -> ActorTime -> ActorTime ageActor :: FactionId -> LevelId -> ActorId -> Delta Time -> ActorTime -> ActorTime instance GHC.Show.Show Game.LambdaHack.Server.State.StateServer instance Data.Binary.Class.Binary Game.LambdaHack.Server.State.StateServer -- | Parsing of commandline arguments. module Game.LambdaHack.Server.Commandline -- | Parser for server options from commandline arguments. serverOptionsPI :: ParserInfo ServerOptions serverOptionsP :: Parser ServerOptions -- | Basic server monads and related operations. module Game.LambdaHack.Server.MonadServer class MonadStateRead m => MonadServer m getsServer :: MonadServer m => (StateServer -> a) -> m a modifyServer :: MonadServer m => (StateServer -> StateServer) -> m () chanSaveServer :: MonadServer m => m (ChanSave (State, StateServer)) liftIO :: MonadServer m => IO a -> m a -- | The monad for executing atomic game state transformations. class MonadServer m => MonadServerAtomic m -- | Execute an atomic command that changes the state on the server and on -- all clients that can notice it. execUpdAtomic :: MonadServerAtomic m => UpdAtomic -> m () -- | Execute an atomic command that changes the state on the server only. execUpdAtomicSer :: MonadServerAtomic m => UpdAtomic -> m Bool -- | Execute an atomic command that changes the state on the given single -- client only. execUpdAtomicFid :: MonadServerAtomic m => FactionId -> UpdAtomic -> m () -- | Execute an atomic command that changes the state on the given single -- client only. Catch AtomicFail and indicate if it was in fact -- raised. execUpdAtomicFidCatch :: MonadServerAtomic m => FactionId -> UpdAtomic -> m Bool -- | Execute an atomic command that only displays special effects. execSfxAtomic :: MonadServerAtomic m => SfxAtomic -> m () execSendPer :: MonadServerAtomic m => FactionId -> LevelId -> Perception -> Perception -> Perception -> m () getServer :: MonadServer m => m StateServer putServer :: MonadServer m => StateServer -> m () debugPossiblyPrint :: MonadServer m => Text -> m () debugPossiblyPrintAndExit :: MonadServer m => Text -> m () serverPrint :: MonadServer m => Text -> m () saveServer :: MonadServer m => m () -- | Dumps to stdout the RNG states from the start of the game. dumpRngs :: MonadServer m => RNGs -> m () -- | Read the high scores dictionary. Return the empty table if no file. restoreScore :: forall m. MonadServer m => COps -> m ScoreDict -- | Generate a new score, register it and save. registerScore :: MonadServer m => Status -> FactionId -> m () -- | Invoke pseudo-random computation with the generator kept in the state. rndToAction :: MonadServer m => Rnd a -> m a -- | Gets a random generator from the user-submitted options or, if not -- present, generates one. getSetGen :: MonadServer m => Maybe StdGen -> m StdGen -- | Server operations for items. module Game.LambdaHack.Server.ItemM registerItem :: MonadServerAtomic m => ItemFullKit -> ItemKnown -> ItemSeed -> Container -> Bool -> m ItemId embedItem :: MonadServerAtomic m => LevelId -> Point -> ContentId TileKind -> m () rollItem :: MonadServerAtomic m => Int -> LevelId -> Freqs ItemKind -> m (Maybe (ItemKnown, ItemFullKit, ItemSeed, GroupName ItemKind)) rollAndRegisterItem :: MonadServerAtomic m => LevelId -> Freqs ItemKind -> Container -> Bool -> Maybe Int -> m (Maybe (ItemId, (ItemFullKit, GroupName ItemKind))) placeItemsInDungeon :: forall m. MonadServerAtomic m => EnumMap LevelId [Point] -> m () embedItemsInDungeon :: MonadServerAtomic m => m () -- | Mapping over actor's items from a give store. mapActorCStore_ :: MonadServer m => CStore -> (ItemId -> ItemQuant -> m a) -> Actor -> m () onlyRegisterItem :: MonadServerAtomic m => ItemKnown -> ItemSeed -> m ItemId createLevelItem :: MonadServerAtomic m => Point -> LevelId -> m () -- | Handle atomic commands on the server, after they are executed to -- change server State and before they are sent to clients. module Game.LambdaHack.Server.HandleAtomicM -- | Effect of atomic actions on server state is calculated with the global -- state from after the command is executed (except where the supplied -- oldState is used). cmdAtomicSemSer :: MonadServer m => State -> UpdAtomic -> m () invalidateArenas :: MonadServer m => m () updateSclear :: MonadServer m => LevelId -> Point -> ContentId TileKind -> ContentId TileKind -> m Bool updateSlit :: MonadServer m => LevelId -> Point -> ContentId TileKind -> ContentId TileKind -> m Bool invalidateLucidLid :: MonadServer m => LevelId -> m () invalidateLucidAid :: MonadServer m => ActorId -> m () actorHasShine :: ActorAspect -> ActorId -> Bool itemAffectsShineRadius :: DiscoveryAspect -> ItemId -> [CStore] -> Bool itemAffectsPerRadius :: DiscoveryAspect -> ItemId -> Bool addPerActor :: MonadServer m => ActorId -> Actor -> m () addPerActorAny :: MonadServer m => ActorId -> Actor -> m () deletePerActor :: MonadServer m => ActorAspect -> ActorId -> Actor -> m () deletePerActorAny :: MonadServer m => ActorId -> Actor -> m () invalidatePerActor :: MonadServer m => ActorId -> m () reconsiderPerActor :: MonadServer m => ActorId -> m () invalidatePerLid :: MonadServer m => LevelId -> m () -- | Debug output for requests and responses. module Game.LambdaHack.Server.DebugM debugResponse :: MonadServer m => FactionId -> Response -> m () debugRequestAI :: MonadServer m => ActorId -> m () debugRequestUI :: MonadServer m => ActorId -> m () debugShow :: Show a => a -> Text debugPretty :: MonadServer m => FactionId -> Text -> UpdAtomic -> m () debugPlain :: MonadServer m => FactionId -> Text -> UpdAtomic -> m () data DebugAid DebugAid :: Text -> ActorId -> FactionId -> LevelId -> Int64 -> Time -> Time -> DebugAid [label] :: DebugAid -> Text [aid] :: DebugAid -> ActorId [faction] :: DebugAid -> FactionId [lid] :: DebugAid -> LevelId [bHP] :: DebugAid -> Int64 [btime] :: DebugAid -> Time [time] :: DebugAid -> Time debugAid :: MonadServer m => ActorId -> Text -> m Text instance GHC.Show.Show Game.LambdaHack.Server.DebugM.DebugAid -- | The server definitions for the server-client communication protocol. module Game.LambdaHack.Server.ProtocolM type CliSerQueue = MVar -- | Connection information for all factions, indexed by faction -- identifier. type ConnServerDict = EnumMap FactionId ChanServer -- | Connection channel between the server and a single client. data ChanServer ChanServer :: CliSerQueue Response -> CliSerQueue RequestAI -> Maybe (CliSerQueue RequestUI) -> ChanServer [responseS] :: ChanServer -> CliSerQueue Response [requestAIS] :: ChanServer -> CliSerQueue RequestAI [requestUIS] :: ChanServer -> Maybe (CliSerQueue RequestUI) -- | The server monad with the ability to communicate with clients. class MonadServer m => MonadServerReadRequest m getsDict :: MonadServerReadRequest m => (ConnServerDict -> a) -> m a modifyDict :: MonadServerReadRequest m => (ConnServerDict -> ConnServerDict) -> m () liftIO :: MonadServerReadRequest m => IO a -> m a putDict :: MonadServerReadRequest m => ConnServerDict -> m () -- | If the AtomicFail conditions hold, send a command to client, -- otherwise do nothing. sendUpdate :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> UpdAtomic -> m () -- | Send a command to client, crashing if the AtomicFail -- conditions don't hold when executed on the client's state. sendUpdateCheck :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> UpdAtomic -> m () sendUpdNoState :: MonadServerReadRequest m => FactionId -> UpdAtomic -> m () sendSfx :: MonadServerReadRequest m => FactionId -> SfxAtomic -> m () sendQueryAI :: MonadServerReadRequest m => FactionId -> ActorId -> m RequestAI sendQueryUI :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> ActorId -> m RequestUI killAllClients :: (MonadServerAtomic m, MonadServerReadRequest m) => m () childrenServer :: MVar [Async ()] -- | 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 :: (MonadServerAtomic m, MonadServerReadRequest m) => (Bool -> FactionId -> ChanServer -> IO ()) -> m () tryRestore :: MonadServerReadRequest m => m (Maybe (State, StateServer)) writeQueue :: MonadServerReadRequest m => Response -> CliSerQueue Response -> m () readQueueAI :: MonadServerReadRequest m => CliSerQueue RequestAI -> m RequestAI readQueueUI :: MonadServerReadRequest m => CliSerQueue RequestUI -> m RequestUI newQueue :: IO (CliSerQueue a) -- | Sending atomic commands to clients and executing them on the server. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Server.BroadcastAtomic -- | Send an atomic action to all clients that can see it. handleAndBroadcast :: (MonadServerAtomic m, MonadServerReadRequest m) => PosAtomic -> [UpdAtomic] -> CmdAtomic -> m () sendPer :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> LevelId -> Perception -> Perception -> Perception -> m () handleCmdAtomicServer :: MonadServerAtomic m => UpdAtomic -> m (PosAtomic, [UpdAtomic], Bool) -- | Messages for some unseen atomic commands. loudUpdAtomic :: MonadStateRead m => Bool -> UpdAtomic -> m (Maybe SfxMsg) -- | Messages for some unseen sfx. loudSfxAtomic :: MonadStateRead m => Bool -> SfxAtomic -> m (Maybe SfxMsg) atomicForget :: FactionId -> LevelId -> Perception -> State -> [UpdAtomic] atomicRemember :: LevelId -> Perception -> State -> State -> [UpdAtomic] -- | Server operations common to many modules. module Game.LambdaHack.Server.CommonM execFailure :: MonadServerAtomic m => ActorId -> RequestTimed a -> ReqFailure -> m () revealItems :: MonadServerAtomic m => Maybe FactionId -> m () moveStores :: MonadServerAtomic m => Bool -> ActorId -> CStore -> CStore -> m () -- | Generate the atomic updates that jointly perform a given item move. generalMoveItem :: MonadStateRead m => Bool -> ItemId -> Int -> Container -> Container -> m [UpdAtomic] deduceQuits :: MonadServerAtomic m => FactionId -> Status -> m () deduceKilled :: MonadServerAtomic m => ActorId -> m () electLeader :: MonadServerAtomic m => FactionId -> LevelId -> ActorId -> m () supplantLeader :: MonadServerAtomic m => FactionId -> ActorId -> m () updatePer :: MonadServerAtomic m => FactionId -> LevelId -> m () recomputeCachePer :: MonadServer m => FactionId -> LevelId -> m Perception projectFail :: MonadServerAtomic m => ActorId -> Point -> Int -> Bool -> ItemId -> CStore -> Bool -> m (Maybe ReqFailure) addActorFromGroup :: MonadServerAtomic m => GroupName ItemKind -> FactionId -> Point -> LevelId -> Time -> m (Maybe ActorId) registerActor :: MonadServerAtomic m => Bool -> ItemKnown -> ItemFullKit -> ItemSeed -> FactionId -> Point -> LevelId -> Time -> m ActorId discoverIfMinorEffects :: MonadServerAtomic m => Container -> ItemId -> ContentId ItemKind -> m () pickWeaponServer :: MonadServer m => ActorId -> m (Maybe (ItemId, CStore)) currentSkillsServer :: MonadServer m => ActorId -> m Skills containerMoveItem :: MonadStateRead m => Bool -> ItemId -> Int -> Container -> Container -> m [UpdAtomic] quitF :: MonadServerAtomic m => Status -> FactionId -> m () -- | Tell whether a faction that we know is still in game, keeps arena. -- Keeping arena means, if the faction is still in game, it always has a -- leader in the dungeon somewhere. So, leaderless factions and spawner -- factions do not keep an arena, even though the latter usually has a -- leader for most of the game. keepArenaFact :: Faction -> Bool anyActorsAlive :: MonadServer m => FactionId -> ActorId -> m Bool projectBla :: MonadServerAtomic m => ActorId -> Point -> [Point] -> ItemId -> CStore -> Bool -> m () addProjectile :: MonadServerAtomic m => Point -> [Point] -> ItemId -> ItemQuant -> LevelId -> FactionId -> Time -> m () addActorIid :: MonadServerAtomic m => ItemId -> ItemFull -> Bool -> FactionId -> Point -> LevelId -> (Actor -> Actor) -> Time -> m ActorId getCacheLucid :: MonadServer m => LevelId -> m FovLucid getCacheTotal :: MonadServer m => FactionId -> LevelId -> m CacheBeforeLucid -- | Operations for starting and restarting the game. module Game.LambdaHack.Server.StartM initPer :: MonadServer m => m () reinitGame :: MonadServerAtomic m => m () gameReset :: MonadServer m => ServerOptions -> Maybe (GroupName ModeKind) -> Maybe StdGen -> m State -- | Apply options that don't need a new game. applyDebug :: MonadServer m => m () mapFromFuns :: (Bounded a, Enum a, Ord b) => [a -> b] -> Map b a resetFactions :: FactionDict -> ContentId ModeKind -> Int -> AbsDepth -> Roster -> Rnd FactionDict populateDungeon :: MonadServerAtomic m => m () -- | Find starting postions for all factions. Try to make them distant from -- each other. Place as many of the factions, as possible, over stairs, -- starting from the end of the list, including placing the last factions -- over escapes (we assume they are guardians of the escapes). This -- implies the inital factions (if any) start far from escapes. findEntryPoss :: COps -> LevelId -> Level -> Int -> Rnd [Point] -- | Server operations performed periodically in the game loop and related -- operations. module Game.LambdaHack.Server.PeriodicM -- | Spawn, possibly, a monster according to the level's actor groups. We -- assume heroes are never spawned. spawnMonster :: MonadServerAtomic m => m () addAnyActor :: MonadServerAtomic m => Bool -> Freqs ItemKind -> LevelId -> Time -> Maybe Point -> m (Maybe ActorId) -- | Advance the move time for the given actor. advanceTime :: MonadServerAtomic m => ActorId -> Int -> Bool -> m () -- | Add communication overhead time delta to all non-projectile, non-dying -- faction's actors, except the leader. Effectively, this limits moves of -- a faction on a level to 10, regardless of the number of actors and -- their speeds. To avoid animals suddenly acting extremely sluggish -- whenever monster's leader visits a distant arena that has a crowd of -- animals, overhead applies only to actors on the same level. Since the -- number of active levels is limited, this bounds the total moves per -- turn of each faction as well. -- -- Leader is immune from overhead and so he is faster than other faction -- members and of equal speed to leaders of other factions (of equal base -- speed) regardless how numerous the faction is. Thanks to this, there -- is no problem with leader of a numerous faction having very long UI -- turns, introducing UI lag. overheadActorTime :: MonadServerAtomic m => FactionId -> LevelId -> m () -- | Swap the relative move times of two actors (e.g., when switching a UI -- leader). swapTime :: MonadServerAtomic m => ActorId -> ActorId -> m () udpateCalm :: MonadServerAtomic m => ActorId -> Int64 -> m () leadLevelSwitch :: MonadServerAtomic m => m () rollSpawnPos :: COps -> EnumSet Point -> Bool -> LevelId -> Level -> FactionId -> State -> Rnd Point -- | Handle effects. They are most often caused by requests sent by clients -- but sometimes also caused by projectiles or periodically activated -- items. module Game.LambdaHack.Server.HandleEffectM applyItem :: MonadServerAtomic m => ActorId -> ItemId -> CStore -> m () meleeEffectAndDestroy :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> Container -> m () effectAndDestroy :: MonadServerAtomic m => Bool -> ActorId -> ActorId -> ItemId -> Container -> Bool -> [Effect] -> ItemFullKit -> m () itemEffectEmbedded :: MonadServerAtomic m => ActorId -> LevelId -> Point -> ItemId -> m () -- | Drop a single actor's item. Note that if there are multiple copies, at -- most one explodes to avoid excessive carnage and UI clutter (let's -- say, the multiple explosions interfere with each other or perhaps -- larger quantities of explosives tend to be packaged more safely). dropCStoreItem :: MonadServerAtomic m => Bool -> CStore -> ActorId -> Actor -> Int -> ItemId -> ItemQuant -> m () highestImpression :: MonadServerAtomic m => ActorId -> m (Maybe FactionId) dominateFidSfx :: MonadServerAtomic m => ActorId -> FactionId -> m Bool pickDroppable :: MonadStateRead m => ActorId -> Actor -> m Container refillHP :: MonadServerAtomic m => ActorId -> ActorId -> Int64 -> m () cutCalm :: MonadServerAtomic m => ActorId -> m () data UseResult UseDud :: UseResult UseId :: UseResult UseUp :: UseResult applyMeleeDamage :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> m Bool imperishableKit :: Bool -> Bool -> ItemTimer -> ItemFull -> ItemQuant -> (Bool, ItemQuant) -- | The source actor affects the target actor, with a given item. If any -- of the effects fires up, the item gets identified. Note that using raw -- damage (beating the enemy with the magic wand, for example) does not -- identify the item. -- -- Note that if we activate a durable item, e.g., armor, from the ground, -- it will get identified, which is perfectly fine, until we want to add -- sticky armor that can't be easily taken off (and, e.g., has some -- maluses). itemEffectDisco :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> ItemKind -> Container -> Bool -> Bool -> [Effect] -> m UseResult -- | 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 item may or may not still be in the container. The boolean result -- indicates if the effect actually fired up, as opposed to fizzled. effectSem :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> Container -> Bool -> Bool -> Effect -> m UseResult effectBurn :: MonadServerAtomic m => Dice -> ActorId -> ActorId -> m UseResult effectExplode :: MonadServerAtomic m => m () -> GroupName ItemKind -> ActorId -> m UseResult effectRefillHP :: MonadServerAtomic m => Int -> ActorId -> ActorId -> m UseResult effectRefillCalm :: MonadServerAtomic m => m () -> Int -> ActorId -> ActorId -> m UseResult effectDominate :: MonadServerAtomic m => ActorId -> ActorId -> m UseResult dominateFid :: MonadServerAtomic m => FactionId -> ActorId -> m Bool effectImpress :: MonadServerAtomic m => (Effect -> m UseResult) -> m () -> ActorId -> ActorId -> m UseResult effectSummon :: MonadServerAtomic m => GroupName ItemKind -> Dice -> ItemId -> ActorId -> ActorId -> Bool -> m UseResult effectAscend :: MonadServerAtomic m => (Effect -> m UseResult) -> m () -> Bool -> ActorId -> ActorId -> Point -> m UseResult findStairExit :: MonadStateRead m => FactionId -> Bool -> LevelId -> Point -> m Point switchLevels1 :: MonadServerAtomic m => (ActorId, Actor) -> m (Maybe ActorId) switchLevels2 :: MonadServerAtomic m => LevelId -> Point -> (ActorId, Actor) -> Time -> Maybe ActorId -> m () -- | The faction leaves the dungeon. effectEscape :: MonadServerAtomic m => ActorId -> ActorId -> m UseResult -- | Advance target actor time by this many time clips. Not by actor moves, -- to hurt fast actors more. effectParalyze :: MonadServerAtomic m => m () -> Dice -> ActorId -> ActorId -> m UseResult -- | Give target actor the given number of extra moves. Don't give an -- absolute amount of time units, to benefit slow actors more. effectInsertMove :: MonadServerAtomic m => m () -> Dice -> ActorId -> ActorId -> m UseResult -- | Teleport the target actor. Note that projectiles can be teleported, -- too, for extra fun. effectTeleport :: MonadServerAtomic m => m () -> Dice -> ActorId -> ActorId -> m UseResult effectCreateItem :: MonadServerAtomic m => Maybe FactionId -> Maybe Int -> ActorId -> CStore -> GroupName ItemKind -> TimerDice -> m UseResult -- | Make the target actor drop items in a store from the given group. effectDropItem :: MonadServerAtomic m => m () -> Int -> Int -> CStore -> GroupName ItemKind -> ActorId -> m UseResult allGroupItems :: MonadServerAtomic m => CStore -> GroupName ItemKind -> ActorId -> m [(ItemId, ItemQuant)] effectPolyItem :: MonadServerAtomic m => m () -> ActorId -> ActorId -> m UseResult effectIdentify :: MonadServerAtomic m => m () -> ItemId -> ActorId -> ActorId -> m UseResult identifyIid :: MonadServerAtomic m => ItemId -> Container -> ContentId ItemKind -> m () effectDetect :: MonadServerAtomic m => m () -> DetectKind -> Int -> ActorId -> Point -> m UseResult effectDetectX :: MonadServerAtomic m => DetectKind -> (Point -> Bool) -> ([Point] -> m Bool) -> m () -> Int -> ActorId -> m UseResult -- | Send the target actor flying like a projectile. The arguments -- correspond to ToThrow and Linger properties of -- items. If the actors are adjacent, the vector is directed outwards, if -- no, inwards, if it's the same actor, boldpos is used, if it can't, a -- random outward vector of length 10 is picked. effectSendFlying :: MonadServerAtomic m => m () -> ThrowMod -> ActorId -> ActorId -> Maybe Bool -> m UseResult sendFlyingVector :: MonadServerAtomic m => ActorId -> ActorId -> Maybe Bool -> m Vector -- | Make the target actor drop his best weapon (stack). effectDropBestWeapon :: MonadServerAtomic m => m () -> ActorId -> m UseResult -- | Activate all items with the given symbol in the target actor's -- equipment (there's no variant that activates a random one, to avoid -- the incentive for carrying garbage). Only one item of each stack is -- activated (and possibly consumed). effectActivateInv :: MonadServerAtomic m => m () -> ActorId -> Char -> m UseResult effectTransformContainer :: forall m. MonadServerAtomic m => m () -> Char -> Container -> (ItemId -> ItemQuant -> m ()) -> m UseResult effectApplyPerfume :: MonadServerAtomic m => m () -> ActorId -> m UseResult effectOneOf :: MonadServerAtomic m => (Effect -> m UseResult) -> [Effect] -> m UseResult effectRecharging :: MonadServerAtomic m => (Effect -> m UseResult) -> Effect -> Bool -> m UseResult effectTemporary :: MonadServerAtomic m => m () -> ActorId -> ItemId -> Container -> m UseResult effectComposite :: forall m. MonadServerAtomic m => (Effect -> m UseResult) -> [Effect] -> m UseResult instance GHC.Classes.Ord Game.LambdaHack.Server.HandleEffectM.UseResult instance GHC.Classes.Eq Game.LambdaHack.Server.HandleEffectM.UseResult -- | Semantics of requests . 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. module Game.LambdaHack.Server.HandleRequestM -- | The semantics of server commands. AI always takes time and so doesn't -- loop. handleRequestAI :: MonadServerAtomic m => ReqAI -> m (Maybe RequestAnyAbility) -- | The semantics of server commands. Only the first two cases affect -- time. handleRequestUI :: MonadServerAtomic m => FactionId -> ActorId -> ReqUI -> m (Maybe RequestAnyAbility) handleRequestTimed :: MonadServerAtomic m => FactionId -> ActorId -> RequestTimed a -> m Bool switchLeader :: MonadServerAtomic m => FactionId -> ActorId -> m () -- | Actor moves or attacks. Note that client may not be able to see an -- invisible monster so it's the server that determines if melee took -- place, 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. reqMove :: MonadServerAtomic m => ActorId -> Vector -> m () -- | Actor tries to swap positions with another. reqDisplace :: MonadServerAtomic m => ActorId -> ActorId -> m () reqAlterFail :: MonadServerAtomic m => ActorId -> Point -> m (Maybe ReqFailure) reqGameDropAndExit :: MonadServerAtomic m => ActorId -> m () reqGameSaveAndExit :: MonadServerAtomic m => ActorId -> m () -- | This is a shorthand. Instead of setting bwait in -- ReqWait and unsetting in all other requests, we call this -- once before executing a request. setBWait :: MonadServerAtomic m => RequestTimed a -> ActorId -> Actor -> m (Maybe Bool) -- | Clear deltas for Calm and HP for proper UI display and AI hints. managePerRequest :: MonadServerAtomic m => ActorId -> m () handleRequestTimedCases :: MonadServerAtomic m => ActorId -> RequestTimed a -> m () -- | Add a smell trace for the actor to the level. For now, only actors -- with gender leave strong and unique enough smell. If smell already -- there and the actor can smell, remove smell. Projectiles are ignored. -- As long as an actor can smell, he doesn't leave any smell ever. affectSmell :: MonadServerAtomic m => ActorId -> m () -- | Resolves the result of an actor moving into another. Actors on -- unwalkable 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. No problem if there are many -- projectiles at the spot. We just attack the one specified. reqMelee :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> CStore -> m () -- | Search and/or alter the tile. reqAlter :: MonadServerAtomic m => ActorId -> Point -> m () -- | Do nothing. -- -- Something is sometimes done in setBWait. reqWait :: MonadServerAtomic m => ActorId -> m () reqMoveItems :: MonadServerAtomic m => ActorId -> [(ItemId, Int, CStore, CStore)] -> m () reqMoveItem :: MonadServerAtomic m => ActorId -> Bool -> (ItemId, Int, CStore, CStore) -> m () computeRndTimeout :: Time -> ItemFull -> Rnd (Maybe Time) reqProject :: MonadServerAtomic m => ActorId -> Point -> Int -> ItemId -> CStore -> m () reqApply :: MonadServerAtomic m => ActorId -> ItemId -> CStore -> m () reqGameRestart :: MonadServerAtomic m => ActorId -> GroupName ModeKind -> Challenge -> m () reqGameSave :: MonadServer m => m () reqTactic :: MonadServerAtomic m => FactionId -> Tactic -> m () reqAutomate :: MonadServerAtomic m => FactionId -> m () -- | Server operations used when ending game and deciding whether to end. module Game.LambdaHack.Server.EndM -- | Continue or exit or restart the game. endOrLoop :: (MonadServerAtomic m, MonadServerReadRequest m) => m () -> (Maybe (GroupName ModeKind) -> m ()) -> m () dieSer :: MonadServerAtomic m => ActorId -> Actor -> m () -- | Save game on server and all clients. writeSaveAll :: MonadServerAtomic m => Bool -> m () gameExit :: (MonadServerAtomic m, MonadServerReadRequest m) => m () -- | Drop all actor's items. dropAllItems :: MonadServerAtomic m => ActorId -> Actor -> m () -- | The main loop of the server, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Server.LoopM -- | Start a game session, including the clients, and then loop, -- communicating with the clients. -- -- The loop is started in server state that is empty, see -- emptyStateServer. loopSer :: (MonadServerAtomic m, MonadServerReadRequest m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m () factionArena :: MonadStateRead m => Faction -> m (Maybe LevelId) arenasForLoop :: MonadStateRead m => m [LevelId] handleFidUpd :: (MonadServerAtomic m, MonadServerReadRequest m) => (FactionId -> m ()) -> FactionId -> Faction -> m () -- | Handle a clip (the smallest fraction of a game turn for which a frame -- may potentially be generated). Run the leader and other actors moves. -- Eventually advance the time and repeat. loopUpd :: forall m. (MonadServerAtomic m, MonadServerReadRequest m) => m () -> m () -- | Handle the end of every clip. Do whatever has to be done every fixed -- number of clips, e.g., monster generation. Advance time. Perform -- periodic saves, if applicable. -- -- This is never run if UI requested save or exit or restart and it's -- correct, because we know nobody moved and no time was or needs to be -- advanced and arenas are not changed. After game was saved and exited, -- on game resume the first clip is performed with empty arenas, so arena -- time is not updated and nobody moves, nor anything happens, but arenas -- are here correctly updated. endClip :: forall m. MonadServerAtomic m => (FactionId -> m ()) -> m () -- | Check if the given actor is dominated and update his calm. manageCalmAndDomination :: MonadServerAtomic m => ActorId -> Actor -> m () -- | Trigger periodic items for all actors on the given level. applyPeriodicLevel :: MonadServerAtomic m => m () handleTrajectories :: MonadServerAtomic m => LevelId -> FactionId -> m () hTrajectories :: MonadServerAtomic m => ActorId -> m () -- | Manage trajectory of a projectile. -- -- Colliding with a wall or actor doesn't take time, because the -- projectile does not move (the move is blocked). Not advancing time -- forces dead projectiles to be destroyed ASAP. Otherwise, with some -- timings, it can stay on the game map dead, blocking path of -- human-controlled actors and alarming the hapless human. setTrajectory :: MonadServerAtomic m => ActorId -> Actor -> m () handleActors :: (MonadServerAtomic m, MonadServerReadRequest m) => LevelId -> FactionId -> m Bool hActors :: forall m. (MonadServerAtomic m, MonadServerReadRequest m) => [ActorId] -> m Bool restartGame :: MonadServerAtomic m => m () -> m () -> Maybe (GroupName ModeKind) -> m () -- | Semantics of requests that are sent by clients to the server, in terms -- of game state changes and responses to be sent to the clients. -- -- See -- https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture. module Game.LambdaHack.Server -- | Start a game session, including the clients, and then loop, -- communicating with the clients. -- -- The loop is started in server state that is empty, see -- emptyStateServer. loopSer :: (MonadServerAtomic m, MonadServerReadRequest m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m () -- | Connection channel between the server and a single client. data ChanServer ChanServer :: CliSerQueue Response -> CliSerQueue RequestAI -> Maybe (CliSerQueue RequestUI) -> ChanServer [responseS] :: ChanServer -> CliSerQueue Response [requestAIS] :: ChanServer -> CliSerQueue RequestAI [requestUIS] :: ChanServer -> Maybe (CliSerQueue RequestUI) -- | Parser for server options from commandline arguments. serverOptionsPI :: ParserInfo ServerOptions -- | Options that affect the behaviour of the server (including game -- rules). data ServerOptions ServerOptions :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe (GroupName ModeKind) -> Bool -> Bool -> Maybe StdGen -> Maybe StdGen -> Bool -> Challenge -> Bool -> String -> Bool -> ClientOptions -> ServerOptions [sknowMap] :: ServerOptions -> Bool [sknowEvents] :: ServerOptions -> Bool [sknowItems] :: ServerOptions -> Bool [sniff] :: ServerOptions -> Bool [sallClear] :: ServerOptions -> Bool [sboostRandomItem] :: ServerOptions -> Bool [sgameMode] :: ServerOptions -> Maybe (GroupName ModeKind) [sautomateAll] :: ServerOptions -> Bool [skeepAutomated] :: ServerOptions -> Bool [sdungeonRng] :: ServerOptions -> Maybe StdGen [smainRng] :: ServerOptions -> Maybe StdGen [snewGameSer] :: ServerOptions -> Bool [scurChalSer] :: ServerOptions -> Challenge [sdumpInitRngs] :: ServerOptions -> Bool [ssavePrefixSer] :: ServerOptions -> String [sdbgMsgSer] :: ServerOptions -> Bool [sclientOptions] :: ServerOptions -> ClientOptions