-- | Display atomic SFX commands received by the client.
module Game.LambdaHack.Client.UI.Watch.WatchSfxAtomicM
  ( watchRespSfxAtomicUI
#ifdef EXPOSE_INTERNAL
    -- * Internal operations
  , returnJustLeft, ppSfxMsg, strike
#endif
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import qualified Data.EnumMap.Strict as EM
import           Data.Int (Int64)
import qualified Data.Text as T
import qualified NLP.Miniutter.English as MU

import           Game.LambdaHack.Atomic
import           Game.LambdaHack.Client.MonadClient
import           Game.LambdaHack.Client.State
import           Game.LambdaHack.Client.UI.ActorUI
import           Game.LambdaHack.Client.UI.Animation
import           Game.LambdaHack.Client.UI.Content.Screen
import           Game.LambdaHack.Client.UI.ContentClientUI
import           Game.LambdaHack.Client.UI.EffectDescription
import           Game.LambdaHack.Client.UI.Frame
import           Game.LambdaHack.Client.UI.FrameM
import           Game.LambdaHack.Client.UI.HandleHelperM
import qualified Game.LambdaHack.Client.UI.HumanCmd as HumanCmd
import           Game.LambdaHack.Client.UI.ItemDescription
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.MsgM
import           Game.LambdaHack.Client.UI.SessionUI
import           Game.LambdaHack.Client.UI.SlideshowM
import           Game.LambdaHack.Client.UI.Watch.WatchCommonM
import           Game.LambdaHack.Common.Actor
import           Game.LambdaHack.Common.ActorState
import           Game.LambdaHack.Common.Faction
import           Game.LambdaHack.Common.Item
import qualified Game.LambdaHack.Common.ItemAspect as IA
import           Game.LambdaHack.Common.Kind
import           Game.LambdaHack.Common.Level
import           Game.LambdaHack.Common.Misc
import           Game.LambdaHack.Common.MonadStateRead
import           Game.LambdaHack.Common.Point
import           Game.LambdaHack.Common.ReqFailure
import           Game.LambdaHack.Common.State
import           Game.LambdaHack.Common.Time
import           Game.LambdaHack.Common.Types
import           Game.LambdaHack.Content.CaveKind (cdesc)
import qualified Game.LambdaHack.Content.ItemKind as IK
import qualified Game.LambdaHack.Content.TileKind as TK
import qualified Game.LambdaHack.Core.Dice as Dice
import           Game.LambdaHack.Core.Frequency
import           Game.LambdaHack.Core.Random
import qualified Game.LambdaHack.Definition.Ability as Ability
import qualified Game.LambdaHack.Definition.Color as Color
import           Game.LambdaHack.Definition.Defs

-- | Display special effects (text, animation) sent to the client.
-- Don't modify client state (except a few fields), but only client
-- session (e.g., by displaying messages). This is enforced by types.
watchRespSfxAtomicUI :: MonadClientUI m => SfxAtomic -> m ()
{-# INLINE watchRespSfxAtomicUI #-}
watchRespSfxAtomicUI :: SfxAtomic -> m ()
watchRespSfxAtomicUI SfxAtomic
sfx = case SfxAtomic
sfx of
  SfxStrike ActorId
source ActorId
target ItemId
iid ->
    Bool -> ActorId -> ActorId -> ItemId -> m ()
forall (m :: * -> *).
MonadClientUI m =>
Bool -> ActorId -> ActorId -> ItemId -> m ()
strike Bool
False ActorId
source ActorId
target ItemId
iid
  SfxRecoil ActorId
source ActorId
target ItemId
iid -> do
    Bool
sourceSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId Actor -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ActorId
source (EnumMap ActorId Actor -> Bool)
-> (State -> EnumMap ActorId Actor) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap ActorId Actor
sactorD
    if Bool -> Bool
not Bool
sourceSeen then do
      Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
target
      LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Animation
blockMiss (Actor -> Point
bpos Actor
tb, Actor -> Point
bpos Actor
tb)
    else do
      CCUI{coscreen :: CCUI -> ScreenContent
coscreen=ScreenContent{X
rwidth :: ScreenContent -> X
rwidth :: X
rwidth}} <- (SessionUI -> CCUI) -> m CCUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
      Actor
sb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
      Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
      Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
source
      Part
tpart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
target
      FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
      FactionDict
factionD <- (State -> FactionDict) -> m FactionDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> FactionDict
sfactionD
      Time
localTime <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Time) -> m Time) -> (State -> Time) -> m Time
forall a b. (a -> b) -> a -> b
$ LevelId -> State -> Time
getLocalTime (Actor -> LevelId
blid Actor
tb)
      ItemFull
itemFullWeapon <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
      let kitWeapon :: ItemQuant
kitWeapon = ItemQuant
quantSingle
          (Part
weaponName, Part
_) = X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItemShort X
rwidth FactionId
side FactionDict
factionD
                                          Time
localTime ItemFull
itemFullWeapon ItemQuant
kitWeapon
          weaponNameOwn :: Part
weaponNameOwn = X
-> FactionId
-> FactionDict
-> Part
-> Time
-> ItemFull
-> ItemQuant
-> Part
partItemShortWownW X
rwidth FactionId
side FactionDict
factionD Part
spart
                                             Time
localTime ItemFull
itemFullWeapon ItemQuant
kitWeapon
          verb :: Part
verb = if Actor -> Bool
bproj Actor
sb then Part
"deflect" else Part
"fend off"
          objects :: [Part]
objects | ItemId
iid ItemId -> ItemId -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> ItemId
btrunk Actor
sb = [Part
"the", Part
spart]
                  | ItemId
