Files
loop/src/Dodge/Inventory.hs
T
2023-05-01 22:35:33 +01:00

449 lines
17 KiB
Haskell

--{-# LANGUAGE TupleSections #-}
module Dodge.Inventory (
selSecSelPos,
checkInvSlotsYou,
rmSelectedInvItem,
selNumTextEndPos,
selSecSelCol,
selNumEndMidHeight,
rmInvItem,
updateCloseObjects,
updateRBList,
checkTermDist,
closeObjScrollDir,
changeSwapSel,
scrollAugInvSel,
crNumFreeSlots,
crInvSize,
selectedCloseObject,
invDimColor,
setInvPosFromSS,
) where
import Control.Monad
import Color
import Control.Applicative
import qualified Data.Map.Strict as M
import Data.Maybe
import Dodge.Base
import Dodge.Data.Config
import Dodge.Data.SelectionList
import Dodge.Data.World
import Dodge.DisplayInventory
import Dodge.Euse
import Dodge.Inventory.CheckSlots
import Dodge.Inventory.CloseObject
import Dodge.Inventory.Color
import Dodge.ItEffect
import Dodge.Reloading
import Dodge.SelectionSections
import Geometry
import qualified IntMapHelp as IM
import LensHelp
import ListHelp
import Padding
-- TODO check what happens to selection index when dropping non-selected items
-- | after this the item at the inventory position will no longer exist
rmInvItem ::
-- | Creature id
Int ->
-- | Inventory position
Int ->
World ->
World
rmInvItem cid invid w = case w ^? getcid . crInv . ix invid . itUse . useAmount of
Just x
| x > 1 ->
w & pointcid . crInv . ix invid . itUse . useAmount -~ 1
& worldEventFlags . at InventoryChange ?~ ()
_ ->
w
& pointcid %~ crCancelReloading
& pointcid . crInv %~ f
& pointcid . crLeftInvSel . lisMPos %~ g'
& removeAnySlotEquipment
& dounequipfunction
& doanyitemeffect
& pointcid . crInvEquipped %~ IM.delete invid
& pointcid . crInvEquipped %~ IM.mapKeys g
& updateselection
& worldEventFlags . at InventoryChange ?~ ()
where
getcid = cWorld . lWorld . creatures . ix cid
pointcid = cWorld . lWorld . creatures . ix cid
updateselection
| cid == 0 && cr ^? crManipulation . manObject . inInventory . ispItem == Just invid =
scrollAugInvSel (-1) . scrollAugInvSel 1 . updateInventorySectionItems
| otherwise =
pointcid . crManipulation . manObject . inInventory . ispItem %~ g
cr = w ^?! cWorld . lWorld . creatures . ix cid
itm = _crInv cr IM.! invid
dounequipfunction = fromMaybe id $ do
rmf <- itm ^? itUse . equipEffect . eeOnRemove
return $ useE rmf itm cr
doanyitemeffect = fromMaybe id $ do
rmf <- itm ^? itEffect . ieOnDrop
return $ doInvEffect rmf itm cr
--removeAnySlotEquipment = case w ^? cWorld . lWorld . creatures . ix cid . crInvEquipped . ix invid of
-- Just epos -> pointcid . crEquipment . at epos .~ Nothing
-- Nothing -> id
removeAnySlotEquipment = fromMaybe id $ do
epos <- w ^? cWorld . lWorld . creatures . ix cid . crInvEquipped . ix invid
return $ pointcid . crEquipment . at epos .~ Nothing
maxk = fmap fst $ IM.lookupMax $ cr ^. crInv
f inv =
let (xs, ys) = IM.split invid inv
in xs `IM.union` IM.mapKeysMonotonic (subtract 1) ys
-- the following might not work if a non-player creature drops their last item
g x
| x > invid || Just x == maxk = max 0 $ x - 1
| otherwise = x
g' Nothing = Nothing
g' (Just x)
| x == invid = Nothing
| x > invid || Just x == maxk = Just $ max 0 $ x - 1
| otherwise = Just x
rmSelectedInvItem :: Int -> World -> World
rmSelectedInvItem cid w = case w ^? cWorld . lWorld . creatures . ix cid . crManipulation . manObject . inInventory . ispItem of
Just i -> rmInvItem cid i w
Nothing -> w
--selNumPos :: ManipulatedObject -> World -> Maybe Int
--selNumPos mo w =
-- w ^? hud . hudElement . diSections
-- >>= case mo of
-- InInventory SortInventory -> selSecSelPos (-1) 0
-- InInventory (SelItem i _) -> selSecSelPos 0 i
-- SelNothing -> selSecSelPos 1 0
-- InNearby SortNearby -> selSecSelPos 2 0
-- InNearby (SelCloseObject i) -> selSecSelPos 3 i
-- there are still more ListDisplayParams to integrate here
selNumTextEndPos :: Configuration -> ListDisplayParams -> SelectionSections a -> Int -> Int -> Maybe Point2
selNumTextEndPos cfig ldp sss i j = do
ipos <- selSecSelPos i j sss
return $ V2 (150 - hw) (hh - ((s * 10 + ygap) * (fromIntegral ipos + 1)))
where
s = _ldpScale ldp
ygap = _ldpVerticalGap ldp
hh = halfHeight cfig
hw = halfWidth cfig
selNumEndMidHeight ::
Configuration ->
ListDisplayParams ->
SelectionSections a ->
Int ->
Int ->
Maybe Point2
selNumEndMidHeight cfig ldp sss i j = do
ipos <- selSecSelPos i j sss
size <- selSecSelSize i j sss
--let bump = negate $ (10 * s + ygap) * fromIntegral size
return $ V2 (150 - hw) (hh - ((10 * s + ygap) * (fromIntegral ipos + fromIntegral size * 0.5)))
where
s = _ldpScale ldp
ygap = _ldpVerticalGap ldp
hh = halfHeight cfig
hw = halfWidth cfig
selSecSelCol :: Int -> Int -> SelectionSections a -> Maybe Color
selSecSelCol i j sss = sss ^? sssSections . ix i . ssItems . ix j . siColor
checkTermDist :: World -> World
--checkTermDist w = case w ^? hud . hudElement . subInventory . termID of
-- Just tmid -> fromMaybe (w & hud . hudElement . subInventory .~ NoSubInventory) $ do
-- btid <- w ^? cWorld . lWorld . terminals . ix tmid . tmButtonID
-- btpos <- w ^? cWorld . lWorld . buttons . ix btid . btPos
-- guard $ dist btpos (_crPos $ you w) < 40
-- return w
-- Nothing -> w
checkTermDist w = fromMaybe w $ do
tmid <- w ^? hud . hudElement . subInventory . termID
btid <- w ^? cWorld . lWorld . terminals . ix tmid . tmButtonID
btpos <- w ^? cWorld . lWorld . buttons . ix btid . btPos
guard $ dist btpos (_crPos $ you w) > 40
return (w & hud . hudElement . subInventory .~ NoSubInventory)
-- this looks ugly...
updateCloseObjects :: World -> World
updateCloseObjects w =
w
& hud . closeObjects .~ newcloseobjects
& updatecursorposifnecessary
where
newcloseobjects = unionBy closeObjEq oldCloseFiltered currentClose
updatecursorposifnecessary =
case w ^? cWorld . lWorld . creatures . ix 0 . crManipulation . manObject . inNearby . ispCloseObject of
Just i
| i >= length newcloseobjects -> scrollAugInvSel 1
| isNothing (w ^? hud . hudElement . diSections . sssSections . ix 3 . ssItems . ix i) ->
scrollAugInvSel (-1)
_ -> id
filt = filter $ \obj -> dist ypos (closeObjPos obj) < 40 && hasButtonLOS ypos (closeObjPos obj) w
ypos = _crPos $ you w
activeButtons =
map Right
. filter ((/=) BtNoLabel . _btState)
. IM.elems
$ w ^. cWorld . lWorld . buttons
currentClose = filt $ map Left (IM.elems $ w ^. cWorld . lWorld . floorItems) ++ activeButtons
oldClose = filt $ mapMaybe updatebyid $ w ^. hud . closeObjects
oldCloseFiltered = intersectBy closeObjEq oldClose currentClose
updatebyid (Left flid) = fmap Left $ w ^? cWorld . lWorld . floorItems . ix (_flItID flid)
updatebyid (Right btid) = fmap Right $ w ^? cWorld . lWorld . buttons . ix (_btID btid)
updateRBList :: World -> World
updateRBList w
| w ^? rbOptions . opItemID == mcurrentitemid =
w & setEquipAllocation & setEquipActivation
| otherwise = fromMaybe (w & rbOptions .~ NoRightButtonOptions) $ do
i <- cr ^? crManipulation . manObject . inInventory . ispItem
esite <- cr ^? crInv . ix i . itUse . equipEffect . eeSite
itid <- mcurrentitemid
return $
w
& rbOptions
.~ EquipOptions
{ _opEquip = equipSiteToPositions esite
, _opSel = chooseEquipmentPosition cr (equipSiteToPositions esite)
, _opItemID = itid
, _opAllocateEquipment = DoNotMoveEquipment
, _opActivateEquipment = NoChangeActivateEquipment
}
& setEquipAllocation
& setEquipActivation
where
mcurrentitemid = do
i <- cr ^? crManipulation . manObject . inInventory . ispItem
cr ^? crInv . ix i . itID
--curinvid = crSel cr
cr = you w
chooseEquipmentPosition :: Creature -> [EquipPosition] -> Int
chooseEquipmentPosition cr eps = fromMaybe (chooseFreeSite cr eps) $ do
i <- cr ^? crManipulation . manObject . inInventory . ispItem
ep <- cr ^? crInvEquipped . ix i
elemIndex ep eps
chooseFreeSite :: Creature -> [EquipPosition] -> Int
chooseFreeSite cr = fromMaybe 0 . findIndex hasnoequipment
where
hasnoequipment ep = isNothing $ cr ^? crEquipment . ix ep
setEquipAllocation :: World -> World
setEquipAllocation w = fromMaybe w $ do
curpos <- you w ^? crManipulation . manObject . inInventory . ispItem
return $ case _rbOptions w of
EquipOptions{_opEquip = es, _opSel = i} ->
case you w ^? crInvEquipped . ix curpos of
Just epos
| es !! i == epos ->
w & rbOptions . opAllocateEquipment
.~ RemoveEquipment
{ _allocOldPos = epos
}
Just epos
| isJust (you w ^? crEquipment . ix (es !! i)) ->
w & rbOptions . opAllocateEquipment
.~ SwapEquipment
{ _allocOldPos = epos
, _allocNewPos = es !! i
, _allocSwapID = _crEquipment (you w) M.! (es !! i)
}
Just epos ->
w & rbOptions . opAllocateEquipment
.~ MoveEquipment
{ _allocOldPos = epos
, _allocNewPos = es !! i
}
Nothing
| isJust (you w ^? crEquipment . ix (es !! i)) ->
w & rbOptions . opAllocateEquipment
.~ ReplaceEquipment
{ _allocNewPos = es !! i
, _allocRemoveID = _crEquipment (you w) M.! (es !! i)
}
Nothing ->
w & rbOptions . opAllocateEquipment
.~ PutOnEquipment
{ _allocNewPos = es !! i
}
_ -> w
setEquipActivation :: World -> World
setEquipActivation w = case w ^? rbOptions . opAllocateEquipment of
Just DoNotMoveEquipment -> w
Just RemoveEquipment{} ->
case you w ^. crLeftInvSel . lisMPos of
Just i
| Just i == minvsel ->
w & rbOptions . opActivateEquipment
.~ DeactivateEquipment
{ _deactivateEquipment = i
}
_ -> w & rbOptions . opActivateEquipment .~ NoChangeActivateEquipment
Just rbos ->
case you w ^. crLeftInvSel . lisMPos of
Just i | Just i == minvsel -> w & rbOptions . opActivateEquipment .~ NoChangeActivateEquipment
Just i
| invselcanactivate ->
w & rbOptions . opActivateEquipment
.~ ActivateDeactivateEquipment
{ _activateEquipment = fromJust minvsel
, _deactivateEquipment = i
}
Just i
| Just i == rbos ^? allocRemoveID ->
w & rbOptions . opActivateEquipment .~ DeactivateEquipment i
Just _ -> w & rbOptions . opActivateEquipment .~ NoChangeActivateEquipment
Nothing
| invselcanactivate ->
w & rbOptions . opActivateEquipment
.~ ActivateEquipment
{ _activateEquipment = fromJust minvsel
}
Nothing -> w & rbOptions . opActivateEquipment .~ NoChangeActivateEquipment
Nothing -> w & rbOptions . opActivateEquipment .~ NoChangeActivateEquipment
where
minvsel = cr ^? crManipulation . manObject . inInventory . ispItem
cr = you w
invselcanactivate = isJust $ do
i <- minvsel
return $ cr ^? crInv . ix i . itUse . leftUse
equipSiteToPositions :: EquipSite -> [EquipPosition]
equipSiteToPositions es = case es of
GoesOnHead -> [OnHead]
GoesOnChest -> [OnChest]
GoesOnBack -> [OnBack]
GoesOnWrist -> [OnLeftWrist, OnRightWrist]
GoesOnLegs -> [OnLegs]
closeObjScrollDir :: Float -> World -> World
closeObjScrollDir x
| x > 0 = over (hud . closeObjects) rotU
| x < 0 = over (hud . closeObjects) rotD
| otherwise = id
changeSwapSel :: Int -> World -> World
changeSwapSel yi w
| yi == 0 = w
| yi > 0 = foldr ($) w $ replicate yi (changeSwapWith $ f IM.cycleLT)
| otherwise = foldr ($) w $ replicate (negate yi) (changeSwapWith $ f IM.cycleGT)
where
f g i m = fst <$> g i m
changeSwapClose :: (Int -> IM.IntMap (SelectionItem ()) -> Maybe Int)
-> Int -> World -> World
changeSwapClose f i w = fromMaybe w $ do
ss <- w ^? hud . hudElement . diSections . sssSections . ix 3 . ssItems
k <- f i ss
return $ w
& cWorld . lWorld . creatures . ix 0 . crManipulation . manObject . inNearby . ispCloseObject
.~ k
& hud . closeObjects %~ swapIndices i k
& hud . hudElement . diSections . sssExtra . sssSelPos . _Just . _2 .~ k
& worldEventFlags . at InventoryChange ?~ ()
changeSwapInv :: (Int -> IM.IntMap (SelectionItem ()) -> Maybe Int)
-> Int -> World -> World
changeSwapInv f i w = fromMaybe w $ do
ss <- w ^? hud . hudElement . diSections . sssSections . ix 0 . ssItems
k <- f i ss
return $
w & cWorld . lWorld . creatures . ix 0 %~ updatecreature k
& hud . hudElement . diSections . sssExtra . sssSelPos . _Just . _2 .~ k
& worldEventFlags . at InventoryChange ?~ ()
where
updateLeftInvSel k li
| i == li = k
| k == li = i
| otherwise = li
updatecreature k =
(crInv %~ IM.safeSwapKeys i k)
. (crLeftInvSel . lisMPos . _Just %~ updateLeftInvSel k)
. (crManipulation . manObject . inInventory . ispItem .~ k)
. (crInvEquipped %~ IM.safeSwapKeys i k)
. swapSite i k
. swapSite k i
cr = you w
swapSite a b = case cr ^? crInvEquipped . ix a of
Just epos -> crEquipment . ix epos .~ b
Nothing -> id
changeSwapWith :: (Int -> IM.IntMap (SelectionItem ()) -> Maybe Int) -> World -> World
changeSwapWith f w = case w ^? hud . hudElement . diSections . sssExtra . sssSelPos . _Just of
Just (0,i) -> w & changeSwapInv f i
Just (3,i) -> w & changeSwapClose f i
_ -> w
--changeSwapInvSel' :: Int -> World -> World
--changeSwapInvSel' k w = case you w ^? crManipulation . manObject of
-- Just (InInventory (SelItem i _)) ->
-- w & cWorld . lWorld . creatures . ix 0 %~ updatecreature i
-- & worldEventFlags . at InventoryChange ?~ ()
-- Just (InNearby (SelCloseObject i)) ->
-- w
-- & cWorld . lWorld . creatures . ix 0 . crManipulation . manObject . inNearby . ispCloseObject
-- .~ ((i - k) `mod` numCO)
-- & hud . closeObjects %~ swapIndices i ((i - k) `mod` numCO)
-- & worldEventFlags . at InventoryChange ?~ ()
-- _ -> w
-- where
-- updatecreature i =
-- (crInv %~ IM.safeSwapKeys (i `mod` n) (swapi i))
-- . (crLeftInvSel . lisMPos . _Just %~ updateLeftInvSel i)
-- . (crManipulation . manObject . inInventory . ispItem %~ (`mod` n) . subtract k)
-- . (crInvEquipped %~ IM.safeSwapKeys i (swapi i))
-- . swapSite i (swapi i)
-- . swapSite (swapi i) i
-- swapSite a b = case cr ^? crInvEquipped . ix a of
-- Just epos -> crEquipment . ix epos .~ b
-- Nothing -> id
-- cr = you w
-- swapi i = (i - k) `mod` n
-- updateLeftInvSel i li
-- | i == li = swapi i
-- | swapi i == li = i
-- | otherwise = li
-- n = length $ _crInv cr
-- numCO = length $ w ^. hud . closeObjects
scrollAugInvSel :: Int -> World -> World
scrollAugInvSel yi w
| yi == 0 = w
| otherwise =
w & hud . hudElement . diSections %~ scrollSelectionSections yi
& worldEventFlags . at InventoryChange ?~ ()
& setInvPosFromSS
setInvPosFromSS :: World -> World
setInvPosFromSS w =
w
& cWorld . lWorld . creatures . ix 0 . crManipulation . manObject .~ thesel
where
thesel = fromMaybe SelNothing $ do
sss <- w ^? hud . hudElement . diSections
(i, j) <- sss ^? sssExtra . sssSelPos . _Just
case i of
(-1) -> Just $ InInventory SortInventory
0 -> Just $ InInventory (SelItem j NoInvSelAction)
1 -> Just SelNothing
2 -> Just $ InNearby SortNearby
3 -> Just $ InNearby $ SelCloseObject j
_ -> error "selection out of bounds"
selectedCloseObject :: World -> Maybe (Either FloorItem Button)
selectedCloseObject w = do
i <-
you w ^? crManipulation . manObject . inNearby . ispCloseObject
<|> fmap fst (IM.lookupMin =<< w ^? hud . hudElement . diSections . sssSections . ix 3 . ssItems)
w ^? hud . closeObjects . ix i