--{-# 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