iid ItemId -> EnumMap ItemId ItemQuant -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.member` Actor -> EnumMap ItemId ItemQuant
borgan Actor
sb =  [Part
"the", Part
weaponNameOwn]
                  | Bool
otherwise = [Part
"the", Part
weaponName, Part
"of", Part
spart]
      MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgActionMajor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
        [Part] -> Text
makeSentence ([Part] -> Text) -> [Part] -> Text
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
tpart Part
verb Part -> [Part] -> [Part]
forall a. a -> [a] -> [a]
: [Part]
objects
      LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Animation
blockMiss (Actor -> Point
bpos Actor
tb, Actor -> Point
bpos Actor
sb)
  SfxSteal ActorId
source ActorId
target ItemId
iid ->
    Bool -> ActorId -> ActorId -> ItemId -> m ()
forall (m :: * -> *).
MonadClientUI m =>
Bool -> ActorId -> ActorId -> ItemId -> m ()
strike Bool
True ActorId
source ActorId
target ItemId
iid
  SfxRelease ActorId
source ActorId
target ItemId
_ -> do
    Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
source
    Part
tpart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
target
    MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgActionMajor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
      [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"release", Part
tpart]
  SfxProject ActorId
aid ItemId
iid ->
    MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Either X X -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Either X X -> m ()
itemAidVerbMU MsgClassShowAndSave
MsgActionMajor ActorId
aid Part
"fling" ItemId
iid (X -> Either X X
forall a b. a -> Either a b
Left X
1)
  SfxReceive ActorId
aid ItemId
iid ->
    MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Either X X -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Either X X -> m ()
itemAidVerbMU MsgClassShowAndSave
MsgActionMajor ActorId
aid Part
"receive" ItemId
iid (X -> Either X X
forall a b. a -> Either a b
Left X
1)
  SfxApply ActorId
aid ItemId
iid -> do
    CCUI{coscreen :: CCUI -> ScreenContent
coscreen=ScreenContent{EnumMap (ContentSymbol ItemKind) Text
rapplyVerbMap :: ScreenContent -> EnumMap (ContentSymbol ItemKind) Text
rapplyVerbMap :: EnumMap (ContentSymbol ItemKind) Text
rapplyVerbMap}} <- (SessionUI -> CCUI) -> m CCUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
    ItemFull{ItemKind
itemKind :: ItemFull -> ItemKind
itemKind :: ItemKind
itemKind} <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
    let actionPart :: Part
actionPart =
          Part -> (Text -> Part) -> Maybe Text -> Part
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Part
"trigger"
                Text -> Part
MU.Text
                (ContentSymbol ItemKind
-> EnumMap (ContentSymbol ItemKind) Text -> Maybe Text
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup (ItemKind -> ContentSymbol ItemKind
IK.isymbol ItemKind
itemKind) EnumMap (ContentSymbol ItemKind) Text
rapplyVerbMap)
    MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Either X X -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Either X X -> m ()
itemAidVerbMU MsgClassShowAndSave
MsgActionMajor ActorId
aid Part
actionPart ItemId
iid (X -> Either X X
forall a b. a -> Either a b
Left X
1)
  SfxCheck ActorId
aid ItemId
iid ->
    MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Either X X -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Either X X -> m ()
itemAidVerbMU MsgClassShowAndSave
MsgActionMajor ActorId
aid Part
"recover" ItemId
iid (X -> Either X X
forall a b. a -> Either a b
Left X
1)
  SfxTrigger ActorId
_ LevelId
_ Point
_ ContentId TileKind
fromTile -> do
    COps{ContentData TileKind
cotile :: COps -> ContentData TileKind
cotile :: ContentData TileKind
cotile} <- (State -> COps) -> m COps
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> COps
scops
    let subject :: Part
subject = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ TileKind -> Text
TK.tname (TileKind -> Text) -> TileKind -> Text
forall a b. (a -> b) -> a -> b
$ ContentData TileKind -> ContentId TileKind -> TileKind
forall a. ContentData a -> ContentId a -> a
okind ContentData TileKind
cotile ContentId TileKind
fromTile
        verb :: Part
verb = Part
"shake"
        msg :: Text
msg = [Part] -> Text
makeSentence [Part
"the", Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb]
    MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgNeutralEvent Text
msg
  SfxShun ActorId
aid LevelId
_ Point
_ ContentId TileKind
_ ->
    MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgActionMajor ActorId
aid Part
"shun it"
  SfxEffect FactionId
fidSource ActorId
aid ItemId
iid Effect
effect Int64
hpDelta -> do
    -- In most messages below @iid@ is ignored, because it's too common,
    -- e.g., caused by some combat hits, or rather obvious,
    -- e.g., in case of embedded items, or would be counterintuitive,
    -- e.g., when actor is said to be intimidated by a particle, not explosion.
    CCUI{coscreen :: CCUI -> ScreenContent
coscreen=ScreenContent{X
rwidth :: X
rwidth :: ScreenContent -> X
rwidth}} <- (SessionUI -> CCUI) -> m CCUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    ActorUI
bUI <- (SessionUI -> ActorUI) -> m ActorUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> ActorUI) -> m ActorUI)
-> (SessionUI -> ActorUI) -> m ActorUI
forall a b. (a -> b) -> a -> b
$ ActorId -> SessionUI -> ActorUI
getActorUI ActorId
aid
    FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
    Maybe ActorId
mleader <- (StateClient -> Maybe ActorId) -> m (Maybe ActorId)
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> Maybe ActorId
sleader
    ItemDict
itemD <- (State -> ItemDict) -> m ItemDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> ItemDict
sitemD
    Skills
actorMaxSk <- (State -> Skills) -> m Skills
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Skills) -> m Skills) -> (State -> Skills) -> m Skills
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Skills
getActorMaxSkills ActorId
aid
    let fid :: FactionId
fid = Actor -> FactionId
bfid Actor
b
        isOurCharacter :: Bool
isOurCharacter = FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side Bool -> Bool -> Bool
&& Bool -> Bool
not (Actor -> Bool
bproj Actor
b)
        isAlive :: Bool
isAlive = Actor -> Int64
bhp Actor
b Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
> Int64
0
        isOurAlive :: Bool
isOurAlive = Bool
isOurCharacter Bool -> Bool -> Bool
&& Bool
isAlive
        isOurLeader :: Bool
isOurLeader = ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
aid Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe ActorId
mleader
        -- The message classes are close enough. It's melee or similar.
        feelLookHPBad :: Text -> Text -> m ()
feelLookHPBad Text
bigAdj Text
projAdj = do
          MsgClassShowAndSave -> MsgClassShowAndSave -> Text -> Text -> m ()
feelLook MsgClassShowAndSave
MsgBadMiscEvent MsgClassShowAndSave
MsgGoodMiscEvent Text
bigAdj Text
projAdj
          -- We can't know here if the hit was in melee, ranged or
          -- even triggering a harmful item. However, let's not talk
          -- about armor before the player has the most basic one.
          -- for melee. Most of the time the first hit in the game is,
          -- in fact, from melee, so that's a sensible default.
          --
          -- Note that the @idamage@ is called piercing (or edged) damage,
          -- even though the distinction from impact damage is fleshed
          -- out only in Allure.
          Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
isOurCharacter
                Bool -> Bool -> Bool
&& Skill -> Skills -> X
Ability.getSk Skill
Ability.SkArmorMelee Skills
actorMaxSk X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
0) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
            MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"You took damage of a different kind than the normal piercing hit, which means your armor couldn't block any part of it. Normally, your HP (hit points, health) do not regenerate, so losing them is a big deal. Apply healing concoctions or take a long sleep to replenish your HP (but in this hectic environment not even uninterrupted resting that leads to sleep is easy)."
        feelLookHPGood :: Text -> Text -> m ()
feelLookHPGood = MsgClassShowAndSave -> MsgClassShowAndSave -> Text -> Text -> m ()
feelLook MsgClassShowAndSave
MsgGoodMiscEvent MsgClassShowAndSave
MsgBadMiscEvent
        feelLookCalm :: Text -> Text -> m ()
feelLookCalm Text
bigAdj Text
projAdj = Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
isAlive (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
          MsgClassShowAndSave -> MsgClassShowAndSave -> Text -> Text -> m ()
feelLook MsgClassShowAndSave
MsgEffectMinor MsgClassShowAndSave
MsgEffectMinor Text
bigAdj Text
projAdj
        -- Ignore @iid@, because it's usually obvious what item caused that
        -- and because the effects are not particularly disortienting.
        feelLook :: MsgClassShowAndSave -> MsgClassShowAndSave -> Text -> Text -> m ()
feelLook MsgClassShowAndSave
msgClassOur MsgClassShowAndSave
msgClassTheir Text
bigAdj Text
projAdj =
          let (Text
verb, Text
adjective) =
                if Actor -> Bool
bproj Actor
b
                then (Text
"get", Text
projAdj)
                else ( if Bool
isOurCharacter then Text
"feel" else Text
"look"
                     , if Bool
isAlive then Text
bigAdj else Text
projAdj )
                         -- dead body is an item, not a person
              msgClass :: MsgClassShowAndSave
msgClass = if | Actor -> Bool
bproj Actor
b -> MsgClassShowAndSave
MsgEffectMinor
                            | Bool
isOurCharacter -> MsgClassShowAndSave
msgClassOur
                            | Bool
otherwise -> MsgClassShowAndSave
msgClassTheir
          in MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
msgClass ActorId
aid (Part -> m ()) -> Part -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Text
verb Text -> Text -> Text
<+> Text
adjective
    case Effect
effect of
      IK.Burn{} -> do
        Text -> Text -> m ()
feelLookHPBad Text
"burned" Text
"scorched"
        let ps :: (Point, Point)
ps = (Actor -> Point
bpos Actor
b, Actor -> Point
bpos Actor
b)
        LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
b) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
twirlSplash (Point, Point)
ps Color
Color.BrRed Color
Color.Brown
      IK.Explode{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- lots of visual feedback
      IK.RefillHP X
p | X
p X -> X -> Bool
forall a. Eq a => a -> a -> Bool
== X
1 -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- no spam from regeneration
      IK.RefillHP X
p | X
p X -> X -> Bool
forall a. Eq a => a -> a -> Bool
== -X
1 -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- no spam from poison
      IK.RefillHP{} | Int64
hpDelta Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
> Int64
0 -> do
        Text -> Text -> m ()
feelLookHPGood Text
"healthier" Text
"mended"
        let ps :: (Point, Point)
ps = (Actor -> Point
bpos Actor
b, Actor -> Point
bpos Actor
b)
        LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
b) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
twirlSplash (Point, Point)
ps Color
Color.BrGreen Color
Color.Green
      IK.RefillHP{} -> do
        Text -> Text -> m ()
feelLookHPBad Text
"wounded" Text
"broken"
        let ps :: (Point, Point)
ps = (Actor -> Point
bpos Actor
b, Actor -> Point
bpos Actor
b)
        LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
b) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
twirlSplash (Point, Point)
ps Color
Color.BrRed Color
Color.Red
      IK.RefillCalm{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.RefillCalm{} | Actor -> Bool
bproj Actor
b -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.RefillCalm X
p | X
p X -> X -> Bool
forall a. Eq a => a -> a -> Bool
== X
1 -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- no spam from regen items
      IK.RefillCalm X
p | X
p X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
0 -> Text -> Text -> m ()
feelLookCalm Text
"calmer" Text
"stabilized"
      IK.RefillCalm X
_ -> Text -> Text -> m ()
feelLookCalm Text
"agitated" Text
"wobbly"
      Effect
IK.Dominate | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Effect
IK.Dominate -> do
        -- For subsequent messages use the proper name, never "you".
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
bUI
        if FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
fidSource then do
          -- Before domination, possibly not seen if actor (yet) not ours.
          if Actor -> Int64
bcalm Actor
b Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
== Int64
0  -- sometimes only a coincidence, but nm
          then MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"yield, under extreme pressure"
          else do
            let verb :: Part
verb = if Bool
isOurAlive
                       then Part
"black out, dominated by foes"
                       else Part
"decide abruptly to switch allegiance"
                -- Faction is being switched, so item that caused domination
                -- and vanished may not be known to the new faction.
                msuffix :: Maybe Part
msuffix = if ItemId
iid ItemId -> ItemId -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> ItemId
btrunk Actor
b Bool -> Bool -> Bool
|| ItemId
iid ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.notMember` ItemDict
itemD
                          then Maybe Part
forall a. Maybe a
Nothing
                          else Part -> Maybe Part
forall a. a -> Maybe a
Just (Part -> Maybe Part) -> Part -> Maybe Part
forall a b. (a -> b) -> a -> b
$ if Bool
isOurAlive
                                      then Part
"through"
                                      else Part
"under the influence of"
            MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
verb ItemId
iid Maybe Part
msuffix
          Text
fidNameRaw <- (State -> Text) -> m Text
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Text) -> m Text) -> (State -> Text) -> m Text
forall a b. (a -> b) -> a -> b
$ Faction -> Text
gname (Faction -> Text) -> (State -> Faction) -> State -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FactionDict -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! FactionId
fid) (FactionDict -> Faction)
-> (State -> FactionDict) -> State -> Faction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> FactionDict
sfactionD
          -- Avoid "controlled by Controlled foo".
          let fidName :: Text
fidName = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ [Text] -> [Text]
forall a. [a] -> [a]
tail ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.words Text
fidNameRaw
              verb :: Part
verb = Part
"be no longer controlled by"
          MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgLnAdd MsgClassShowAndSave
MsgEffectMajor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
            [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb, Text -> Part
MU.Text Text
fidName]
          Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
isOurAlive (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ColorMode -> Text -> m ()
forall (m :: * -> *). MonadClientUI m => ColorMode -> Text -> m ()
displayMoreKeep ColorMode
ColorFull Text
""  -- Ln makes it short
        else do
          -- After domination, possibly not seen, if actor (already) not ours.
          Text
fidSourceNameRaw <- (State -> Text) -> m Text
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Text) -> m Text) -> (State -> Text) -> m Text
forall a b. (a -> b) -> a -> b
$ Faction -> Text
gname (Faction -> Text) -> (State -> Faction) -> State -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FactionDict -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! FactionId
fidSource) (FactionDict -> Faction)
-> (State -> FactionDict) -> State -> Faction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> FactionDict
sfactionD
          -- Avoid "Controlled control".
          let fidSourceName :: Text
fidSourceName = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ [Text] -> [Text]
forall a. [a] -> [a]
tail ([Text] -> [Text]) -> [Text] -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> [Text]
T.words Text
fidSourceNameRaw
              verb :: Part
verb = Part
"be now under"
          MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMajor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
            [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb, Text -> Part
MU.Text Text
fidSourceName, Part
"control"]
      Effect
IK.Impress | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Effect
IK.Impress -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMinor ActorId
aid Part
"be awestruck"
      Effect
IK.PutToSleep | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Effect
IK.PutToSleep -> do
        let verb :: Part
verb = Part
"be put to sleep"
            msuffix :: Maybe Part
msuffix = Part -> Maybe Part
forall a. a -> Maybe a
Just (Part -> Maybe Part) -> Part -> Maybe Part
forall a b. (a -> b) -> a -> b
$ if FactionId
fidSource FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> FactionId
bfid Actor
b then Part
"due to" else Part
"by"
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMajor ActorId
aid Part
verb ItemId
iid Maybe Part
msuffix
      Effect
IK.Yell | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Effect
IK.Yell -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgMiscellanous ActorId
aid Part
"start"
      IK.Summon GroupName ItemKind
grp Dice
p -> do
        let verbBase :: Part
verbBase = if Actor -> Bool
bproj Actor
b then Part
"lure" else Part
"summon"
            part :: Part
part = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ GroupName ItemKind -> Text
forall c. GroupName c -> Text
displayGroupName GroupName ItemKind
grp
            object :: Part
object = if Dice
p Dice -> Dice -> Bool
forall a. Eq a => a -> a -> Bool
== Dice
1  -- works, because exact number sent, not dice
                     then Part -> Part
MU.AW Part
part
                     else Part -> Part
MU.Ws Part
part
            verb :: Part
verb = [Part] -> Part
MU.Phrase [Part
verbBase, Part
object]
            msuffix :: Maybe Part
msuffix = Part -> Maybe Part
forall a. a -> Maybe a
Just Part
"with"
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMajor ActorId
aid Part
verb ItemId
iid Maybe Part
msuffix
      IK.Ascend{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.Ascend Bool
up -> do
        COps{ContentData CaveKind
cocave :: COps -> ContentData CaveKind
cocave :: ContentData CaveKind
cocave} <- (State -> COps) -> m COps
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> COps
scops
        MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMajor ActorId
aid (Part -> m ()) -> Part -> m ()
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$
          Text
"find a way" Text -> Text -> Text
<+> if Bool
up then Text
"upstairs" else Text
"downstairs"
        Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
isOurLeader (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
          [(LevelId, Point)]
destinations <- (State -> [(LevelId, Point)]) -> m [(LevelId, Point)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(LevelId, Point)]) -> m [(LevelId, Point)])
-> (State -> [(LevelId, Point)]) -> m [(LevelId, Point)]
forall a b. (a -> b) -> a -> b
$ LevelId -> Point -> Bool -> Dungeon -> [(LevelId, Point)]
whereTo (Actor -> LevelId
blid Actor
b) (Actor -> Point
bpos Actor
b) Bool
up
                                      (Dungeon -> [(LevelId, Point)])
