--{-# LANGUAGE TupleSections #-} module Dodge.Render.HUD ( drawHUD, ) where import Dodge.Creature.Info import Control.Lens import qualified Data.Map.Strict as M import Data.Maybe import qualified Data.Vector as V import Dodge.Base import Dodge.Clock import Dodge.Combine import Dodge.Data.CardinalPoint import Dodge.Data.Config import Dodge.Data.SelectionList import Dodge.Data.World import Dodge.Inventory import Dodge.Inventory.ItemSpace import Dodge.Inventory.SelectionList import Dodge.Item.Display import Dodge.Item.Info import Dodge.Render.Connectors import Dodge.Render.List import Dodge.Tweak.Show import Dodge.WorldPos import Geometry import qualified IntMapHelp as IM import Justify import ListHelp import Padding import Picture import SDL (MouseButton (..)) drawHUD :: Configuration -> World -> Picture drawHUD cfig w = case w ^. hud . hudElement of DisplayCarte -> drawCarte cfig w DisplayInventory subinv -> drawInGameHUD sl cfig w <> drawSubInventory subinv cfig w where sl = makeInventorySelectionList w drawInGameHUD :: SelectionList () -> Configuration -> World -> Picture drawInGameHUD sl cfig w = pictures [ winScale cfig . dShadCol white $ displayHP 0 cfig w , inventoryDisplay w cfig sl ] defaultListDisplayParams :: ListDisplayParams defaultListDisplayParams = ListDisplayParams { _ldpVerticalGap = 10 , _ldpScale = 1 , _ldpPosX = 0 , _ldpPosY = 0 , _ldpCursorType = NoCursor , _ldpWidth = FixedSelectionWidth 15 } defaultSubInvSelectionList :: SelectionList a defaultSubInvSelectionList = SelectionList { _slItems = [] , _slSelPos = Nothing , _slLength = 15 , _slRegex = "" , _slRegexInput = False } invDisplayParams :: World -> ListDisplayParams invDisplayParams w = defaultListDisplayParams -- & ldpWidth .~ FixedSelectionWidth topInvW & ldpCursorType .~ BorderCursor selcursortype & ldpWidth .~ FixedSelectionWidth (determineInvSelCursorWidth w) where selcursortype | isexaminesub || ButtonRight `M.member` _mouseButtons (_input w) = [North, South, East, West] | otherwise = [North, South, West] isexaminesub = case w ^? hud . hudElement . subInventory of Just ExamineInventory{} -> True _ -> False inventoryDisplay :: World -> Configuration -> SelectionList () -> Picture inventoryDisplay = drawSelectionList . invDisplayParams drawSubInventory :: SubInventory -> Configuration -> World -> Picture drawSubInventory subinv cfig w = case subinv of LockedInventory -> mempty -- topInvCursor col cursPos cfig w NoSubInventory -> drawNoSubInventory cfig w ExamineInventory mtweaki -> drawExamineInventory cfig mtweaki w DisplayTerminal tid -> displayTerminal tid cfig (w ^. cWorld . lWorld) CombineInventory mi regex x -> titledSub cfig ("COMBINE") (combineListSelection w mi regex x) <> combineInventoryExtra mi cfig w titledSub :: Configuration -> String -> SelectionList a -> Picture titledSub cfig subtitle subitems = invHead cfig subtitle <> drawSelectionList secondColumnParams cfig subitems drawExamineInventory :: Configuration -> Maybe Int -> World -> Picture drawExamineInventory cfig mtweaki w = titledSub cfig "EXAMINE" (defaultSubInvSelectionList & slItems .~ ammoTweakSelectionItems itm ++ map f (makeParagraph 60 $ yourAugmentedItem itemInfo (yourInfo (you w)) (closeObjectInfo (crNumFreeSlots (you w)) ) w)) <> examineInventoryExtra mtweaki itm cfig where itm = yourItem w f str = SelectionItem { _siPictures = [str] , _siHeight = 1 , _siIsSelectable = True , _siWidth = length str , _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 >= ceiling (_itInvSize itm) = ", but you have space to pick it up." | otherwise = ", and you don't have space to pick it up." yourAugmentedItem :: (Item -> a) -> a -> (Either FloorItem Button -> a) -> World -> a yourAugmentedItem f x g w | i < n = f $ yourInv w ^?! ix i | i == n = x | otherwise = g $ w ^?! hud . closeObjects . ix (i - n - 1) where i = crSel (you w) n = length $ yourInv w drawNoSubInventory :: Configuration -> World -> Picture drawNoSubInventory cfig w = pictures [ closeobjectcursor , equipcursors , equipcursor -- the order is important, this should go on top of the other equipcursors , rboptions ] where closeobjectcursor = case selectedCloseObject w of Nothing -> mempty Just (i, _) -> drawCursorAt (invDisplayParams w & ldpCursorType .~ BorderCursor [North, South]) cfig (Just i) (inventorySelectionList w) equipcursor = case cr ^. crLeftInvSel . lisMPos of Just invid -> f cyan invid (_crInvEquipped cr IM.! invid) _ -> mempty equipcursors = IM.foldMapWithKey (f yellow) (_crInvEquipped cr) cr = you w rboptions | ButtonRight `M.member` _mouseButtons (_input w) = drawRBOptions cfig w (_rbOptions w) | otherwise = mempty f col invid epos = listTextPictureAt 144 0 cfig (selNumPos invid w) . color col $ text $ eqPosText epos examineInventoryExtra :: Maybe Int -> Maybe Item -> Configuration -> Picture examineInventoryExtra mtweaki mitm cfig = pictures [ fromMaybe mempty $ do tweaki <- mtweaki -- consider moving this functionality out into a tweaks module tparam <- mitm ^? _Just . itTweaks . tweakParams . ix tweaki return $ listCursorNSW subInvX 60 cfig tweaki white (length $ showTweak tparam) 15 -- , drawSelectionList thirdColumnParams cfig (thirdColumnPara (itmInfo mitm)) ] combineInventoryExtra :: Maybe Int -> Configuration -> World -> Picture combineInventoryExtra mi cfig w = pictures [ fromMaybe mempty $ do i <- mi cpos <- combinePoss w !? i col <- (combineItemListYou w !? i) <&> _itInvColor . snd return $ pictures [ fromMaybe mempty $ do strs <- fmap (fst . snd) (combineListInfo w !? i) return $ listPicturesAtOff (subInvX + 150) 60 cfig cpos $ map (color red . text) strs , fromMaybe mempty $ do lnks <- map fst (combineItemListYou w) !? i return $ lnkMidPosInvSelsCol cfig w cpos col lnks <> foldMap (topCursorTypeWidth listCursorNESW (topInvW + 2) cfig w) lnks <> combineCounts cfig w lnks ] ] secondColumnParams :: ListDisplayParams secondColumnParams = defaultListDisplayParams & ldpPosX .~ subInvX & ldpPosY .~ 60 & ldpCursorType .~ BorderCursor [North, South, West] --thirdColumnParams :: ListDisplayParams --thirdColumnParams = -- defaultListDisplayParams -- & ldpPosX .~ 9 * fromIntegral topInvW + 275 -- & ldpPosY .~ 60 --thirdColumnPara :: [String] -> SelectionList () --thirdColumnPara strs = SelectionList (map f strs) Nothing (length strs) -- where -- f str = -- SelectionItem -- { _siPictures = [text str] -- , _siHeight = 1 -- , _siIsSelectable = True -- , _siWidth = length str -- , _siColor = white -- , _siOffX = 0 -- , _siPayload = () -- } displayTerminal :: Int -> Configuration -> LWorld -> Picture displayTerminal tid cfig w = fromMaybe mempty $ do tm <- w ^? terminals . ix tid return $ pictures [ invHead cfig (_tmTitle tm ++ ":T" ++ show tid) , drawSelectionList secondColumnParams cfig (thesellist tm) ] where toselitm (str, col) = SelectionItem [str] 1 True (length str) col 0 () thesellist tm = SelectionList (thelist tm) Nothing (length (thelist tm)) "" False thelist tm = map toselitm . displayTermInput tm . reverse . take (_tmMaxLines tm) $ _tmDisplayedLines tm displayTermInput tm = case _tmInput tm of TerminalInput s hasfoc _ -> (++ [(displayInputText tm s ++ displayBlinkCursor hasfoc, white)]) displayInputText tm s | _tmStatus tm == TerminalReady = '>' : s | otherwise = "" displayBlinkCursor hasfoc | hasfoc = clockCycle 10 (V.fromList ["_", ""]) w | otherwise = [] drawRBOptions :: Configuration -> World -> RightButtonOptions -> Picture drawRBOptions cfig w EquipOptions{_opEquip = es, _opSel = i, _opAllocateEquipment = ae} = listPicturesAtOff 342 0 cfig (curpos - i) (map (text . eqPosText) es) <> case ae of DoNotMoveEquipment -> mempty PutOnEquipment{} -> midtext "PUT ONTO" MoveEquipment{} -> midtext "MOVE TO" <> extratext [] SwapEquipment{_allocOldPos = oldp, _allocSwapID = sid} -> midtext "MOVE TO" <> extratext ("SWAPS " ++ otheritem sid ++ " ONTO " ++ eqPosText oldp) ReplaceEquipment{_allocRemoveID = rid} -> midtext "PUT ONTO" <> extratext ("REMOVES " ++ otheritem rid) RemoveEquipment{} -> midtext "TAKE OFF" where midtext str = listTextPictureAt 252 0 cfig curpos (text str) extratext str = listTextPictureAt 432 0 cfig curpos (text (str ++ deactivatetext)) deactivatetext = case w ^? rbOptions . opActivateEquipment . deactivateEquipment of Just k -> " DEACTIVATES " ++ show (_iyBase $ _itType (_crInv (you w) IM.! k)) Nothing -> "" curpos = invSelPos w otheritem j = show $ _iyBase $ _itType (_crInv (you w) IM.! j) drawRBOptions _ _ _ = mempty eqPosText :: EquipPosition -> String eqPosText ep = case ep of OnHead -> "HEAD" OnChest -> "CHEST" OnBack -> "BACK" OnLeftWrist -> "L.WRIST" OnRightWrist -> "R.WRIST" OnLegs -> "LEGS" OnSpecial -> "EQUIPPED" topInvW :: Int topInvW = 15 subInvX :: Float subInvX = 9 * fromIntegral topInvW + 50 combineCounts :: Configuration -> World -> [Int] -> Picture combineCounts cfig w = winScale cfig . foldMap f . group where f (i : is) = case yourInv w ^? ix i . itUse . useAmount of Just _ -> color (selNumCol i w) $ uncurryV translate (selNumTextPos cfig w i) . scale 0.1 0.1 . text $ ('-' : show (length is + 1)) _ -> mempty f _ = mempty lnkMidPosInvSelsCol :: Configuration -> World -> Int -> Color -> [Int] -> Picture lnkMidPosInvSelsCol cfig w i col = winScale cfig . foldMap (\j -> zConnectCol rp (V2 18 0 + selNumMidHeight cfig w j) col white white (selNumCol j w)) where rp = V2 (190 - hw) (hh - (20 * fromIntegral i + 77.5)) hh = halfHeight cfig hw = halfWidth cfig topCursorTypeWidth :: (Float -> Float -> Configuration -> Int -> Color -> Int -> Int -> Picture) -> Int -> Configuration -> World -> Int -> Picture topCursorTypeWidth ctype width cfig w i = ctype 0 0 cfig (selNumPos i w) (selNumCol i w) width (invSelSize i w) determineInvSelCursorWidth :: World -> Int determineInvSelCursorWidth w = case _rbOptions w of NoRightButtonOptions -> topInvW EquipOptions{} | ButtonRight `M.member` _mouseButtons (_input w) && w ^? hud . hudElement . subInventory == Just NoSubInventory -> 47 | otherwise -> topInvW combineListSelection :: World -> Maybe Int -> String -> Bool -> SelectionList () combineListSelection w mi regex x = defaultSubInvSelectionList & slItems .~ combineListSelectionItems w & slSelPos .~ mi & slRegex .~ regex & slRegexInput .~ x combineListSelectionItems :: World -> [SelectionItem ()] combineListSelectionItems w = case combineListSelectionItems' w of [] -> [SelectionItem [thetext] 1 False (length thetext) white 0 ()] xs -> xs where thetext = "NO POSSIBLE COMBINATIONS" combineListSelectionItems' :: World -> [SelectionItem ()] combineListSelectionItems' = map (picsToSelectable 15 . itemText . snd) . combineItemListYou ammoTweakSelectionItems :: Maybe Item -> [SelectionItem ()] ammoTweakSelectionItems = textSelItems . ammoTweakStrings ammoTweakStrings :: Maybe Item -> [String] ammoTweakStrings it = case it ^? _Just . itTweaks . tweakParams of Just l -> map tweakString $ IM.elems l _ -> ["NOT TWEAKABLE"] tweakString :: TweakParam -> String tweakString tp = rightPad 12 ' ' (show $ _tweakType tp) ++ " " ++ showTweak tp invHead :: Configuration -> String -> Picture invHead cfig = winScale cfig . translate (- halfWidth cfig + subInvX + 20) (halfHeight cfig - 40) . dShadCol white . scale 0.4 0.4 . text drawCarte :: Configuration -> World -> Picture drawCarte cfig w = pictures $ renderListAt 0 0 cfig locs : zipWith bConnect (displayListEndCoords cfig locTexts) locPoss ++ mapOverlay cfig w ++ [mainListCursor white iPos cfig] where iPos = w ^. cWorld . lWorld . selLocation locs = map (\(_, s) -> (s, white)) . IM.elems . _seenLocations . _lWorld $ _cWorld w 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 mapOverlay :: Configuration -> World -> [Picture] mapOverlay cfig w = (color (withAlpha 0.5 black) . polygon $ reverse $ rectNSWE 1 (-1) 1 (-1)) : [foldMap (drawMapWall cfig (w ^. hud)) $ IM.restrictKeys (lw ^. walls) (w ^. cWorld . seenWalls)] where --(mapMaybe (mapWall cfig (w ^. hud)) . IM.elems $ w ^. cWorld . lWorld . walls) lw = w ^. cWorld . lWorld drawMapWall :: Configuration -> HUD -> Wall -> Picture drawMapWall cfig thehud wl = color c . polygon $ map (cartePosToScreen cfig thehud) [x, x +.+ n2, y +.+ n2, y] where t = normalizeV (y -.- x) n2 = 20 *.* vNormal t (x, y) = _wlLine wl c = _wlColor wl --mapWall :: Configuration -> HUD -> Wall -> Maybe Picture --mapWall cfig thehud wl -- | _wlSeen wl = Just . color c . polygon $ map (cartePosToScreen cfig thehud) [x, x +.+ n2, y +.+ n2, y] -- | otherwise = Nothing -- where -- t = normalizeV (y -.- x) -- n2 = 20 *.* vNormal t -- (x, y) = _wlLine wl -- c = _wlColor wl --selectedCloseObjectLink :: Configuration -> World -> Picture --selectedCloseObjectLink cfig w = mempty -- | Pictures of popup text for items close to your position. --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 mainListCursor :: Color -> Int -> Configuration -> Picture mainListCursor c = openCursorAt 120 c 5 0 picsToSelectable :: Int -> [String] -> SelectionItem () picsToSelectable wdth pics = SelectionItem { _siPictures = pics , _siHeight = length pics , _siIsSelectable = True , _siWidth = wdth , _siColor = white , _siOffX = 0 , _siPayload = () } textSelItems :: [String] -> [SelectionItem ()] textSelItems = map (picsToSelectable 15 . (: [])) itemText :: Item -> [String] {-# INLINE itemText #-} itemText it = f $ case _itCurseStatus it of UndroppableIdentified -> itemDisplay it _ -> itemDisplay it where f = take (itSlotsTaken it) . (++ replicate 10 "*") openCursorAt :: -- | Width Float -> Color -> -- | x offset Float -> -- | y offset Float -> -- | y offset (discrete) Int -> Configuration -> Picture openCursorAt wth col xoff yoff yint w = winScale w . translate (xoff - halfWidth w) (halfHeight w - (20 * fromIntegral yint + yoff) - 20) $ lineCol [ (V2 wth 12.5, withAlpha 0 col) , (V2 0 12.5, col) , (V2 0 (-7.5), col) , (V2 wth (-7.5), withAlpha 0 col) ] displayHP :: Int -> Configuration -> World -> Picture displayHP cid cfig = translate (halfWidth cfig -80) (halfHeight cfig -20) . scale 0.2 0.2 . text . leftPad 5 ' ' . show . (^?! cWorld . lWorld . creatures . ix cid . crHP)