Files
loop/src/Dodge/Inventory.hs
T

213 lines
7.4 KiB
Haskell

--{-# LANGUAGE TupleSections #-}
module Dodge.Inventory (
rmInvItem,
destroyInvItem,
updateCloseObjects,
changeSwapSel,
invSetSelection,
invSetSelectionPos,
scrollAugInvSel,
setInvPosFromSS,
module Dodge.Inventory.RBList,
swapInvItems,
scrollAugNextInSection,
swapItemWith,
destroyItem,
destroyAllInvItems,
) where
import Data.Function
import Data.Maybe
import Dodge.Base
import Dodge.Data.SelectionList
import Dodge.Data.World
import Dodge.Equipment
import Dodge.Inventory.Location
import Dodge.Inventory.RBList
import Dodge.Inventory.Swap
import Dodge.SelectionSections
import Geometry
import qualified IntMapHelp as IM
import LensHelp
import ListHelp
import NewInt
-- TODO check what happens to selection index when dropping non-selected items
-- should consider never fully destroying items, but assigning a flag saying how
-- they were moved from play
destroyInvItem :: Int -> NewInt InvInt -> World -> World
destroyInvItem cid invid w = rmInvItem cid invid w & removeitloc & removeithotkey
where
removeitloc = fromMaybe id $ do
itid <- w ^? cWorld . lWorld . creatures . ix cid . crInv . ix invid
return $ cWorld . lWorld . items . at itid .~ Nothing
removeithotkey = fromMaybe id $ do
itid <- w ^? cWorld . lWorld . creatures . ix cid . crInv . ix invid
hk <- w ^? cWorld . lWorld . imHotkeys . unNIntMap . ix itid
return $
(cWorld . lWorld . imHotkeys . unNIntMap . at itid .~ Nothing)
. (cWorld . lWorld . hotkeys . at hk .~ Nothing)
destroyAllInvItems :: Creature -> World -> World
destroyAllInvItems cr w =
foldl' (flip $ destroyInvItem (cr ^. crID)) w
. reverse
. fmap NInt
. IM.keys
. _unNIntMap
$ cr ^. crInv
destroyItem :: Int -> World -> World
destroyItem itid w = case w ^? cWorld . lWorld . items . ix itid . itLocation of
Nothing -> error $ "Tried to destroy item that does not exist; item id: " ++ show itid
Just InInv{_ilCrID = cid, _ilInvID = invid} -> destroyInvItem cid invid w
Just OnTurret{} -> error "need to write code for destroying items on turrets"
Just OnFloor ->
w & cWorld . lWorld . items . at itid .~ Nothing
& cWorld . lWorld . floorItems . at itid .~ Nothing
Just InVoid -> w & cWorld . lWorld . items . at itid .~ Nothing
-- note rmInvItem does not fully destroy the item, other updates to the item
-- location are required
rmInvItem :: Int -> NewInt InvInt -> World -> World
rmInvItem cid invid w =
w
& dounequipfunction --the ordering of these is
& pointcid . crInv %~ f -- important
& removeAnySlotEquipment
& cWorld . lWorld . items . ix itid . itLocation . ilEquipSite .~ Nothing
& updateselection
& updateselectionextra
& pointcid %~ updateRootItemID (w ^. cWorld . lWorld . items)
& worldEventFlags . at InventoryChange ?~ ()
where
pointcid = cWorld . lWorld . creatures . ix cid
updateselectionextra
| cid == 0 = hud . diSelection . _Just . slSet %~ const mempty
| otherwise = id
updateselection
| cid == 0 && cr ^? crManipulation . manObject . imSelectedItem == Just invid =
scrollAugInvSel (-1) . scrollAugInvSel 1
| otherwise =
pointcid . crManipulation . manObject . imSelectedItem %~ g
cr = w ^?! cWorld . lWorld . creatures . ix cid
itid = _crInv cr ^?! ix invid
itm = w ^?! cWorld . lWorld . items . ix itid
dounequipfunction = effectOnRemove itm cr
removeAnySlotEquipment = fromMaybe id $ do
epos <- itm ^?
itLocation
. ilEquipSite
. _Just
return $ pointcid . crEquipment . at epos .~ Nothing
-- return $ pointcid . crEquipment .~ mempty
maxk = fmap fst $ IM.lookupMax $ _unNIntMap $ cr ^. crInv
f inv =
let (xs, ys) = IM.split (_unNInt invid) $ _unNIntMap inv
in NIntMap $ 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 == fmap NInt maxk = max 0 $ x - 1
| otherwise = x
updateCloseObjects :: World -> World
updateCloseObjects w =
w & hud . closeItems %~ h citems
& hud . closeButtons %~ h cbts
where
h a b = intersect b a `union` a
lw = w ^. cWorld . lWorld
citems = map NInt $ IM.keys $ IM.intersection (lw ^. items)
$ IM.filter (isclose . _flItPos) (lw^.floorItems)
cbts = lw^..buttons . each . filtered canpress . filtered (isclose . _btPos) . to _btID
canpress bt = case bt ^. btEvent of
ButtonPress{_btOn = t} -> not t
ButtonAccessTerminal tid -> fromMaybe False $ do
x <- lw ^? terminals . ix tid . tmStatus
return (x /= TerminalDeactivated)
_ -> True
isclose x = dist y x < 40 && hasButtonLOS y x w
y = _crPos $ you w
changeSwapSel :: Int -> World -> World
changeSwapSel yi w
| yi >= 0 = foldl' (&) w $ replicate yi (changeSwapWith $ f IM.cycleLT)
| otherwise = foldl' (&) w $ replicate (negate yi) (changeSwapWith $ f IM.cycleGT)
where
f g i m = fst <$> g i m
changeSwapOther ::
((Int -> Identity Int) -> ManipulatedObject -> Identity ManipulatedObject) ->
Int ->
(Int -> IM.IntMap (SelectionItem ()) -> Maybe Int) ->
Int ->
World ->
World
changeSwapOther manlens n f i w = fromMaybe w $ do
ss <- w ^? hud . diSections . ix n . ssItems
k <- f i ss
let doswap j
| j == i = k
| j == k = i
| otherwise = j
return $
w
& swapAnyExtraSelection i k
& cWorld . lWorld . creatures . ix 0 . crManipulation . manObject . manlens
%~ doswap
& hud . closeItems %~ swapIndices i k
& hud . diSelection . _Just . slInt %~ doswap
& worldEventFlags . at InventoryChange ?~ ()
swapItemWith ::
(Int -> IM.IntMap (SelectionItem ()) -> Maybe Int) ->
(Int, Int) ->
World ->
World
swapItemWith f (j, i) = case j of
0 -> swapInvItems f i
3 -> changeSwapOther ispCloseItem 3 f i
5 -> changeSwapOther ispCloseButton 5 f i
_ -> id
changeSwapWith :: (Int -> IM.IntMap (SelectionItem ()) -> Maybe Int) -> World -> World
changeSwapWith f w
| Just (Sel j i _) <- w ^. hud . diSelection = swapItemWith f (j,i) w
| otherwise = w
invSetSelection :: Selection -> World -> World
invSetSelection sel w =
w
& hud . diSelection ?~ sel
& worldEventFlags . at InventoryChange ?~ ()
& setInvPosFromSS
& cWorld . lWorld %~ crUpdateItemLocations 0
invSetSelectionPos :: Int -> Int -> World -> World
invSetSelectionPos i j = invSetSelection (Sel i j mempty)
scrollAugInvSel :: Int -> World -> World
scrollAugInvSel yi w
| yi == 0 = w
| otherwise =
w & hud %~ doscroll
& worldEventFlags . at InventoryChange ?~ ()
& setInvPosFromSS
& cWorld . lWorld %~ crUpdateItemLocations 0
where
doscroll he = fromMaybe he $ do
sss <- he ^? diSections
return $ he & diSelection %~ scrollSelectionSections yi sss
scrollAugNextInSection :: World -> World
scrollAugNextInSection w =
w & hud %~ doscroll
& worldEventFlags . at InventoryChange ?~ ()
& setInvPosFromSS
& cWorld . lWorld %~ crUpdateItemLocations 0
where
doscroll he = fromMaybe he $ do
sss <- he ^? diSections
return $ he & diSelection %~ nextInSectionSS sss