-- | Monadic operations on game messages.
module Game.LambdaHack.Client.UI.MsgM
  ( msgAddDuplicate, msgAdd, msgAdd0, promptAdd, promptAdd0
  , promptMainKeys, recordHistory
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import qualified Data.EnumMap.Strict as EM

import           Game.LambdaHack.Client.MonadClient
import           Game.LambdaHack.Client.State
import qualified Game.LambdaHack.Client.UI.HumanCmd as HumanCmd
import qualified Game.LambdaHack.Client.UI.Key as K
import           Game.LambdaHack.Client.UI.MonadClientUI
import           Game.LambdaHack.Client.UI.Msg
import           Game.LambdaHack.Client.UI.SessionUI
import           Game.LambdaHack.Client.UI.UIOptions
import           Game.LambdaHack.Common.ActorState
import           Game.LambdaHack.Common.MonadStateRead
import           Game.LambdaHack.Common.State
import           Game.LambdaHack.Definition.Defs

-- | Add a message to the current report.
msgAddDuplicate :: MonadClientUI m => Text -> MsgClass -> Int -> m Bool
msgAddDuplicate :: Text -> MsgClass -> Int -> m Bool
msgAddDuplicate msg :: Text
msg msgClass :: MsgClass
msgClass n :: Int
n = do
  UIOptions
sUIOptions <- (SessionUI -> UIOptions) -> m UIOptions
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> UIOptions
sUIOptions
  Time
time <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> Time
stime
  History
history <- (SessionUI -> History) -> m History
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> History
shistory
  let mem :: Maybe (EnumMap MsgClass Color)
mem = [(MsgClass, Color)] -> EnumMap MsgClass Color
forall k a. Enum k => [(k, a)] -> EnumMap k a
EM.fromList ([(MsgClass, Color)] -> EnumMap MsgClass Color)
-> Maybe [(MsgClass, Color)] -> Maybe (EnumMap MsgClass Color)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> UIOptions -> Maybe [(MsgClass, Color)]
uMessageColors UIOptions
sUIOptions
      (nhistory :: History
nhistory, duplicate :: Bool
duplicate) =
        History -> Msg -> Int -> Time -> (History, Bool)
addToReport History
history (Maybe (EnumMap MsgClass Color) -> MsgClass -> Text -> Msg
toMsg Maybe (EnumMap MsgClass Color)
mem MsgClass
msgClass Text
msg) Int
n Time
time
  (SessionUI -> SessionUI) -> m ()
forall (m :: * -> *).
MonadClientUI m =>
(SessionUI -> SessionUI) -> m ()
modifySession ((SessionUI -> SessionUI) -> m ())
-> (SessionUI -> SessionUI) -> m ()
forall a b. (a -> b) -> a -> b
$ \sess :: SessionUI
sess -> SessionUI
sess {shistory :: History
shistory = History
nhistory}
  Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
duplicate

-- | Add a message to the current report. Do not report if it was a duplicate.
msgAdd :: MonadClientUI m => MsgClass -> Text -> m ()
msgAdd :: MsgClass -> Text -> m ()
msgAdd msgClass :: MsgClass
msgClass msg :: Text
msg = m Bool -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Bool -> m ()) -> m Bool -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> MsgClass -> Int -> m Bool
forall (m :: * -> *).
MonadClientUI m =>
Text -> MsgClass -> Int -> m Bool
msgAddDuplicate Text
msg MsgClass
msgClass 1

-- | Add a message to the current report with 0 copies for the purpose
-- of collating duplicates. Do not report if it was a duplicate.
msgAdd0 :: MonadClientUI m => MsgClass -> Text -> m ()
msgAdd0 :: MsgClass -> Text -> m ()
msgAdd0 msgClass :: MsgClass
msgClass msg :: Text
msg = m Bool -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Bool -> m ()) -> m Bool -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> MsgClass -> Int -> m Bool
forall (m :: * -> *).
MonadClientUI m =>
Text -> MsgClass -> Int -> m Bool
msgAddDuplicate Text
msg MsgClass
msgClass 0

-- | Add a prompt to the current report. Do not report if it was a duplicate.
promptAdd :: MonadClientUI m => Text -> m ()
promptAdd :: Text -> m ()
promptAdd = MsgClass -> Text -> m ()
forall (m :: * -> *). MonadClientUI m => MsgClass -> Text -> m ()
msgAdd MsgClass
MsgAlert

-- | Add a prompt to the current report with 0 copies for the purpose
-- of collating duplicates. Do not report if it was a duplicate.
promptAdd0 :: MonadClientUI m => Text -> m ()
promptAdd0 :: Text -> m ()
promptAdd0 = MsgClass -> Text -> m ()
forall (m :: * -> *). MonadClientUI m => MsgClass -> Text -> m ()
msgAdd0 MsgClass
MsgPrompt

-- | Add a prompt with basic keys description.
promptMainKeys :: MonadClientUI m => m ()
promptMainKeys :: m ()
promptMainKeys = do
  FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
  [(ActorId, Actor)]
ours <- (State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)])
-> (State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)]
forall a b. (a -> b) -> a -> b
$ FactionId -> State -> [(ActorId, Actor)]
fidActorNotProjGlobalAssocs FactionId
side
  KM -> HumanCmd -> KM
revCmd <- m (KM -> HumanCmd -> KM)
forall (m :: * -> *). MonadClientUI m => m (KM -> HumanCmd -> KM)
revCmdMap
  let kmHelp :: KM