-> (State -> Dungeon) -> State -> [(LevelId, Point)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> Dungeon
sdungeon
          case [(LevelId, Point)]
destinations of
            (LevelId
lid, Point
_) : [(LevelId, Point)]
_ -> do  -- only works until different levels possible
              Level
lvl <- LevelId -> m Level
forall (m :: * -> *). MonadStateRead m => LevelId -> m Level
getLevel LevelId
lid
              let desc :: Text
desc = CaveKind -> Text
cdesc (CaveKind -> Text) -> CaveKind -> Text
forall a b. (a -> b) -> a -> b
$ ContentData CaveKind -> ContentId CaveKind -> CaveKind
forall a. ContentData a -> ContentId a -> a
okind ContentData CaveKind
cocave (ContentId CaveKind -> CaveKind) -> ContentId CaveKind -> CaveKind
forall a b. (a -> b) -> a -> b
$ Level -> ContentId CaveKind
lkind Level
lvl
              Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Text -> Bool
T.null Text
desc) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
                MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgBackdropInfo (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ Text
desc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n"
              MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"New floor is new opportunities, though the old level is still there and others may roam it after you left. Viewing all floors, without moving between them, can be done using the '<' and '>' keys."
            [] -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- spell fizzles; normally should not be sent
      IK.Escape{} | Bool
isOurCharacter -> do
        [(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
        Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([(ActorId, Actor)] -> X
forall a. [a] -> X
length [(ActorId, Actor)]
ours X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
1) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
          (EnumMap ItemId ItemQuant
_, X
total) <- (State -> (EnumMap ItemId ItemQuant, X))
-> m (EnumMap ItemId ItemQuant, X)
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> (EnumMap ItemId ItemQuant, X))
 -> m (EnumMap ItemId ItemQuant, X))
-> (State -> (EnumMap ItemId ItemQuant, X))
-> m (EnumMap ItemId ItemQuant, X)
forall a b. (a -> b) -> a -> b
$ FactionId -> State -> (EnumMap ItemId ItemQuant, X)
calculateTotal FactionId
side
          if X
total X -> X -> Bool
forall a. Eq a => a -> a -> Bool
== X
0
          then MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgFactionIntel (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
                 Text
"The team joins" Text -> Text -> Text
<+> [Part] -> Text
makePhrase [ActorUI -> Part
partActor ActorUI
bUI]
                 Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", forms a perimeter and leaves triumphant."
          else MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgItemCreation (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
                 Text
"The team joins" Text -> Text -> Text
<+> [Part] -> Text
makePhrase [ActorUI -> Part
partActor ActorUI
bUI]
                 Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", forms a perimeter, repacks its belongings and leaves triumphant."
      IK.Escape{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.Paralyze{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.Paralyze{} ->
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"be paralyzed" ItemId
iid (Part -> Maybe Part
forall a. a -> Maybe a
Just Part
"with")
      IK.ParalyzeInWater{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.ParalyzeInWater{} ->
        MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMinor ActorId
aid Part
"move with difficulty"
      IK.InsertMove{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.InsertMove Dice
d ->
        -- Usually self-inflicted of from embeds, so obvious, so no @iid@.
        if Dice -> X
Dice.supDice Dice
d X -> X -> Bool
forall a. Ord a => a -> a -> Bool
>= X
10
        then MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"act with extreme speed"
        else do
          let msgClass :: MsgClassShowAndSave
msgClass = if Bool
isOurCharacter
                         then MsgClassShowAndSave
MsgEffectMedium
                         else MsgClassShowAndSave
MsgEffectMinor
          MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
msgClass ActorId
aid Part
"move swiftly"
      IK.Teleport Dice
t | Dice -> X
Dice.supDice Dice
t X -> X -> Bool
forall a. Ord a => a -> a -> Bool
<= X
9 -> do
        -- Actor may be sent away before noticing the item that did it.
        let msuffix :: Maybe Part
msuffix = if ItemId
iid ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.notMember` ItemDict
itemD
                      then Maybe Part
forall a. Maybe a
Nothing
                      else Part -> Maybe Part
forall a. a -> Maybe a
Just Part
"due to"
            msgClass :: MsgClassShowAndSave
msgClass = if Bool
isOurCharacter
                       then MsgClassShowAndSave
MsgEffectMedium
                       else MsgClassShowAndSave
MsgEffectMinor
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
msgClass ActorId
aid Part
"blink" ItemId
iid Maybe Part
msuffix
      IK.Teleport{} -> do
        -- Actor may be sent away before noticing the item that did it.
        let msuffix :: Maybe Part
msuffix = if ItemId
iid ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.notMember` ItemDict
itemD
                      then Maybe Part
forall a. Maybe a
Nothing
                      else Part -> Maybe Part
forall a. a -> Maybe a
Just Part
"by the power of"
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"teleport" ItemId
iid Maybe Part
msuffix
      IK.CreateItem{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.DestroyItem{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.ConsumeItems{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.DropItem X
_ X
_ CStore
COrgan GroupName ItemKind
_ -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.DropItem{} ->  -- rare enough
        MsgClassShowAndSave
-> ActorId -> Part -> ItemId -> Maybe Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> ItemId -> Maybe Part -> m ()
mitemAidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"be stripped" ItemId
iid (Part -> Maybe Part
forall a. a -> Maybe a
Just Part
"with")
      IK.Recharge{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.Recharge{} -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"heat up"
      IK.Discharge{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.Discharge{} -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"cool down"
      Effect
IK.PolyItem -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        let ppstore :: Part
ppstore = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ CStore -> Text
ppCStoreIn CStore
CGround
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMedium (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
          [ Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
"repurpose", Part
"what lies", Part
ppstore
          , Part
"to a common item of the current level" ]
      Effect
IK.RerollItem -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        let ppstore :: Part
ppstore = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ CStore -> Text
ppCStoreIn CStore
CGround
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMedium (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
          [ Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
"reshape", Part
"what lies", Part
ppstore
          , Part
"striving for the highest possible standards" ]
      Effect
IK.DupItem -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        let ppstore :: Part
ppstore = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ CStore -> Text
ppCStoreIn CStore
CGround
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMedium (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
          [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
"multiply", Part
"what lies", Part
ppstore]
      Effect
IK.Identify -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        Part
pronoun <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partPronounLeader ActorId
aid
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMinor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence
          [ Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
"look at"
          , Part -> Part -> Part
MU.WownW Part
pronoun (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text Text
"inventory"
          , Part
"intensely" ]
      IK.Detect DetectKind
d X
_ -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        FactionDict
factionD <- (State -> FactionDict) -> m FactionDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> FactionDict
sfactionD
        Time
localTime <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Time) -> m Time) -> (State -> Time) -> m Time
forall a b. (a -> b) -> a -> b
$ LevelId -> State -> Time
getLocalTime (LevelId -> State -> Time) -> LevelId -> State -> Time
forall a b. (a -> b) -> a -> b
$ Actor -> LevelId
blid Actor
b
        let verb :: Part
verb = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ DetectKind -> Text
detectToVerb DetectKind
d
            object :: Part
object = Part -> Part
MU.Ws (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ DetectKind -> Text
detectToObject DetectKind
d
        (Bool
periodic, ItemFull
itemFull) <-
          if ItemId
iid ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.member` ItemDict
itemD then do
            ItemFull
itemFull <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
            let arItem :: AspectRecord
arItem = ItemFull -> AspectRecord
aspectRecordFull ItemFull
itemFull
            (Bool, ItemFull) -> m (Bool, ItemFull)
forall (m :: * -> *) a. Monad m => a -> m a
return (Flag -> AspectRecord -> Bool
IA.checkFlag Flag
Ability.Periodic AspectRecord
arItem, ItemFull
itemFull)
          else do
#ifdef WITH_EXPENSIVE_ASSERTIONS
            -- It's not actually expensive, but it's particularly likely
            -- to fail with wild content, indicating server game rules logic
            -- needs to be fixed/extended:
            -- Observer from another faction may receive the effect information
            -- from the server, because the affected actor is visible,
            -- but the position of the item may be out of FOV. This is fine;
            -- the message is then shorter, because only the effect was seen,
            -- while the cause remains misterious.
            let !_A :: ()
_A = if FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
side  -- not from affected faction; observing
                      then ()
                      else [ContentSymbol ItemKind] -> ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> ()) -> [ContentSymbol ItemKind] -> ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"item never seen by the affected actor"
                                   [ContentSymbol ItemKind]
-> (ActorId, Actor, ActorUI, Part, ItemId, SfxAtomic)
-> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` (ActorId
aid, Actor
b, ActorUI
bUI, Part
verb, ItemId
iid, SfxAtomic
sfx)
#endif
            (Bool, ItemFull) -> m (Bool, ItemFull)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, ItemFull
forall a. HasCallStack => a
undefined)
        let iidDesc :: Text
iidDesc =
              let (Part
name1, Part
powers) = X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItemShort X
rwidth FactionId
side FactionDict
factionD Time
localTime
                                                  ItemFull
itemFull ItemQuant
quantSingle
              in [Part] -> Text
makePhrase [Part
"the", Part
name1, Part
powers]
            -- If item not periodic, most likely intentional, so don't spam.
            means :: [Part]
means = [Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Text
"(via" Text -> Text -> Text
<+> Text
iidDesc Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")" | Bool
periodic]
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMinor (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
          [Part] -> Text
makeSentence ([Part] -> Text) -> [Part] -> Text
forall a b. (a -> b) -> a -> b
$ [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb] [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part
object] [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
means
        -- Don't make it modal if all info remains after no longer seen.
        Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
side Bool -> Bool -> Bool
|| DetectKind
d DetectKind -> [DetectKind] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [DetectKind
IK.DetectHidden, DetectKind
IK.DetectExit]) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
          ColorMode -> Text -> m ()
forall (m :: * -> *). MonadClientUI m => ColorMode -> Text -> m ()
displayMore ColorMode
ColorFull Text
""  -- the sentence short
      IK.SendFlying{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.SendFlying{} -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"be sent flying"
      IK.PushActor{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.PushActor{} -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"be pushed"
      IK.PullActor{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.PullActor{} -> MsgClassShowAndSave -> ActorId -> Part -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ActorId -> Part -> m ()
aidVerbMU MsgClassShowAndSave
MsgEffectMedium ActorId
aid Part
"be pulled"
      Effect
IK.ApplyPerfume ->
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMinor
               Text
"The fragrance quells all scents in the vicinity."
      IK.AtMostOneOf{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.OneOf{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.OnSmash{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.OnCombine{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.OnUser{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      Effect
IK.NopEffect -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.AndEffect{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.OrEffect{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.SeqEffect{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.When{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.Unless{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.IfThenElse{} -> [ContentSymbol ItemKind] -> m ()
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> m ())
-> [ContentSymbol ItemKind] -> m ()
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind] -> SfxAtomic -> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` SfxAtomic
sfx
      IK.VerbNoLonger{} | Bool -> Bool
not Bool
isAlive -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      IK.VerbNoLonger Text
verb Text
ending -> do
        let msgClass :: MsgClassShowAndSave
msgClass = if FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side
                       then MsgClassShowAndSave
MsgStatusStopUs
                       else MsgClassShowAndSave
MsgStatusStopThem
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgClass (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
          [Part] -> Text
makePhrase [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
subject (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text Text
verb]
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
ending
      IK.VerbMsg Text
verb Text
ending -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgEffectMedium (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
          [Part] -> Text
makePhrase [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
subject (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text Text
verb]
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
ending
      IK.VerbMsgFail Text
verb Text
ending -> do
        Part
subject <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
        MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgActionWarning (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
          [Part] -> Text
makePhrase [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
subject (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text Text
verb]
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
ending
  SfxItemApplied ItemId
iid Container
c ->
    MsgClassSave -> ItemId -> ItemQuant -> Part -> Container -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> ItemId -> ItemQuant -> Part -> Container -> m ()
itemVerbMU MsgClassSave
MsgInnerWorkSpam ItemId
iid (X
1, []) Part
"have been triggered" Container
c
  SfxMsgFid FactionId
_ SfxMsg
sfxMsg -> do
    Maybe ActorId
mleader <- (StateClient -> Maybe ActorId) -> m (Maybe ActorId)
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> Maybe ActorId
sleader
    case Maybe ActorId
mleader of
      Just{} -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()  -- will flush messages when leader moves
      Maybe ActorId
Nothing -> do
        LevelId
lidV <- m LevelId
forall (m :: * -> *). MonadClientUI m => m LevelId
viewedLevelUI
        LevelId -> m ()
forall (m :: * -> *). MonadClientUI m => LevelId -> m ()
markDisplayNeeded LevelId
lidV
        m ()
forall (m :: * -> *). MonadClientUI m => m ()
recordHistory
    Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
mmsg <- SfxMsg
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
SfxMsg
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
ppSfxMsg SfxMsg
sfxMsg
    case Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
mmsg of
      Just (Left (MsgClassShowAndSave
msgClass, Text
msg)) -> MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgClass Text
msg
      Just (Right (MsgClassDistinct
msgClass, (Text
t1, Text
t2))) -> do
        let dotsIfShorter :: Text
dotsIfShorter = if Text
t1 Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
t2 then Text
"" else Text
".."
        MsgClassDistinct -> (Text, Text) -> m ()
forall (m :: * -> *).
MonadClientUI m =>
MsgClassDistinct -> (Text, Text) -> m ()
msgAddDistinct MsgClassDistinct
msgClass  (Text
t1 Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
dotsIfShorter, Text
t2)
      Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
Nothing -> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  SfxAtomic
SfxRestart -> Bool -> m ()
forall (m :: * -> *). MonadClientUI m => Bool -> m ()
fadeOutOrIn Bool
True
  SfxCollideTile ActorId
source Point
pos -> do
    COps{ContentData TileKind
cotile :: ContentData TileKind
cotile :: COps -> ContentData TileKind
cotile} <- (State -> COps) -> m COps
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> COps
scops
    Actor
sb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
    Level
lvl <- LevelId -> m Level
forall (m :: * -> *). MonadStateRead m => LevelId -> m Level
getLevel (LevelId -> m Level) -> LevelId -> m Level
forall a b. (a -> b) -> a -> b
$ Actor -> LevelId
blid Actor
sb
    Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
source
    let object :: Part
object = Part -> Part
MU.AW (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ TileKind -> Text
TK.tname (TileKind -> Text) -> TileKind -> Text
forall a b. (a -> b) -> a -> b
$ ContentData TileKind -> ContentId TileKind -> TileKind
forall a. ContentData a -> ContentId a -> a
okind ContentData TileKind
cotile (ContentId TileKind -> TileKind) -> ContentId TileKind -> TileKind
forall a b. (a -> b) -> a -> b
$ Level
lvl Level -> Point -> ContentId TileKind
`at` Point
pos
    -- Neutral message, because minor damage and we don't say, which faction.
    MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgNeutralEvent (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$! [Part] -> Text
makeSentence
      [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"collide", Part
"painfully with", Part
object]
  SfxTaunt Bool
voluntary ActorId
aid -> do
    FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Actor -> Bool
bproj Actor
b Bool -> Bool -> Bool
&& Actor -> FactionId
bfid Actor
b FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do  -- don't spam
      Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
aid
      (Text
_heardSubject, Text
verb) <- Bool
-> (Rnd (Text, Text) -> m (Text, Text))
-> ActorId
-> m (Text, Text)
forall (m :: * -> *).
MonadStateRead m =>
Bool
-> (Rnd (Text, Text) -> m (Text, Text))
-> ActorId
-> m (Text, Text)
displayTaunt Bool
voluntary Rnd (Text, Text) -> m (Text, Text)
forall (m :: * -> *) a. MonadClientUI m => Rnd a -> m a
rndToActionUI ActorId
aid
      let msgClass :: MsgClassShowAndSave
msgClass = if Bool
voluntary Bool -> Bool -> Bool
&& Actor -> FactionId
bfid Actor
b FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side
                     then MsgClassShowAndSave
MsgActionComplete  -- give feedback after keypress
                     else MsgClassShowAndSave
MsgMiscellanous
      MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgClass (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$! [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
spart (Text -> Part
MU.Text Text
verb)]

returnJustLeft :: MonadClientUI m
               => (MsgClassShowAndSave, Text)
               -> m (Maybe (Either (MsgClassShowAndSave, Text)
                                   (MsgClassDistinct, (Text, Text))))
returnJustLeft :: (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft = Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe
   (Either
      (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
 -> m (Maybe
         (Either
            (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))))
-> ((MsgClassShowAndSave, Text)
    -> Maybe
         (Either
            (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
-> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. a -> Maybe a
Just (Either
   (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
 -> Maybe
      (Either
         (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
-> ((MsgClassShowAndSave, Text)
    -> Either
         (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> (MsgClassShowAndSave, Text)
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MsgClassShowAndSave, Text)
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
forall a b. a -> Either a b
Left

ppSfxMsg :: MonadClientUI m
         => SfxMsg -> m (Maybe (Either (MsgClassShowAndSave, Text)
                                       (MsgClassDistinct, (Text, Text))))
ppSfxMsg :: SfxMsg
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
ppSfxMsg SfxMsg
sfxMsg = case SfxMsg
sfxMsg of
  SfxUnexpected ReqFailure
reqFailure -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"Unexpected problem:" Text -> Text -> Text
<+> ReqFailure -> Text
showReqFailure ReqFailure
reqFailure Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxExpected Text
itemName ReqFailure
reqFailure -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"The" Text -> Text -> Text
<+> Text
itemName Text -> Text -> Text
<+> Text
"is not triggered:"
      Text -> Text -> Text
<+> ReqFailure -> Text
showReqFailure ReqFailure
reqFailure Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxExpectedEmbed ItemId
iid LevelId
lid ReqFailure
reqFailure -> do
    Bool
iidSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ItemId
iid (ItemDict -> Bool) -> (State -> ItemDict) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> ItemDict
sitemD
    if Bool
iidSeen then do
      ItemFull
itemFull <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
      FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
      FactionDict
factionD <- (State -> FactionDict) -> m FactionDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> FactionDict
sfactionD
      Time
localTime <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Time) -> m Time) -> (State -> Time) -> m Time
forall a b. (a -> b) -> a -> b
$ LevelId -> State -> Time
getLocalTime LevelId
lid
      let (Part
object1, Part
object2) =
            X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItemShortest X
forall a. Bounded a => a
maxBound FactionId
side FactionDict
factionD Time
localTime
                             ItemFull
itemFull ItemQuant
quantSingle
          name :: Text
name = [Part] -> Text
makePhrase [Part
object1, Part
object2]
      (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
        ( MsgClassShowAndSave
MsgActionWarning
        , Text
"The" Text -> Text -> Text
<+> Text
"embedded" Text -> Text -> Text
<+> Text
name Text -> Text -> Text
<+> Text
"is not activated:"
          Text -> Text -> Text
<+> ReqFailure -> Text
showReqFailure ReqFailure
reqFailure Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
    else Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
  SfxFizzles ItemId
iid Container
c -> do
    Text
msg <- Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
forall (m :: * -> *).
MonadClientUI m =>
Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
itemVerbMUGeneral Bool
True ItemId
iid (X
1, []) Part
"do not work" Container
c
    Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe
   (Either
      (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
 -> m (Maybe
         (Either
            (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall a b. (a -> b) -> a -> b
$ Either (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. a -> Maybe a
Just (Either
   (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
 -> Maybe
      (Either
         (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a b. (a -> b) -> a -> b
$ (MsgClassDistinct, (Text, Text))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
forall a b. b -> Either a b
Right (MsgClassDistinct
MsgStatusWarning, (Text
"It didn't work.", Text
msg))
  SfxNothingHappens ItemId
iid Container
c -> do
    Text
msg <- Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
forall (m :: * -> *).
MonadClientUI m =>
Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
itemVerbMUGeneral Bool
True ItemId
iid (X
1, []) Part
"do nothing, predictably" Container
c
    Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe
   (Either
      (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
 -> m (Maybe
         (Either
            (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall a b. (a -> b) -> a -> b
$ Either (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. a -> Maybe a
Just (Either
   (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
 -> Maybe
      (Either
         (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a b. (a -> b) -> a -> b
$ (MsgClassDistinct, (Text, Text))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
forall a b. b -> Either a b
Right (MsgClassDistinct
MsgStatusBenign, (Text
"Nothing happens.", Text
msg))
  SfxNoItemsForTile [[(X, GroupName ItemKind)]]
toolsToAlterWith -> do
    HumanCmd -> KM
revCmd <- m (HumanCmd -> KM)
forall (m :: * -> *). MonadClientUI m => m (HumanCmd -> KM)
revCmdMap
    let km :: KM
km = HumanCmd -> KM
revCmd HumanCmd
HumanCmd.AlterDir
        tItems :: Text
tItems = [[(X, GroupName ItemKind)]] -> Text
describeToolsAlternative [[(X, GroupName ItemKind)]]
toolsToAlterWith
    (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft ( MsgClassShowAndSave
MsgActionWarning
                   , Text
"To transform the terrain, prepare the following items on the ground or in equipment:"
                     Text -> Text -> Text
<+> Text
tItems
                     Text -> Text -> Text
<+> Text
"and use the '"
                     Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [ContentSymbol ItemKind] -> Text
T.pack (KM -> [ContentSymbol ItemKind]
K.showKM KM
km)
                     Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"' terrain modification command."
                   )
  SfxVoidDetection DetectKind
d -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgMiscellanous
    , [Part] -> Text
makeSentence [Part
"no new", Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ DetectKind -> Text
detectToObject DetectKind
d, Part
"detected"] )
  SfxUnimpressed ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"be unimpressed"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft ( MsgClassShowAndSave
MsgActionWarning
                       , [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb] )
  SfxSummonLackCalm ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"lack Calm to summon"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft ( MsgClassShowAndSave
MsgActionWarning
                       , [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb] )
  SfxSummonTooManyOwn ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"can't keep track of their numerous friends, let alone summon any more"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft (MsgClassShowAndSave
MsgActionWarning, [Part] -> Text
makeSentence [Part
subject, Part
verb])
  SfxSummonTooManyAll ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"can't keep track of everybody around, let alone summon anyone else"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft (MsgClassShowAndSave
MsgActionWarning, [Part] -> Text
makeSentence [Part
subject, Part
verb])
  SfxSummonFailure ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"fail to summon anything"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft ( MsgClassShowAndSave
MsgActionWarning
                       , [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb] )
  SfxMsg
SfxLevelNoMore -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"No more levels in this direction.")
  SfxMsg
SfxLevelPushed -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"You notice somebody pushed to another level.")
  SfxBracedImmune ActorId
aid -> do
    Maybe ActorUI
msbUI <- (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI))
-> (SessionUI -> Maybe ActorUI) -> m (Maybe ActorUI)
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId ActorUI -> Maybe ActorUI
forall k a. Enum k => k -> EnumMap k a -> Maybe a
EM.lookup ActorId
aid (EnumMap ActorId ActorUI -> Maybe ActorUI)
-> (SessionUI -> EnumMap ActorId ActorUI)
-> SessionUI
-> Maybe ActorUI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SessionUI -> EnumMap ActorId ActorUI
sactorUI
    case Maybe ActorUI
msbUI of
      Maybe ActorUI
Nothing -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
      Just ActorUI
sbUI -> do
        let subject :: Part
subject = ActorUI -> Part
partActor ActorUI
sbUI
            verb :: Part
verb = Part
"be braced and so immune to translocation"
        (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft ( MsgClassShowAndSave
MsgMiscellanous
                       , [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
subject Part
verb] )
                         -- too common
  SfxMsg
SfxEscapeImpossible -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"Escaping outside is unthinkable for members of this faction." )
  SfxMsg
SfxStasisProtects -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgMiscellanous  -- too common
    , Text
"Paralysis and speed surge require recovery time." )
  SfxMsg
SfxWaterParalysisResisted -> Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing  -- don't spam
  SfxMsg
SfxTransImpossible -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Translocation not possible.")
  SfxMsg
SfxIdentifyNothing -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Nothing to identify.")
  SfxMsg
SfxPurposeNothing -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"The purpose of repurpose cannot be availed without an item"
      Text -> Text -> Text
<+> CStore -> Text
ppCStoreIn CStore
CGround Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxPurposeTooFew X
maxCount X
itemK -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"The purpose of repurpose is served by" Text -> Text -> Text
<+> X -> Text
forall a. Show a => a -> Text
tshow X
maxCount
      Text -> Text -> Text
<+> Text
"pieces of this item, not by" Text -> Text -> Text
<+> X -> Text
forall a. Show a => a -> Text
tshow X
itemK Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxMsg
SfxPurposeUnique -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Unique items can't be repurposed.")
  SfxMsg
SfxPurposeNotCommon -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Only ordinary common items can be repurposed.")
  SfxMsg
SfxRerollNothing -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"The shape of reshape cannot be assumed without an item"
      Text -> Text -> Text
<+> CStore -> Text
ppCStoreIn CStore
CGround Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxMsg
SfxRerollNotRandom -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Only items of variable shape can be reshaped.")
  SfxMsg
SfxDupNothing -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgActionWarning
    , Text
"Mutliplicity won't rise above zero without an item"
      Text -> Text -> Text
<+> CStore -> Text
ppCStoreIn CStore
CGround Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." )
  SfxMsg
SfxDupUnique -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Unique items can't be multiplied.")
  SfxMsg
SfxDupValuable -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    (MsgClassShowAndSave
MsgActionWarning, Text
"Valuable items can't be multiplied.")
  SfxMsg
SfxColdFish -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgMiscellanous  -- repeatable
    , Text
"Healing attempt from another faction is thwarted by your cold fish attitude." )
  SfxMsg
SfxReadyGoods -> (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
    ( MsgClassShowAndSave
MsgMiscellanous  -- repeatable
    , Text
"Crafting is alien to you, accustomed to buying ready goods all your life." )
  SfxTimerExtended ActorId
aid ItemId
iid CStore
cstore Delta Time
delta -> do
    CCUI{coscreen :: CCUI -> ScreenContent
coscreen=ScreenContent{X
rwidth :: X
rwidth :: ScreenContent -> X
rwidth}} <- (SessionUI -> CCUI) -> m CCUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
    Bool
aidSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId Actor -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ActorId
aid (EnumMap ActorId Actor -> Bool)
-> (State -> EnumMap ActorId Actor) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap ActorId Actor
sactorD
    Bool
iidSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ItemId
iid (ItemDict -> Bool) -> (State -> ItemDict) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> ItemDict
sitemD
    if Bool
aidSeen Bool -> Bool -> Bool
&& Bool
iidSeen then do
      Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
      ActorUI
bUI <- (SessionUI -> ActorUI) -> m ActorUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> ActorUI) -> m ActorUI)
-> (SessionUI -> ActorUI) -> m ActorUI
forall a b. (a -> b) -> a -> b
$ ActorId -> SessionUI -> ActorUI
getActorUI ActorId
aid
      FactionDict
factionD <- (State -> FactionDict) -> m FactionDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> FactionDict
sfactionD
      Time
localTime <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Time) -> m Time) -> (State -> Time) -> m Time
forall a b. (a -> b) -> a -> b
$ LevelId -> State -> Time
getLocalTime (Actor -> LevelId
blid Actor
b)
      ItemFull
itemFull <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
      FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
      EnumMap ItemId ItemQuant
bag <- (State -> EnumMap ItemId ItemQuant) -> m (EnumMap ItemId ItemQuant)
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> EnumMap ItemId ItemQuant)
 -> m (EnumMap ItemId ItemQuant))
-> (State -> EnumMap ItemId ItemQuant)
-> m (EnumMap ItemId ItemQuant)
forall a b. (a -> b) -> a -> b
$ Actor -> CStore -> State -> EnumMap ItemId ItemQuant
getBodyStoreBag Actor
b CStore
cstore
      let (Part
name, Part
powers) =
            X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItem X
rwidth (Actor -> FactionId
bfid Actor
b) FactionDict
factionD Time
localTime ItemFull
itemFull ItemQuant
quantSingle
          total :: Delta Time
total = case EnumMap ItemId ItemQuant
bag EnumMap ItemId ItemQuant -> ItemId -> ItemQuant
forall k a. Enum k => EnumMap k a -> k -> a
EM.! ItemId
iid of
            (X
_, []) -> [ContentSymbol ItemKind] -> Delta Time
forall a. HasCallStack => [ContentSymbol ItemKind] -> a
error ([ContentSymbol ItemKind] -> Delta Time)
-> [ContentSymbol ItemKind] -> Delta Time
forall a b. (a -> b) -> a -> b
$ [ContentSymbol ItemKind]
"" [ContentSymbol ItemKind]
-> (EnumMap ItemId ItemQuant, ItemId, ActorId, CStore, Delta Time)
-> [ContentSymbol ItemKind]
forall v.
Show v =>
[ContentSymbol ItemKind] -> v -> [ContentSymbol ItemKind]
`showFailure` (EnumMap ItemId ItemQuant
bag, ItemId
iid, ActorId
aid, CStore
cstore, Delta Time
delta)
            (X
_, ItemTimer
t:[ItemTimer]
_) -> Time -> ItemTimer -> Delta Time
deltaOfItemTimer Time
localTime ItemTimer
t
              -- only exceptionally not singleton list
      [Part]
storeOwn <- (ActorId -> m Part) -> Bool -> Container -> m [Part]
forall (m :: * -> *).
MonadClientUI m =>
(ActorId -> m Part) -> Bool -> Container -> m [Part]
ppContainerWownW ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partPronounLeader Bool
True (ActorId -> CStore -> Container
CActor ActorId
aid CStore
cstore)
      -- Ideally we'd use a pronoun here, but the action (e.g., hit)
      -- that caused this extension can be invisible to some onlookers.
      -- So their narrative context needs to be taken into account.
      -- The upside is that the messages do not bind pronouns
      -- and so commute and so repetitions can be squashed.
      let cond :: [Part]
cond = [ Part
"condition"
                 | Flag -> AspectRecord -> Bool
IA.checkFlag Flag
Ability.Condition (AspectRecord -> Bool) -> AspectRecord -> Bool
forall a b. (a -> b) -> a -> b
$ ItemFull -> AspectRecord
aspectRecordFull ItemFull
itemFull ]
          usShow :: [Part]
usShow =
            [Part
"the", Part
name, Part
powers] [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
cond
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
storeOwn [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part
"will now last longer"]
          usSave :: [Part]
usSave =
            [Part
"the", Part
name, Part
powers] [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
cond
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
storeOwn [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part
"will now last"]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Delta Time -> Text
timeDeltaInSecondsText Delta Time
delta Text -> Text -> Text
<+> Text
"longer"]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Text
"(total:" Text -> Text -> Text
<+> Delta Time -> Text
timeDeltaInSecondsText Delta Time
total Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"]
          -- Note that when enemy actor causes the extension to himself,
          -- the player is not notified at all. So the shorter blurb
          -- displayed on the screen is middle ground and full is in history.
          themShow :: [Part]
themShow =
            [X
-> FactionId
-> FactionDict
-> Part
-> Time
-> ItemFull
-> ItemQuant
-> Part
partItemShortWownW X
rwidth FactionId
side FactionDict
factionD (ActorUI -> Part
partActor ActorUI
bUI) Time
localTime
                                ItemFull
itemFull ItemQuant
quantSingle]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
cond [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part
"is extended"]
          themSave :: [Part]
themSave =
            [X
-> FactionId
-> FactionDict
-> Part
-> Time
-> ItemFull
-> ItemQuant
-> Part
partItemShortWownW X
rwidth FactionId
side FactionDict
factionD (ActorUI -> Part
partActor ActorUI
bUI) Time
localTime
                                ItemFull
itemFull ItemQuant
quantSingle]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
cond [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part
"is extended by"]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Delta Time -> Text
timeDeltaInSecondsText Delta Time
delta]
            [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Text
"(total:" Text -> Text -> Text
<+> Delta Time -> Text
timeDeltaInSecondsText Delta Time
total Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"]
          (MsgClassDistinct
msgClass, [Part]
parts1, [Part]
parts2) =
            if Actor -> FactionId
bfid Actor
b FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side
            then (MsgClassDistinct
MsgStatusLongerUs, [Part]
usShow, [Part]
usSave)
            else (MsgClassDistinct
MsgStatusLongThem, [Part]
themShow, [Part]
themSave)
      Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe
   (Either
      (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
 -> m (Maybe
         (Either
            (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall a b. (a -> b) -> a -> b
$ Either (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. a -> Maybe a
Just (Either
   (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
 -> Maybe
      (Either
         (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
-> Maybe
     (Either
        (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a b. (a -> b) -> a -> b
$ (MsgClassDistinct, (Text, Text))
-> Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))
forall a b. b -> Either a b
Right
        (MsgClassDistinct
msgClass, ([Part] -> Text
makeSentence [Part]
parts1, [Part] -> Text
makeSentence [Part]
parts2))
    else Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
  SfxCollideActor ActorId
source ActorId
target -> do
    Bool
sourceSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId Actor -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ActorId
source (EnumMap ActorId Actor -> Bool)
-> (State -> EnumMap ActorId Actor) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap ActorId Actor
sactorD
    Bool
targetSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId Actor -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ActorId
target (EnumMap ActorId Actor -> Bool)
-> (State -> EnumMap ActorId Actor) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap ActorId Actor
sactorD
    if Bool
sourceSeen Bool -> Bool -> Bool
&& Bool
targetSeen then do
      Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
source
      Part
tpart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
target
      -- Neutral message, because minor damage and we don't say, which faction.
      -- And the collision may even be intentional.
      (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft
        ( MsgClassShowAndSave
MsgSpecialEvent
        , [Part] -> Text
makeSentence
            [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"collide", Part
"awkwardly with", Part
tpart] )
    else Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing
  SfxItemYield ItemId
iid X
k LevelId
lid -> do
    Bool
iidSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ItemId
iid (ItemDict -> Bool) -> (State -> ItemDict) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> ItemDict
sitemD
    if Bool
iidSeen then do
      let fakeKit :: ItemQuant
fakeKit = ItemQuant
quantSingle
          fakeC :: Container
fakeC = LevelId -> Point -> Container
CFloor LevelId
lid Point
originPoint
          verb :: Part
verb = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Text
"yield" Text -> Text -> Text
<+> [Part] -> Text
makePhrase [X -> Part -> Part
MU.CardinalAWs X
k Part
"item"]
      Text
msg <- Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
forall (m :: * -> *).
MonadClientUI m =>
Bool -> ItemId -> ItemQuant -> Part -> Container -> m Text
itemVerbMUGeneral Bool
False ItemId
iid ItemQuant
fakeKit Part
verb Container
fakeC
      (MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *).
MonadClientUI m =>
(MsgClassShowAndSave, Text)
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
returnJustLeft (MsgClassShowAndSave
MsgSpecialEvent, Text
msg)  -- differentiate wrt item creation
    else Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
-> m (Maybe
        (Either
           (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text))))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe
  (Either
     (MsgClassShowAndSave, Text) (MsgClassDistinct, (Text, Text)))
forall a. Maybe a
Nothing

strike :: MonadClientUI m => Bool -> ActorId -> ActorId -> ItemId -> m ()
strike :: Bool -> ActorId -> ActorId -> ItemId -> m ()
strike Bool
catch ActorId
source ActorId
target ItemId
iid = Bool -> m () -> m ()
forall a. HasCallStack => Bool -> a -> a
assert (ActorId
source ActorId -> ActorId -> Bool
forall a. Eq a => a -> a -> Bool
/= ActorId
target) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
  Bool
sourceSeen <- (State -> Bool) -> m Bool
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Bool) -> m Bool) -> (State -> Bool) -> m Bool
forall a b. (a -> b) -> a -> b
$ ActorId -> EnumMap ActorId Actor -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
EM.member ActorId
source (EnumMap ActorId Actor -> Bool)
-> (State -> EnumMap ActorId Actor) -> State -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap ActorId Actor
sactorD
  if Bool -> Bool
not Bool
sourceSeen then do
    Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
target
    LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Animation
blockMiss (Actor -> Point
bpos Actor
tb, Actor -> Point
bpos Actor
tb)
  else do
    CCUI{coscreen :: CCUI -> ScreenContent
coscreen=ScreenContent{X
rwidth :: X
rwidth :: ScreenContent -> X
rwidth}} <- (SessionUI -> CCUI) -> m CCUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
    Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
target
    X
hurtMult <- (State -> X) -> m X
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> X) -> m X) -> (State -> X) -> m X
forall a b. (a -> b) -> a -> b
$ ActorId -> ActorId -> State -> X
armorHurtBonus ActorId
source ActorId
target
    Actor
sb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
    Skills
sMaxSk <- (State -> Skills) -> m Skills
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Skills) -> m Skills) -> (State -> Skills) -> m Skills
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Skills
getActorMaxSkills ActorId
source
    Part
spart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
source
    Part
tpart <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partActorLeader ActorId
target
    Part
spronoun <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partPronounLeader ActorId
source
    Part
tpronoun <- ActorId -> m Part
forall (m :: * -> *). MonadClientUI m => ActorId -> m Part
partPronounLeader ActorId
target
    ActorUI
tbUI <- (SessionUI -> ActorUI) -> m ActorUI
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> ActorUI) -> m ActorUI)
-> (SessionUI -> ActorUI) -> m ActorUI
forall a b. (a -> b) -> a -> b
$ ActorId -> SessionUI -> ActorUI
getActorUI ActorId
target
    Time
localTime <- (State -> Time) -> m Time
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Time) -> m Time) -> (State -> Time) -> m Time
forall a b. (a -> b) -> a -> b
$ LevelId -> State -> Time
getLocalTime (Actor -> LevelId
blid Actor
tb)
    ItemFull
itemFullWeapon <- (State -> ItemFull) -> m ItemFull
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemFull) -> m ItemFull)
-> (State -> ItemFull) -> m ItemFull
forall a b. (a -> b) -> a -> b
$ ItemId -> State -> ItemFull
itemToFull ItemId
iid
    let kitWeapon :: ItemQuant
kitWeapon = ItemQuant
quantSingle
    FactionId
side <- (StateClient -> FactionId) -> m FactionId
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
    FactionDict
factionD <- (State -> FactionDict) -> m FactionDict
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> FactionDict
sfactionD
    Faction
tfact <- (State -> Faction) -> m Faction
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Faction) -> m Faction)
-> (State -> Faction) -> m Faction
forall a b. (a -> b) -> a -> b
$ (FactionDict -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! Actor -> FactionId
bfid Actor
tb) (FactionDict -> Faction)
-> (State -> FactionDict) -> State -> Faction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> FactionDict
sfactionD
    [(ItemId, ItemFullKit)]
eqpOrgKit <- (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)])
-> (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
forall a b. (a -> b) -> a -> b
$ ActorId -> [CStore] -> State -> [(ItemId, ItemFullKit)]
kitAssocs ActorId
target [CStore
CEqp, CStore
COrgan]
    [(ItemId, ItemFullKit)]
orgKit <- (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)])
-> (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
forall a b. (a -> b) -> a -> b
$ ActorId -> [CStore] -> State -> [(ItemId, ItemFullKit)]
kitAssocs ActorId
target [CStore
COrgan]
    let isCond :: (a, (ItemFull, b)) -> Bool
isCond (a
_, (ItemFull
itemFullArmor, b
_)) =
          Flag -> AspectRecord -> Bool
IA.checkFlag Flag
Ability.Condition (AspectRecord -> Bool) -> AspectRecord -> Bool
forall a b. (a -> b) -> a -> b
$ ItemFull -> AspectRecord
aspectRecordFull ItemFull
itemFullArmor
        -- We exclude genetic flaws, backstory items, etc., because they
        -- can't be easily taken off, so no point spamming the player.
        isOrdinaryCond :: (a, (ItemFull, b)) -> Bool
isOrdinaryCond ikit :: (a, (ItemFull, b))
ikit@(a
_, (ItemFull
itemFullArmor, b
_)) =
          Bool -> Bool
not (Flag -> AspectRecord -> Bool
IA.checkFlag Flag
Ability.MetaGame (ItemFull -> AspectRecord
aspectRecordFull ItemFull
itemFullArmor))
          Bool -> Bool -> Bool
&& (a, (ItemFull, b)) -> Bool
forall a b. (a, (ItemFull, b)) -> Bool
isCond (a, (ItemFull, b))
ikit
        relevantSkArmor :: Skill
relevantSkArmor =
          if Actor -> Bool
bproj Actor
sb then Skill
Ability.SkArmorRanged else Skill
Ability.SkArmorMelee
        rateArmor :: (ItemId, ItemFullKit) -> (X, (ItemId, ItemFull))
rateArmor (ItemId
iidArmor, (ItemFull
itemFullArmor, (X
k, [ItemTimer]
_))) =
          ( X
k X -> X -> X
forall a. Num a => a -> a -> a
* Skill -> AspectRecord -> X
IA.getSkill Skill
relevantSkArmor (ItemFull -> AspectRecord
aspectRecordFull ItemFull
itemFullArmor)
          , ( ItemId
iidArmor
            , ItemFull
itemFullArmor ) )
        abs15 :: (a, b) -> Bool
abs15 (a
v, b
_) = a -> a
forall a. Num a => a -> a
abs a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
15
        condArmor :: [(X, (ItemId, ItemFull))]
condArmor = ((X, (ItemId, ItemFull)) -> Bool)
-> [(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))]
forall a. (a -> Bool) -> [a] -> [a]
filter (X, (ItemId, ItemFull)) -> Bool
forall a b. (Ord a, Num a) => (a, b) -> Bool
abs15 ([(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))])
-> [(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> a -> b
$ ((ItemId, ItemFullKit) -> (X, (ItemId, ItemFull)))
-> [(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> [a] -> [b]
map (ItemId, ItemFullKit) -> (X, (ItemId, ItemFull))
rateArmor ([(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))])
-> [(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> a -> b
$ ((ItemId, ItemFullKit) -> Bool)
-> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)]
forall a. (a -> Bool) -> [a] -> [a]
filter (ItemId, ItemFullKit) -> Bool
forall a b. (a, (ItemFull, b)) -> Bool
isOrdinaryCond [(ItemId, ItemFullKit)]
orgKit
        fstGt0 :: (a, b) -> Bool
fstGt0 (a
v, b
_) = a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0
        wornArmor :: [(X, (ItemId, ItemFull))]
wornArmor =
          ((X, (ItemId, ItemFull)) -> Bool)
-> [(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))]
forall a. (a -> Bool) -> [a] -> [a]
filter (X, (ItemId, ItemFull)) -> Bool
forall a b. (Ord a, Num a) => (a, b) -> Bool
fstGt0 ([(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))])
-> [(X, (ItemId, ItemFull))] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> a -> b
$ ((ItemId, ItemFullKit) -> (X, (ItemId, ItemFull)))
-> [(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> [a] -> [b]
map (ItemId, ItemFullKit) -> (X, (ItemId, ItemFull))
rateArmor ([(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))])
-> [(ItemId, ItemFullKit)] -> [(X, (ItemId, ItemFull))]
forall a b. (a -> b) -> a -> b
$ ((ItemId, ItemFullKit) -> Bool)
-> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ((ItemId, ItemFullKit) -> Bool) -> (ItemId, ItemFullKit) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ItemId, ItemFullKit) -> Bool
forall a b. (a, (ItemFull, b)) -> Bool
isCond) [(ItemId, ItemFullKit)]
eqpOrgKit
    Maybe (ItemId, ItemFull)
mblockArmor <- case [(X, (ItemId, ItemFull))]
wornArmor of
      [] -> Maybe (ItemId, ItemFull) -> m (Maybe (ItemId, ItemFull))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (ItemId, ItemFull)
forall a. Maybe a
Nothing
      [(X, (ItemId, ItemFull))]
_ -> (ItemId, ItemFull) -> Maybe (ItemId, ItemFull)
forall a. a -> Maybe a
Just
           ((ItemId, ItemFull) -> Maybe (ItemId, ItemFull))
-> m (ItemId, ItemFull) -> m (Maybe (ItemId, ItemFull))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Rnd (ItemId, ItemFull) -> m (ItemId, ItemFull)
forall (m :: * -> *) a. MonadClientUI m => Rnd a -> m a
rndToActionUI (Frequency (ItemId, ItemFull) -> Rnd (ItemId, ItemFull)
forall a. Show a => Frequency a -> Rnd a
frequency (Frequency (ItemId, ItemFull) -> Rnd (ItemId, ItemFull))
-> Frequency (ItemId, ItemFull) -> Rnd (ItemId, ItemFull)
forall a b. (a -> b) -> a -> b
$ Text -> [(X, (ItemId, ItemFull))] -> Frequency (ItemId, ItemFull)
forall a. Text -> [(X, a)] -> Frequency a
toFreq Text
"msg armor" [(X, (ItemId, ItemFull))]
wornArmor)
    ActorMaxSkills
actorMaxSkills <- (State -> ActorMaxSkills) -> m ActorMaxSkills
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> ActorMaxSkills
sactorMaxSkills
    let ([Part]
blockWithWhat, Bool
blockWithWeapon) = case Maybe (ItemId, ItemFull)
mblockArmor of
          Just (ItemId
iidArmor, ItemFull
itemFullArmor) | ItemId
iidArmor ItemId -> ItemId -> Bool
forall a. Eq a => a -> a -> Bool
/= Actor -> ItemId
btrunk Actor
tb ->
            let (Part
object1, Part
object2) =
                  X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItemShortest X
rwidth (Actor -> FactionId
bfid Actor
tb) FactionDict
factionD Time
localTime
                                   ItemFull
itemFullArmor ItemQuant
quantSingle
                name :: Part
name = [Part] -> Part
MU.Phrase [Part
object1, Part
object2]
            in ( [Part
"with", Part -> Part -> Part
MU.WownW Part
tpronoun Part
name]
               , Dice -> X
Dice.supDice (ItemKind -> Dice
IK.idamage (ItemKind -> Dice) -> ItemKind -> Dice
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFullArmor) X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
0 )
          Maybe (ItemId, ItemFull)
_ -> ([], Bool
False)
        verb :: Part
verb = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ ItemKind -> Text
IK.iverbHit (ItemKind -> Text) -> ItemKind -> Text
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFullWeapon
        partItemChoice :: ItemFull -> ItemQuant -> Part
partItemChoice =
          if ItemId
iid ItemId -> EnumMap ItemId ItemQuant -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.member` Actor -> EnumMap ItemId ItemQuant
borgan Actor
sb
          then X
-> FactionId
-> FactionDict
-> Part
-> Time
-> ItemFull
-> ItemQuant
-> Part
partItemShortWownW X
rwidth FactionId
side FactionDict
factionD Part
spronoun Time
localTime
          else X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> Part
partItemShortAW X
rwidth FactionId
side FactionDict
factionD Time
localTime
        weaponNameWith :: [Part]
weaponNameWith = if ItemId
iid ItemId -> ItemId -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> ItemId
btrunk Actor
sb
                         then []
                         else [Part
"with", ItemFull -> ItemQuant -> Part
partItemChoice ItemFull
itemFullWeapon ItemQuant
kitWeapon]
        sleepy :: Part
sleepy = if Actor -> Watchfulness
bwatch Actor
tb Watchfulness -> [Watchfulness] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Watchfulness
WSleep, Watchfulness
WWake]
                    Bool -> Bool -> Bool
&& Part
tpart Part -> Part -> Bool
forall a. Eq a => a -> a -> Bool
/= Part
"you"
                    Bool -> Bool -> Bool
&& Actor -> Int64
bhp Actor
tb Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
> Int64
0
                 then Part
"the sleepy"
                 else Part
""
        unBurn :: Effect -> Maybe Dice
unBurn (IK.Burn Dice
d) = Dice -> Maybe Dice
forall a. a -> Maybe a
Just Dice
d
        unBurn Effect
_ = Maybe Dice
forall a. Maybe a
Nothing
        unRefillHP :: Effect -> Maybe X
unRefillHP (IK.RefillHP X
n) | X
n X -> X -> Bool
forall a. Ord a => a -> a -> Bool
< X
0 = X -> Maybe X
forall a. a -> Maybe a
Just (-X
n)
        unRefillHP Effect
_ = Maybe X
forall a. Maybe a
Nothing
        kineticDmg :: Int64
kineticDmg =
          let dmg :: X
dmg = Dice -> X
Dice.supDice (Dice -> X) -> Dice -> X
forall a b. (a -> b) -> a -> b
$ ItemKind -> Dice
IK.idamage (ItemKind -> Dice) -> ItemKind -> Dice
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFullWeapon
              rawDeltaHP :: Int64
rawDeltaHP = X -> Int64
forall target source. From source target => source -> target
into @Int64 X
sHurt Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
* X -> Int64
xM X
dmg Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
`divUp` Int64
100
          in case Actor -> Maybe ([Vector], Speed)
btrajectory Actor
sb of
            Just ([Vector]
_, Speed
speed) | Actor -> Bool
bproj Actor
sb ->
              - Int64 -> Speed -> Int64
modifyDamageBySpeed Int64
rawDeltaHP Speed
speed
            Maybe ([Vector], Speed)
_ -> - Int64
rawDeltaHP
        burnDmg :: X
burnDmg = - ([X] -> X
forall a. Num a => [a] -> a
sum ([X] -> X) -> [X] -> X
forall a b. (a -> b) -> a -> b
$ (Dice -> X) -> [Dice] -> [X]
forall a b. (a -> b) -> [a] -> [b]
map Dice -> X
Dice.supDice
                     ([Dice] -> [X]) -> [Dice] -> [X]
forall a b. (a -> b) -> a -> b
$ (Effect -> Maybe Dice) -> [Effect] -> [Dice]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Effect -> Maybe Dice
unBurn ([Effect] -> [Dice]) -> [Effect] -> [Dice]
forall a b. (a -> b) -> a -> b
$ ItemKind -> [Effect]
IK.ieffects (ItemKind -> [Effect]) -> ItemKind -> [Effect]
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFullWeapon)
        fillDmg :: X
fillDmg =
          - ([X] -> X
forall a. Num a => [a] -> a
sum ([X] -> X) -> [X] -> X
forall a b. (a -> b) -> a -> b
$ (Effect -> Maybe X) -> [Effect] -> [X]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Effect -> Maybe X
unRefillHP ([Effect] -> [X]) -> [Effect] -> [X]
forall a b. (a -> b) -> a -> b
$ ItemKind -> [Effect]
IK.ieffects (ItemKind -> [Effect]) -> ItemKind -> [Effect]
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFullWeapon)
        -- For variety, attack adverb is based on attacker's and weapon's
        -- damage potential as compared to victim's current HP.
        -- We are not taking into account victim's armor yet.
        sHurt :: X
sHurt = Bool -> Skills -> Skills -> X
armorHurtCalculation (Actor -> Bool
bproj Actor
sb) Skills
sMaxSk Skills
Ability.zeroSkills
        nonPiercingDmg :: X
nonPiercingDmg = X
burnDmg X -> X -> X
forall a. Num a => a -> a -> a
+ X
fillDmg
        sDamage :: Int64
sDamage = Int64 -> Int64 -> Int64
forall a. Ord a => a -> a -> a
min Int64
0 (Int64 -> Int64) -> Int64 -> Int64
forall a b. (a -> b) -> a -> b
$ Int64
kineticDmg Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
+ X -> Int64
xM X
nonPiercingDmg
        deadliness :: Int64
deadliness = Int64
1000 Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
* (- Int64
sDamage) Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
`div` Int64 -> Int64 -> Int64
forall a. Ord a => a -> a -> a
max Int64
1 (Actor -> Int64
bhp Actor
tb)
        strongly :: Part
strongly
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
10000 = Part
"artfully"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
5000 = Part
"madly"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2000 = Part
"mercilessly"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
1000 = Part
"murderously"  -- one blow can wipe out all HP
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
700 = Part
"devastatingly"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
500 = Part
"vehemently"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
400 = Part
"forcefully"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
350 = Part
"sturdily"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
300 = Part
"accurately"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
20 = Part
""  -- common, terse case, between 2% and 30%
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
10 = Part
"cautiously"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
5 = Part
"guardedly"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
3 = Part
"hesitantly"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2 = Part
"clumsily"
          | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
1 = Part
"haltingly"
          | Bool
otherwise = Part
"feebly"
        -- Here we take into account armor, so we look at @hurtMult@,
        -- so we finally convey the full info about effectiveness of the strike.
        blockHowWell :: Part
blockHowWell  -- under some conditions, the message not shown at all
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
90 = Part
"incompetently"
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
80 = Part
"too late"
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
70 = Part
"too slowly"
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
20 Bool -> Bool -> Bool
|| X
nonPiercingDmg X -> X -> Bool
forall a. Ord a => a -> a -> Bool
< X
0 =
                            if | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2000 -> Part
"marginally"
                               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
1000 -> Part
"partially"
                               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
100 -> Part
"partly"  -- common
                               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
50 -> Part
"to an extent"
                               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
20 -> Part
"to a large extent"
                               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
5 -> Part
"for the major part"
                               | Bool
otherwise -> Part
"for the most part"
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
1 = if | Actor -> Bool
actorWaits Actor
tb -> Part
"doggedly"
                              | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
50 -> Part
"easily"  -- common
                              | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
20 -> Part
"effortlessly"
                              | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
5 -> Part
"nonchalantly"
                              | Bool
otherwise -> Part
"bemusedly"
          | Bool
otherwise = Part
"almost completely"
              -- a fraction gets through, but if fast missile, can be deadly
        avertVerb :: Part
avertVerb = if Actor -> Bool
actorWaits Actor
tb then Part
"avert it" else Part
"ward it off"
        blockPhrase :: Part
blockPhrase =
          let (Part
subjectBlock, Part
verbBlock) =
                if | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Actor -> Bool
bproj Actor
sb ->
                     (Part
tpronoun, if Bool
blockWithWeapon
                                then Part
"parry"
                                else Part
"block")
                   | Part
tpronoun Part -> Part -> Bool
forall a. Eq a => a -> a -> Bool
== Part
"it"
                     Bool -> Bool -> Bool
|| Bool
projectileHitsWeakly Bool -> Bool -> Bool
&& Part
tpronoun Part -> Part -> Bool
forall a. Eq a => a -> a -> Bool
/= Part
"you" ->
                     -- Avoid ambiguity.
                     (ActorUI -> Part
partActor ActorUI
tbUI, Part
avertVerb)
                   | Bool
otherwise -> (Part
tpronoun, Part
avertVerb)
          in Part -> Part -> Part
MU.SubjectVerbSg Part
subjectBlock Part
verbBlock
        surprisinglyGoodDefense :: Bool
surprisinglyGoodDefense = Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
20 Bool -> Bool -> Bool
&& X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
<= X
70
        surprisinglyBadDefense :: Bool
surprisinglyBadDefense = Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
20 Bool -> Bool -> Bool
&& X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
70
        yetButAnd :: Text
yetButAnd
          | Bool
surprisinglyGoodDefense = Text
", but"
          | Bool
surprisinglyBadDefense = Text
", yet"
          | Bool
otherwise = Text
" and"  -- no surprises
        projectileHitsWeakly :: Bool
projectileHitsWeakly = Actor -> Bool
bproj Actor
sb Bool -> Bool -> Bool
&& Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
20
        msgArmor :: Text
msgArmor = if Bool -> Bool
not Bool
projectileHitsWeakly
                        -- ensures if attack msg terse, armor message
                        -- mentions object, so we know who is hit
                      Bool -> Bool -> Bool
&& X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
90
                        -- at most minor armor relatively to skill of the hit
                      Bool -> Bool -> Bool
&& ([(X, (ItemId, ItemFull))] -> Bool
forall a. [a] -> Bool
null [(X, (ItemId, ItemFull))]
condArmor Bool -> Bool -> Bool
|| Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
100)
                      Bool -> Bool -> Bool
|| [Part] -> Bool
forall a. [a] -> Bool
null [Part]
blockWithWhat
                      Bool -> Bool -> Bool
|| Int64
kineticDmg Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= -Int64
1000  -- -1/1000 HP
                   then Text
""
                   else Text
yetButAnd
                        Text -> Text -> Text
<+> [Part] -> Text
makePhrase ([Part
blockPhrase, Part
blockHowWell]
                                        [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
blockWithWhat)
        ps :: (Point, Point)
ps = (Actor -> Point
bpos Actor
tb, Actor -> Point
bpos Actor
sb)
        basicAnim :: Animation
basicAnim
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
70 = (Point, Point) -> Color -> Color -> Animation
twirlSplash (Point, Point)
ps Color
Color.BrRed Color
Color.Red
          | X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
1 = if X
nonPiercingDmg X -> X -> Bool
forall a. Ord a => a -> a -> Bool
>= X
0  -- no extra anim
                           then (Point, Point) -> Color -> Color -> Animation
blockHit (Point, Point)
ps Color
Color.BrRed Color
Color.Red
                           else (Point, Point) -> Animation
blockMiss (Point, Point)
ps
          | Bool
otherwise = (Point, Point) -> Animation
blockMiss (Point, Point)
ps
        targetIsFoe :: Bool
targetIsFoe = Actor -> FactionId
bfid Actor
sb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side  -- no big news if others hit our foes
                      Bool -> Bool -> Bool
&& FactionId -> Faction -> FactionId -> Bool
isFoe (Actor -> FactionId
bfid Actor
tb) Faction
tfact FactionId
side
        targetIsFriend :: Bool
targetIsFriend = FactionId -> Faction -> FactionId -> Bool
isFriend (Actor -> FactionId
bfid Actor
tb) Faction
tfact FactionId
side
                           -- warning if anybody hits our friends
        msgClassMelee :: MsgClassShowAndSave
msgClassMelee =
          if Bool
targetIsFriend then MsgClassShowAndSave
MsgMeleeNormalUs else MsgClassShowAndSave
MsgMeleeOthers
        msgClassRanged :: MsgClassShowAndSave
msgClassRanged =
          if Bool
targetIsFriend then MsgClassShowAndSave
MsgRangedNormalUs else MsgClassShowAndSave
MsgRangedOthers
        animateAlive :: LevelId -> Animation -> m ()
animateAlive LevelId
lid Animation
anim =
          if Actor -> Int64
bhp Actor
tb Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
> Int64
0
          then LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate LevelId
lid Animation
anim
          else LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate LevelId
lid (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
twirlSplashShort (Point, Point)
ps Color
Color.BrRed Color
Color.Red
        tutorialHintBenignFoe :: m ()
tutorialHintBenignFoe =
          Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Actor -> FactionId
bfid Actor
sb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side
                Bool -> Bool -> Bool
&& Bool -> Bool
not (ActorMaxSkills -> ActorId -> Actor -> Bool
actorCanMeleeToHarm ActorMaxSkills
actorMaxSkills ActorId
target Actor
tb)) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
            MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"This enemy can't harm you in melee. Left alone could it possibly be of some use?"
    -- The messages about parrying and immediately afterwards dying
    -- sound goofy, but there is no easy way to prevent that.
    -- And it's consistent.
    -- If/when death blow instead sets HP to 1 and only the next below 1,
    -- we can check here for HP==1; also perhaps actors with HP 1 should
    -- not be able to block.
    if | Bool
catch -> do  -- charge not needed when catching
         let msg :: Text
msg = [Part] -> Text
makeSentence
                     [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"catch", Part
tpart, Part
"skillfully"]
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgSpecialEvent Text
msg
         Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Actor -> FactionId
bfid Actor
sb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
           MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"You managed to catch a projectile, thanks to being braced and hitting it exactly when it was at arm's reach. The obtained item has been put into the shared stash of your party."
         LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
blockHit (Point, Point)
ps Color
Color.BrGreen Color
Color.Green
       | Bool -> Bool
not (Time -> ItemQuant -> Bool
hasCharge Time
localTime ItemQuant
kitWeapon) -> do
         -- Can easily happen with a thrown discharged item.
         -- Much less plausible with a wielded weapon.
         -- Theoretically possible if the weapon not identified
         -- (then timeout is a mean estimate), but they usually should be,
         -- even in foes' possession.
         let msg :: Text
msg = if Actor -> Bool
bproj Actor
sb
                   then [Part] -> Text
makePhrase
                          [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"connect"]
                        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", but it may be completely discharged."
                   else [Part] -> Text
makePhrase
                          ([ Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"try"
                           , Part
"to"
                           , Part
verb
                           , Part
tpart ]
                           [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
weaponNameWith)
                        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> if [Part] -> Bool
forall a. [a] -> Bool
null [Part]
weaponNameWith
                           then Text
", but there are no charges left."
                           else Text
", but it may be not readied yet."
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgSpecialEvent Text
msg  -- and no animation
       | Actor -> Bool
bproj Actor
sb Bool -> Bool -> Bool
&& Actor -> Bool
bproj Actor
tb -> do  -- server sends unless both are blasts
         -- Short message.
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgSpecialEvent (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
           [Part] -> Text
makeSentence [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"intercept", Part
tpart]
         -- Basic non-bloody animation regardless of stats.
         LevelId -> Animation -> m ()
animateAlive (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Color -> Color -> Animation
blockHit (Point, Point)
ps Color
Color.BrBlue Color
Color.Blue
       | Int64
kineticDmg Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= -Int64
1000  -- -1/1000 HP
         -- We ignore nested effects, because they are, in general, avoidable.
         Bool -> Bool -> Bool
&& X
nonPiercingDmg X -> X -> Bool
forall a. Ord a => a -> a -> Bool
>= X
0 -> do
         let adverb :: Part
adverb | ItemFull -> Bool
itemSuspect ItemFull
itemFullWeapon Bool -> Bool -> Bool
&& Actor -> FactionId
bfid Actor
sb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side =
                        Part
"tentatively"  -- we didn't identify the weapon before
                    | Actor -> Bool
bproj Actor
sb = Part
"lightly"
                    | Bool
otherwise = Part
"delicately"
             msg :: Text
msg = [Part] -> Text
makeSentence ([Part] -> Text) -> [Part] -> Text
forall a b. (a -> b) -> a -> b
$
               [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
verb, Part
tpart, Part
adverb]
               [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ if Actor -> Bool
bproj Actor
sb then [] else [Part]
weaponNameWith
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgClassMelee Text
msg  -- too common for color
         Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Actor -> FactionId
bfid Actor
sb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side Bool -> Bool -> Bool
|| Actor -> FactionId
bfid Actor
tb FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
           MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"Some hits don't cause piercing, impact, burning nor any other direct damage. However, they can have other effects, bad, good or both."
         LevelId -> Animation -> m ()
forall (m :: * -> *).
MonadClientUI m =>
LevelId -> Animation -> m ()
animate (Actor -> LevelId
blid Actor
tb) (Animation -> m ()) -> Animation -> m ()
forall a b. (a -> b) -> a -> b
$ (Point, Point) -> Animation
subtleHit (Point, Point)
ps
       | Actor -> Bool
bproj Actor
sb -> do  -- more terse than melee, because sometimes very spammy
         let msgRangedPowerful :: MsgClassShowAndSave
msgRangedPowerful | Bool
targetIsFoe = MsgClassShowAndSave
MsgRangedMightyWe
                               | Bool
targetIsFriend = MsgClassShowAndSave
MsgRangedMightyUs
                               | Bool
otherwise = MsgClassShowAndSave
msgClassRanged
             ([Part]
attackParts, MsgClassShowAndSave
msgRanged)
               | Bool
projectileHitsWeakly =
                 ( [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
"connect"]  -- weak, so terse
                 , MsgClassShowAndSave
msgClassRanged )
               | Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
300 =
                 ( [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
verb, Part
tpart, Part
"powerfully"]
                 , if Bool
targetIsFriend Bool -> Bool -> Bool
|| Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
700
                   then MsgClassShowAndSave
msgRangedPowerful
                   else MsgClassShowAndSave
msgClassRanged )
               | Bool
otherwise =
                 ( [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
verb, Part
tpart]  -- strong, for a proj
                 , MsgClassShowAndSave
msgClassRanged )
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgRanged (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makePhrase [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ [Part] -> Part
MU.Phrase [Part]
attackParts]
                            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msgArmor Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"."
         m ()
tutorialHintBenignFoe
         LevelId -> Animation -> m ()
animateAlive (Actor -> LevelId
blid Actor
tb) Animation
basicAnim
       | Actor -> Bool
bproj Actor
tb -> do  -- much less emotion and the victim not active.
         let attackParts :: [Part]
attackParts =
               [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
verb, Part
tpart] [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
weaponNameWith
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgMeleeOthers (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makeSentence [Part]
attackParts
         LevelId -> Animation -> m ()
animateAlive (Actor -> LevelId
blid Actor
tb) Animation
basicAnim
       | Bool
otherwise -> do  -- ordinary melee
         let msgMeleeInteresting :: MsgClassShowAndSave
msgMeleeInteresting | Bool
targetIsFoe = MsgClassShowAndSave
MsgMeleeComplexWe
                                 | Bool
targetIsFriend = MsgClassShowAndSave
MsgMeleeComplexUs
                                 | Bool
otherwise = MsgClassShowAndSave
msgClassMelee
             msgMeleePowerful :: MsgClassShowAndSave
msgMeleePowerful | Bool
targetIsFoe = MsgClassShowAndSave
MsgMeleeMightyWe
                              | Bool
targetIsFriend = MsgClassShowAndSave
MsgMeleeMightyUs
                              | Bool
otherwise = MsgClassShowAndSave
msgClassMelee
             attackParts :: [Part]
attackParts =
               [Part -> Part -> Part
MU.SubjectVerbSg Part
spart Part
verb, Part
sleepy, Part
tpart, Part
strongly]
               [Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Part]
weaponNameWith
             (Text
tmpInfluenceBlurb, MsgClassShowAndSave
msgClassInfluence) =
               if [(X, (ItemId, ItemFull))] -> Bool
forall a. [a] -> Bool
null [(X, (ItemId, ItemFull))]
condArmor Bool -> Bool -> Bool
|| Text -> Bool
T.null Text
msgArmor
               then (Text
"", MsgClassShowAndSave
msgClassMelee)
               else
                 let (X
armor, (ItemId
_, ItemFull
itemFullArmor)) =
                       ((X, (ItemId, ItemFull)) -> (X, (ItemId, ItemFull)) -> Ordering)
-> [(X, (ItemId, ItemFull))] -> (X, (ItemId, ItemFull))
forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
maximumBy (((X, (ItemId, ItemFull)) -> X)
-> (X, (ItemId, ItemFull)) -> (X, (ItemId, ItemFull)) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (((X, (ItemId, ItemFull)) -> X)
 -> (X, (ItemId, ItemFull)) -> (X, (ItemId, ItemFull)) -> Ordering)
-> ((X, (ItemId, ItemFull)) -> X)
-> (X, (ItemId, ItemFull))
-> (X, (ItemId, ItemFull))
-> Ordering
forall a b. (a -> b) -> a -> b
$ X -> X
forall a. Num a => a -> a
abs (X -> X)
-> ((X, (ItemId, ItemFull)) -> X) -> (X, (ItemId, ItemFull)) -> X
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (X, (ItemId, ItemFull)) -> X
forall a b. (a, b) -> a
fst) [(X, (ItemId, ItemFull))]
condArmor
                     (Part
object1, Part
object2) =
                       X
-> FactionId
-> FactionDict
-> Time
-> ItemFull
-> ItemQuant
-> (Part, Part)
partItemShortest X
rwidth (Actor -> FactionId
bfid Actor
tb) FactionDict
factionD Time
localTime
                                        ItemFull
itemFullArmor ItemQuant
quantSingle
                     name :: Text
name = [Part] -> Text
makePhrase [Part
object1, Part
object2]
                     msgText :: Text
msgText =
                       if X
hurtMult X -> X -> Bool
forall a. Ord a => a -> a -> Bool
> X
70
                       then (if X
armor X -> X -> Bool
forall a. Ord a => a -> a -> Bool
<= -X
15
                             then Text
", due to being"
                             else Bool -> Text -> Text
forall a. HasCallStack => Bool -> a -> a
assert (X
armor X -> X -> Bool
forall a. Ord a => a -> a -> Bool
>= X
15) Text
", regardless of being")
                            Text -> Text -> Text
<+> Text
name
                       else (if X
armor X -> X -> Bool
forall a. Ord a => a -> a -> Bool
>= X
15
                             then Text
", thanks to being"
                             else Bool -> Text -> Text
forall a. HasCallStack => Bool -> a -> a
assert (X
armor X -> X -> Bool
forall a. Ord a => a -> a -> Bool
<= -X
15) Text
", despite being")
                            Text -> Text -> Text
<+> Text
name
                 in (Text
msgText, MsgClassShowAndSave
msgMeleeInteresting)
             msgClass :: MsgClassShowAndSave
msgClass = if Bool
targetIsFriend Bool -> Bool -> Bool
&& Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
300
                           Bool -> Bool -> Bool
|| Int64
deadliness Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
2000
                        then MsgClassShowAndSave
msgMeleePowerful
                        else MsgClassShowAndSave
msgClassInfluence
         MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
msgClass (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$ [Part] -> Text
makePhrase [Part -> Part
MU.Capitalize (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ [Part] -> Part
MU.Phrase [Part]
attackParts]
                           Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msgArmor Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
tmpInfluenceBlurb Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"."
         m ()
tutorialHintBenignFoe
         LevelId -> Animation -> m ()
animateAlive (Actor -> LevelId
blid Actor
tb) Animation
basicAnim