Files
loop/src/Dodge/Render/HUD.hs
T
2024-11-17 13:03:46 +00:00

494 lines
18 KiB
Haskell

{-# LANGUAGE LambdaCase #-}
module Dodge.Render.HUD (
drawHUD,
selNumPos, -- this shoud probably be pushed back here
selNumPosCardinal, -- this shoud probably be pushed back here
) where
import Control.Applicative
import Control.Lens
import Control.Monad
import qualified Data.Map.Strict as M
import Data.Maybe
--import qualified Data.Vector as V
import Dodge.Base
import Dodge.CharacterEnums
--import Dodge.Clock
import Dodge.Creature.Info
import Dodge.Creature.Test
import Dodge.Data.CardinalPoint
import Dodge.Data.Combine
import Dodge.Data.ComposedItem
import Dodge.Data.Config
import Dodge.Data.DoubleTree
import Dodge.Data.SelectionList
import Dodge.Data.World
import Dodge.DoubleTree
import Dodge.Equipment.Text
import Dodge.Inventory
import Dodge.Item.Display
import Dodge.Item.Grammar
import Dodge.Item.Info
import Dodge.ListDisplayParams
import Dodge.Render.Connectors
import Dodge.Render.HUD.Carte
import Dodge.Render.List
import Dodge.ScreenPos
import Dodge.SelectionSections
import Dodge.SelectionSections.Draw
import Dodge.Terminal.Type
import Geometry
import qualified IntMapHelp as IM
import Justify
import Picture
import SDL (MouseButton (..))
drawHUD :: Configuration -> World -> Picture
drawHUD cfig w = case w ^. hud . hudElement of
DisplayCarte -> drawCarte cfig w
DisplayInventory{_diSections = sections, _subInventory = subinv} ->
drawHP cfig w
<> drawInventory sections w cfig
<> drawSubInventory subinv cfig w
drawHP :: Configuration -> World -> Picture
drawHP cfig =
dShadCol white
. translate (halfWidth cfig) (halfHeight cfig - 40)
. scale 0.2 0.2
. textRight
. show
. (^?! cWorld . lWorld . creatures . ix 0 . crHP)
drawInventory :: IM.IntMap (SelectionSection ()) -> World -> Configuration -> Picture
drawInventory sss w cfig =
drawSelectionSections sss ldp cfig
<> drawSSCursor sss (w ^? hud . hudElement . diSelection . _Just) ldp curs cfig
<> drawRootCursor w sss (w ^? hud . hudElement . diSelection . _Just) ldp cfig
<> iextra
<> drawMouseOver cfig w
<> translateScreenPos
cfig
(ldp ^. ldpPos)
(drawDISelections w)
where
ldp = invDisplayParams w
curs = invCursorParams w
iextra = fromMaybe mempty $ do
inv <- w ^? cWorld . lWorld . creatures . ix 0 . crInv
guard . not . isFilteringInv =<< (w ^? hud . hudElement . diSections)
return . inventoryExtra sss cfig w $ invAdj inv
drawRootCursor ::
World ->
IM.IntMap (SelectionSection ()) ->
Maybe (Int, Int) ->
ListDisplayParams ->
Configuration ->
Picture
drawRootCursor w sss msel ldp cfig = fromMaybe mempty $ do
cr <- w ^? cWorld . lWorld . creatures . ix 0
guard $ crIsAiming cr
(i, j) <- msel
guard $ i == 0
inv <- w ^? cWorld . lWorld . creatures . ix 0 . crInv
(x, y) <- getRootItemBounds j inv
return $
drawSSMultiCursor
sss
(Just (0, x))
(Just (y - x))
ldp
(BoundaryCursor [minBound ..])
cfig
getRootItemBounds :: Int -> IM.IntMap Item -> Maybe (Int, Int)
getRootItemBounds i inv = do
let ia = allInvLocs inv
itm <- ia ^? ix i . _2
let root = locToTop itm
x <- locRightmost root ^? locLDT . ldtValue . cItem . itLocation . ilInvID
y <- locLeftmost root ^? locLDT . ldtValue . cItem . itLocation . ilInvID
return (x, y)
drawMouseOver :: Configuration -> World -> Picture
drawMouseOver cfig w = fromMaybe mempty $ invsel <|> combinvsel
where
invsel = do
(j, i) <- w ^? input . mouseContext . mcoInvSelect <|>
w ^? input . mouseContext . mcoInvFilt
sss <- w ^? hud . hudElement . diSections
let idp = invDisplayParams w
return . translateScreenPos cfig (invDisplayParams w ^. ldpPos)
. color (withAlpha 0.2 white)
$ selSecDrawCursorAt 15 idp curs sss (j, i)
curs = BackdropCursor
combinvsel = do
(j, i) <- (w ^? input . mouseContext . mcoCombSelect)
<|> (w ^? input . mouseContext . mcoCombCombine)
sss <- w ^? hud . hudElement . subInventory . ciSections
let idp = secondColumnParams
return . translateScreenPos cfig (idp ^. ldpPos)
. color (withAlpha 0.2 white)
$ selSecDrawCursorAt 15 idp curs sss (j, i)
getMouseInvSel :: World -> Maybe ((Int, Int), (Int, Int))
getMouseInvSel w = case w ^? hud . hudElement . subInventory . nsSelected of
Just (MouseInvSelect s (Just e)) -> Just (s, e)
_ -> case w ^? hud . hudElement . diSelectionExtra of
Just x | x > 0 -> do
(i, j) <- w ^? hud . hudElement . diSelection . _Just
return ((i, j), (i, j + x))
_ -> Nothing
drawDISelections :: World -> Picture
drawDISelections w = fromMaybe mempty $ do
((i, j), (a, b)) <- getMouseInvSel w
guard $ i == a
sss <- w ^? hud . hudElement . diSections
let idp = invDisplayParams w
let f x = selSecDrawCursorAt 15 idp BackdropCursor sss (i, x)
return . color (withAlpha 0.2 white) . foldMap f $ [min j b .. max j b]
drawSubInventory :: SubInventory -> Configuration -> World -> Picture
drawSubInventory subinv cfig w = case subinv of
LockedInventory -> mempty -- topInvCursor col cursPos cfig w
NoSubInventory{} -> drawRBOptions cfig w
ExamineInventory -> drawExamineInventory cfig w
DisplayTerminal tid -> drawTerminalDisplay tid cfig (w ^. cWorld . lWorld)
CombineInventory{_ciSections = sss} -> drawCombineInventory cfig sss w
drawCombineInventory ::
Configuration ->
IM.IntMap (SelectionSection CombinableItem) ->
World ->
Picture
drawCombineInventory cfig sss w =
invHead cfig "COMBINE"
<> drawSelectionSections sss secondColumnParams cfig
<> drawSSCursor sss msel secondColumnParams curs cfig
<> combineInventoryExtra sss msel cfig w
where
curs = BoundaryCursor [North, South, West]
msel = w ^? hud . hudElement . subInventory . ciSelection . _Just
drawExamineInventory :: Configuration -> World -> Picture
drawExamineInventory cfig w =
invHead cfig "EXAMINE"
<> drawSelectionList
secondColumnParams
cfig
( (map f
( makeParagraph 55 $
yourAugmentedItem
itemInfo
(yourInfo (you w))
(closeObjectInfo (crNumFreeSlots (you w)))
w
))
)
where
f str =
SelectionItem
{ _siPictures = [str]
, _siHeight = 1
, _siIsSelectable = True
, _siColor = white
, _siOffX = 0
, _siPayload = ()
}
closeObjectInfo :: Int -> Either FloorItem Button -> String
closeObjectInfo n x = case x of
Left FlIt{_flIt = itm} -> itemInfo itm ++ " It is on the floor" ++ floorItemPickupInfo n itm
Right _ -> "Some sort of switch or button."
floorItemPickupInfo :: Int -> Item -> String
floorItemPickupInfo n itm
| n >= _itInvSize itm = ", but you have space to pick it up."
| otherwise = ", and you don't have space to pick it up."
-- note the use of ^?!
-- it is probably desirable for this to crash hard for now
yourAugmentedItem :: (Item -> a) -> a -> (Either FloorItem Button -> a) -> World -> a
yourAugmentedItem f x g w = case you w ^? crManipulation . manObject of
Just (SelectedItem i _ _) -> f $ yourInv w ^?! ix i
Just (SelCloseObject i) -> g $ w ^?! hud . closeObjects . ix i
_ -> x
drawRBOptions :: Configuration -> World -> Picture
drawRBOptions cfig w = fromMaybe mempty $ do
guard $ ButtonRight `M.member` _mouseButtons (_input w)
invid <- you w ^? crManipulation . manObject . imSelectedItem
eslist <-
fmap equipSiteToPositions $
you w ^? crInv . ix invid . itUse . uequipEffect . eeSite
i <- w ^? rbOptions . opSel
let ae = getEquipmentAllocation w
sss <- w ^? hud . hudElement . diSections
(i', j) <- w ^? hud . hudElement . diSelection . _Just
curpos <- selSecYint i' j sss
let ytext = drawListElement 0 1 0 curpos . text
midstr = equipAllocString ae
extrastr = case ae of
SwapEquipment{_allocOldPos = oldp, _allocSwapID = sid} ->
"SWAPS " ++ otheritem sid ++ " ONTO " ++ eqPosText oldp
ReplaceEquipment{_allocRemoveID = rid} ->
"REMOVES " ++ otheritem rid
_ -> ""
return $
toTopLeft cfig $
translate 290 (-1) (ytext midstr)
<> translate
160
(-1)
( listCursorChooseBorderScale
0
1
(BoundaryCursor [North, South])
curpos
0
white
21
1
)
<> translate
380
(-1)
( drawListYoff (curpos - i) (map (text . eqPosText) eslist)
<> listCursorChooseBorderScale 0 1 (bc East) (curpos - i) 0 white 7 (length eslist)
<> listCursorChooseBorderScale 0 1 (bc West) (curpos + 1) 0 white 7 (length eslist - (i + 1))
<> listCursorChooseBorderScale 0 1 (bc West) (curpos - i) 0 white 7 i
<> maybetopborder i curpos
<> maybebottomborder i (length eslist) curpos
)
<> translate 460 (-1) (ytext extrastr)
where
bc x = BoundaryCursor [x]
maybetopborder 0 curpos = listCursorChooseBorderScale 0 1 (bc North) curpos 0 white 7 1
maybetopborder _ _ = mempty
maybebottomborder a b curpos
| a == b - 1 = listCursorChooseBorderScale 0 1 (bc South) curpos 0 white 7 1
| otherwise = mempty
otheritem j = fromMaybe "" $ do
itm <- you w ^? crInv . ix j
return $ itemBaseName itm
equipAllocString :: EquipmentAllocation -> String
equipAllocString = \case
DoNotMoveEquipment -> ""
PutOnEquipment{} -> " PUT ON"
MoveEquipment{} -> " MOVE TO"
SwapEquipment{} -> " MOVE TO"
ReplaceEquipment{} -> " PUT ON"
RemoveEquipment{} -> "TAKE OFF"
inventoryExtra ::
IM.IntMap (SelectionSection ()) ->
Configuration ->
World ->
IM.IntMap (Maybe (Int, Int), [Int], [Int]) ->
Picture
inventoryExtra sss cfig w =
translate (negate 5) 0
. IM.foldMapWithKey (inventoryExtraH sss cfig w)
. fmap (\(_, a, b) -> a <> b)
inventoryExtraH ::
IM.IntMap (SelectionSection ()) ->
Configuration ->
World ->
Int ->
[Int] ->
Picture
inventoryExtraH sss cfig w i is = fromMaybe mempty $ do
p <- snum i
let ps = mapMaybe snum is
return $ color white $ lConnectMulti ps p
where
snum = selNumPos cfig (invDisplayParams w) sss 0
combineInventoryExtra ::
IM.IntMap (SelectionSection CombinableItem) ->
Maybe (Int, Int) ->
Configuration ->
World ->
Picture
combineInventoryExtra sss msel cfig w = fromMaybe mempty $ do
(i, j) <- msel
cpos <- selSecYint i j sss
si <- sss ^? ix i . ssItems . ix j
let col = _siColor si
mconcat
[ do
strs <- si ^? siPayload . ciInfo
return
. translate 160 0
-- it would be better to get the width of the selection list from elsewhere
. translateScreenPos cfig (secondColumnParams ^. ldpPos)
$ drawListYoff cpos $ map (color red . text) strs
, do
lnks <- si ^? siPayload . ciInvIDs
return (lnkMidPosInvSelsCol cfig w j col lnks)
<> foldMap invcursor lnks
]
where
invcursor i = do
sss' <- w ^? hud . hudElement . diSections
let idp = invDisplayParams w
return $
translateScreenPos cfig (idp ^. ldpPos) $
selSecDrawCursor
15
idp
(BoundaryCursor [North, South, East, West])
sss'
(Just (0, i))
drawTerminalDisplay :: Int -> Configuration -> LWorld -> Picture
drawTerminalDisplay tid cfig w = fromMaybe mempty $ do
tm <- w ^? terminals . ix tid
return $
invHead cfig (_tmTitle tm ++ ":T" ++ show tid)
<> drawSelectionList secondColumnParams cfig (thesellist tm)
<> color (withAlpha 0.5 green) (drawSelectionListBackground secondColumnParams cfig 15)
-- when changing the 15, change isOverTerminalScreen
<> color (dark $ _tmExternalColor tm) (drawTitleBackground cfig)
where
toselitm (str, col) = SelectionItem [str] 1 True col 0 ()
thesellist tm = thelist tm
thelist tm =
map toselitm . displayTermInput tm
. reverse
. take (getMaxLinesTM (tm ^. tmType))
$ _tmDisplayedLines tm
displayTermInput tm = case _tmInput tm of
TerminalInput{_tiText = s} ->
(++ [(displayInputText tm s ++ [cFilledRect], white)])
partcommand tm = maybe "" (++ " ") $ tm ^? tmPartialCommand . _Just . tcString
displayInputText tm s
| _tmStatus tm == TerminalReady = partcommand tm ++ getPromptTM (tm ^. tmType) ++ s
| otherwise = ""
-- | hasfoc = clockCycle 10 (V.fromList [[cFilledRect] , "."]) w
lnkMidPosInvSelsCol :: Configuration -> World -> Int -> Color -> [Int] -> Picture
lnkMidPosInvSelsCol cfig w i col = fromMaybe mempty . foldMap f
where
f j = do
sss <- w ^? hud . hudElement . diSections
combinesss <- w ^? hud . hudElement . subInventory . ciSections
lp <- selNumPos cfig (invDisplayParams w) sss 0 j
rp <- selNumPos cfig secondColumnParams combinesss 0 i
invcol <- selSecSelCol 0 j sss
return $ zConnectColMidX (rp - V2 5 0) (lp + V2 155 0) (rp ^. _1 - 20) col col col invcol
invHead :: Configuration -> String -> Picture
invHead cfig =
translateScreenPos cfig (fromTopLeft (V2 subInvX 80))
. dShadCol white
. scale 0.4 0.4
. textJustifyLeft
--locPoss = map (cartePosToScreen cfig (w ^. hud) . ($ w) . doWorldPos . fst) . IM.elems . _seenLocations . _lWorld $ _cWorld w
--locTexts = map fst locs
--displayListEndCoords :: Configuration -> [String] -> [Point2]
--displayListEndCoords cfig ss = map (doWindowScale cfig) $ zipWith h ss $ map f [1 ..]
-- where
-- f :: Int -> Point2
-- f i = V2 (15 - halfWidth cfig) (2.5 + halfHeight cfig - (20 * fromIntegral i))
-- h :: String -> Point2 -> Point2
-- h s (V2 x y) = V2 (x + 9 * fromIntegral (length s)) y
--closeObjectTexts :: Configuration -> World -> Picture
--closeObjectTexts cfig w = pictures $
-- renderListAt pushout (negate 20 * fromIntegral invPos) cfig (map colAndText $ _closeObjects w)
-- : maybeToList maybeLine
-- where
-- colAndText (Left x) = ( _itName $ _flIt x, _itInvColor $ _flIt x)
-- colAndText (Right x) = (_btText x,yellow)
-- youSel = _crInvSel $ you w
-- freeSlot = mayIt >>= \it -> checkInvSlotsYou (_flIt it) w
-- invPos = fromMaybe youSel freeSlot
-- mayObj = listToMaybe $ _closeObjects w
-- mayIt = mayObj >>= maybeLeft
-- maybeLeft (Left x) = Just x
-- maybeLeft _ = Nothing
-- pushout = 120
-- objPos obj = case obj of
-- Left flit -> _flItPos flit
-- Right bt -> _btPos bt
-- mayScreenPos = fmap (worldPosToScreen w . objPos) mayObj
-- maybeLine = do
-- itScreenPos <- mayScreenPos
-- (theText,col) <- fmap colAndText mayObj
-- let textWidth = 9 * fromIntegral (length theText)
-- let p = V2 (textWidth + 15 + pushout - halfWidth cfig)
-- ( halfHeight cfig - 20* (fromIntegral invPos +1) + 2.5)
-- return . winScale cfig . color col $ lConnect p itScreenPos
--textSelItems :: [String] -> [SelectionItem ()]
--textSelItems = map (picsToSelectable . (: []))
--picsToSelectable :: [String] -> SelectionItem ()
--picsToSelectable pics =
-- SelectionItem
-- { _siPictures = pics
-- , _siHeight = length pics
-- , _siIsSelectable = True
-- , _siColor = white
-- , _siOffX = 0
-- , _siPayload = ()
-- }
-- would be nice to add parameter to orient this with NSEW, cf cursor
selNumPos ::
Configuration ->
ListDisplayParams ->
IM.IntMap (SelectionSection a) ->
Int ->
Int ->
Maybe Point2
selNumPos = selNumPosCardinal West8
--selNumPos cfig ldp sss i j = do
-- ipos <- selSecYint i j sss
-- size <- selSecSelSize i j sss
-- indent <- sss ^? sssSections . ix i . ssItems . ix j . siOffX
-- return $
-- screenPosAbs cfig (ldp ^. ldpPos)
-- + V2
-- (10 * s * fromIntegral indent)
-- (negate (20 * s + ygap) * (fromIntegral ipos + fromIntegral size * 0.5))
-- where
-- s = _ldpScale ldp
-- ygap = _ldpVerticalGap ldp
-- need to be able to determine a selection item's width for this
selNumPosCardinal ::
CardinalEightPoint ->
Configuration ->
ListDisplayParams ->
IM.IntMap (SelectionSection a) ->
Int ->
Int ->
Maybe Point2
selNumPosCardinal card cfig ldp sss i j = do
ipos <- selSecYint i j sss
size <- selSecSelSize i j sss
indent <- sss ^? ix i . ssItems . ix j . siOffX
let offset = cardEightVec card * V2 0 (fromIntegral size * 0.5 * 20 * s)
return $
screenPosAbs cfig (ldp ^. ldpPos)
+ offset
+ V2
(10 * s * fromIntegral indent)
(negate (20 * s + ygap) * (fromIntegral ipos + fromIntegral size * 0.5))
where
s = _ldpScale ldp
ygap = _ldpVerticalGap ldp
selSecSelCol :: Int -> Int -> IM.IntMap (SelectionSection a) -> Maybe Color
selSecSelCol i j sss = sss ^? ix i . ssItems . ix j . siColor