{-# LANGUAGE DeriveGeneric #-} -- | Abstract syntax human player commands. module Game.LambdaHack.Client.UI.HumanCmd ( CmdCategory(..), HumanCmd(..), Trigger(..) , noRemoteHumanCmd, categoryDescription, cmdDescription ) where import Control.DeepSeq import Control.Exception.Assert.Sugar import Data.Maybe import Data.Text (Text) import GHC.Generics (Generic) import qualified NLP.Miniutter.English as MU import Game.LambdaHack.Common.Actor (verbCStore) import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Common.Vector import Game.LambdaHack.Content.ModeKind import qualified Game.LambdaHack.Content.TileKind as TK data CmdCategory = CmdMenu | CmdMove | CmdItem | CmdTgt | CmdAuto | CmdMeta | CmdMouse | CmdInternal | CmdDebug | CmdMinimal deriving (Show, Read, Eq, Generic) instance NFData CmdCategory categoryDescription :: CmdCategory -> Text categoryDescription CmdMenu = "Main Menu" categoryDescription CmdMove = "Terrain exploration and alteration" categoryDescription CmdItem = "Item use" categoryDescription CmdTgt = "Aiming and targeting" categoryDescription CmdAuto = "Automation" categoryDescription CmdMeta = "Assorted" categoryDescription CmdMouse = "Mouse" categoryDescription CmdInternal = "Internal" categoryDescription CmdDebug = "Debug" categoryDescription CmdMinimal = "The minimal command set" -- | Abstract syntax of player commands. data HumanCmd = -- Global. -- These usually take time. Move !Vector | Run !Vector | Wait | MoveItem ![CStore] !CStore !(Maybe MU.Part) !MU.Part !Bool | DescribeItem !ItemDialogMode | Project ![Trigger] | Apply ![Trigger] | AlterDir ![Trigger] | TriggerTile ![Trigger] | RunOnceAhead | MoveOnceToCursor | RunOnceToCursor | ContinueToCursor -- Below this line, commands do not take time. | GameRestart !(GroupName ModeKind) | GameExit | GameSave | Tactic | Automate -- Local. -- Below this line, commands do not notify the server. | GameDifficultyCycle | PickLeader !Int | MemberCycle | MemberBack | SelectActor | SelectNone | Clear | StopIfTgtMode | SelectWithPointer | Repeat !Int | Record | History | MarkVision | MarkSmell | MarkSuspect | Help | MainMenu | Macro !Text ![String] -- These are mostly related to targeting. | MoveCursor !Vector !Int | TgtFloor | TgtEnemy | TgtAscend !Int | EpsIncr !Bool | TgtClear | CursorUnknown | CursorItem | CursorStair !Bool | Cancel | Accept | CursorPointerFloor | CursorPointerEnemy | TgtPointerFloor | TgtPointerEnemy deriving (Show, Read, Eq, Ord, Generic) instance NFData HumanCmd data Trigger = ApplyItem {verb :: !MU.Part, object :: !MU.Part, symbol :: !Char} | AlterFeature {verb :: !MU.Part, object :: !MU.Part, feature :: !TK.Feature} | TriggerFeature {verb :: !MU.Part, object :: !MU.Part, feature :: !TK.Feature} deriving (Show, Read, Eq, Ord, Generic) instance NFData Trigger -- | Commands that are forbidden on a remote level, because they -- would usually take time when invoked on one. -- Note that some commands that take time are not included, -- because they don't take time in targeting mode. noRemoteHumanCmd :: HumanCmd -> Bool noRemoteHumanCmd cmd = case cmd of Wait -> True MoveItem{} -> True Apply{} -> True AlterDir{} -> True MoveOnceToCursor -> True RunOnceToCursor -> True ContinueToCursor -> True _ -> False -- | Description of player commands. cmdDescription :: HumanCmd -> Text cmdDescription cmd = case cmd of Move v -> "move" <+> compassText v Run v -> "run" <+> compassText v Wait -> "wait" MoveItem _ store2 mverb object _ -> let verb = fromMaybe (MU.Text $ verbCStore store2) mverb in makePhrase [verb, object] DescribeItem (MStore CGround) -> "manage items on the ground" DescribeItem (MStore COrgan) -> "describe organs of the leader" DescribeItem (MStore CEqp) -> "manage equipment of the leader" DescribeItem (MStore CInv) -> "manage inventory pack of the leader" DescribeItem (MStore CSha) -> "manage the shared party stash" DescribeItem MOwned -> "describe all owned items" DescribeItem MStats -> "show the stats summary of the leader" Project ts -> triggerDescription ts Apply ts -> triggerDescription ts AlterDir ts -> triggerDescription ts TriggerTile ts -> triggerDescription ts RunOnceAhead -> "run once ahead" MoveOnceToCursor -> "move one step towards the crosshair" RunOnceToCursor -> "run selected one step towards the crosshair" ContinueToCursor -> "continue towards the crosshair" GameRestart t -> -- TODO: use mname for the game mode instead of t makePhrase ["new", MU.Capitalize $ MU.Text $ tshow t, "game"] GameExit -> "save and exit" GameSave -> "save game" Tactic -> "cycle tactic of non-leader team members (WIP)" Automate -> "automate faction (ESC to retake control)" GameDifficultyCycle -> "cycle difficulty of the next game" PickLeader{} -> "pick leader" MemberCycle -> "cycle among party members on the level" MemberBack -> "cycle among all party members" SelectActor -> "select (or deselect) a party member" SelectNone -> "deselect (or select) all on the level" Clear -> "clear messages" StopIfTgtMode -> "stop playback if in aiming mode" SelectWithPointer -> "select actors if pointer over actor list" Repeat 1 -> "voice again the recorded commands" Repeat n -> "voice the recorded commands" <+> tshow n <+> "times" Record -> "start recording commands" History -> "display player diary" MarkVision -> "toggle visible zone display" MarkSmell -> "toggle smell clues display" MarkSuspect -> "toggle suspect terrain display" Help -> "display help" MainMenu -> "display the Main Menu" Macro t _ -> t MoveCursor v 1 -> "move crosshair" <+> compassText v MoveCursor v k -> "move crosshair up to" <+> tshow k <+> "steps" <+> compassText v TgtFloor -> "cycle aiming styles" TgtEnemy -> "aim at an enemy" TgtAscend k | k == 1 -> "aim at next shallower level" TgtAscend k | k >= 2 -> "aim at" <+> tshow k <+> "levels shallower" TgtAscend k | k == -1 -> "aim at next deeper level" TgtAscend k | k <= -2 -> "aim at" <+> tshow (-k) <+> "levels deeper" TgtAscend _ -> assert `failure` "void level change when aiming" `twith` cmd EpsIncr True -> "swerve the aiming line" EpsIncr False -> "unswerve the aiming line" TgtClear -> "reset target/crosshair" CursorUnknown -> "set crosshair to the closest unknown spot" CursorItem -> "set crosshair to the closest item" CursorStair up -> "set crosshair to the closest stairs" <+> if up then "up" else "down" Cancel -> "cancel action, open Main Menu" Accept -> "accept target/choice" CursorPointerFloor -> "set crosshair to floor under pointer" CursorPointerEnemy -> "set crosshair to enemy under pointer" TgtPointerFloor -> "enter aiming mode and describe a tile" TgtPointerEnemy -> "enter aiming mode and describe an enemy" triggerDescription :: [Trigger] -> Text triggerDescription [] = "trigger a thing" triggerDescription (t : _) = makePhrase [verb t, object t]