kmHelp = KM -> HumanCmd -> KM
revCmd KM
K.undefinedKM HumanCmd
HumanCmd.Hint
      kmViewEqp :: KM
kmViewEqp = KM -> HumanCmd -> KM
revCmd KM
K.undefinedKM (ItemDialogMode -> HumanCmd
HumanCmd.ChooseItemMenu (CStore -> ItemDialogMode
MStore CStore
CEqp))
      kmItemEqp :: KM
kmItemEqp = KM -> HumanCmd -> KM
revCmd KM
K.undefinedKM
                         ([CStore] -> CStore -> Maybe Part -> Bool -> HumanCmd
HumanCmd.MoveItem [CStore
CGround, CStore
CInv, CStore
CSha] CStore
CEqp
                                            Maybe Part
forall a. Maybe a
Nothing Bool
False)
      kmXhairPointerFloor :: KM
kmXhairPointerFloor = KM -> HumanCmd -> KM
revCmd KM
K.undefinedKM HumanCmd
HumanCmd.XhairPointerFloor
  Maybe AimMode
saimMode <- (SessionUI -> Maybe AimMode) -> m (Maybe AimMode)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> Maybe AimMode
saimMode
  UIOptions{Bool
uVi :: UIOptions -> Bool
uVi :: Bool
uVi, Bool
uLaptop :: UIOptions -> Bool
uLaptop :: Bool
uLaptop} <- (SessionUI -> UIOptions) -> m UIOptions
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> UIOptions
sUIOptions
  Maybe Target
xhair <- (SessionUI -> Maybe Target) -> m (Maybe Target)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> Maybe Target
sxhair
  -- The silly "uk8o79jl" ordering of keys is chosen to match "hjklyubn",
  -- which the usual way of writing them.
  let moveKeys :: Text
moveKeys | Bool
uVi = "keypad or hjklyubn"
               | Bool
uLaptop = "keypad or uk8o79jl"
               | Bool
otherwise = "keypad"
      manyTeammates :: Bool
manyTeammates = [(ActorId, Actor)] -> Int
forall a. [a] -> Int
length [(ActorId, Actor)]
ours Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 1
      keepTab :: Text
keepTab = if Bool
manyTeammates
                then "Keep TAB of teammates (S-TAB for other levels)."
                else ""
      describePos :: Text
describePos = if Bool
mmbIsNormal
                    then "Describe map position with MMB."
                    else ""
      viewEquip :: Text
viewEquip = if Bool
eqpKeysAreNormal
                  then "View (E)quipment and (e)quip items."
                  else ""
      moreHelp :: Text
moreHelp = "Press" Text -> Text -> Text
<+> KM -> Text
forall a. Show a => a -> Text
tshow KM
kmHelp Text -> Text -> Text
<+> "for help."
      mmbIsNormal :: Bool
mmbIsNormal = KM
kmXhairPointerFloor KM -> KM -> Bool
forall a. Eq a => a -> a -> Bool
== KM
K.middleButtonReleaseKM
      eqpKeysAreNormal :: Bool
eqpKeysAreNormal = KM
kmViewEqp KM -> KM -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> KM
K.mkChar 'E'
                         Bool -> Bool -> Bool
&& KM
kmItemEqp KM -> KM -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> KM
K.mkChar 'e'
      keys :: Text
keys | Maybe AimMode -> Bool
forall a. Maybe a -> Bool
isNothing Maybe AimMode
saimMode =
        "Explore with" Text -> Text -> Text
<+> Text
moveKeys Text -> Text -> Text
<+> "keys or mouse."
        Text -> Text -> Text
<+> Text
describePos
        Text -> Text -> Text
<+> Text
viewEquip
        Text -> Text -> Text
<+> Text
keepTab
        Text -> Text -> Text
<+> Text
moreHelp
           | Bool
otherwise =
        Maybe Target -> Text
tgtKindVerb Maybe Target
xhair
        Text -> Text -> Text
<+> "with" Text -> Text -> Text
<+> Text
moveKeys Text -> Text -> Text
<+> "keys or mouse."
        Text -> Text -> Text
<+> Text
keepTab
        Text -> Text -> Text
<+> Text
moreHelp
  m () -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> m ()
forall (m :: * -> *). MonadClientUI m => Text -> m ()
promptAdd0 Text
keys

tgtKindVerb :: Maybe Target -> Text
tgtKindVerb :: Maybe Target -> Text
tgtKindVerb mtgt :: Maybe Target
mtgt = case Maybe Target
mtgt of
  Just TEnemy{} -> "Aim at enemy"
  Just TNonEnemy{} -> "Aim at non-enemy"
  Just TPoint{} -> "Aim at position"
  Just TVector{} -> "Indicate a move vector"
  Nothing -> "Start aiming"

-- | Store new report in the history and archive old report.
recordHistory :: MonadClientUI m => m ()
recordHistory :: m ()
recordHistory =
  (SessionUI -> SessionUI) -> m ()
forall (m :: * -> *).
MonadClientUI m =>
(SessionUI -> SessionUI) -> m ()
modifySession ((SessionUI -> SessionUI) -> m ())
-> (SessionUI -> SessionUI) -> m ()
forall a b. (a -> b) -> a -> b
$ \sess :: SessionUI
sess -> SessionUI
sess {shistory :: History
shistory = History -> History
archiveReport (History -> History) -> History -> History
forall a b. (a -> b) -> a -> b
$ SessionUI -> History
shistory SessionUI
sess}