Files
loop/src/Dodge/Inventory.hs
T

222 lines
8.0 KiB
Haskell

--{-# LANGUAGE TupleSections #-}
module Dodge.Inventory (
checkInvSlotsYou,
rmInvItem,
destroyInvItem,
updateCloseObjects,
changeSwapSel,
scrollAugInvSel,
crNumFreeSlots,
crInvSize,
selectedCloseObject,
setInvPosFromSS,
module Dodge.Inventory.RBList
) where
import NewInt
import Dodge.Inventory.Location
import Dodge.Inventory.RBList
import Control.Applicative
import Data.Maybe
import Dodge.Base
import Dodge.Data.SelectionList
import Dodge.Data.World
import Dodge.DisplayInventory
import Dodge.Euse
import Dodge.Inventory.CheckSlots
import Dodge.Inventory.CloseObject
import Dodge.ItEffect
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
-- should consider never fully destroying items, but assigning a flag saying how
-- they were moved from play
destroyInvItem ::
Int ->
-- | Inventory position
Int ->
World ->
World
destroyInvItem cid invid w = rmInvItem cid invid w & removeitloc
where
removeitloc = fromMaybe id $ do
itid <- w ^? cWorld . lWorld . creatures . ix cid . crInv . ix invid . itID . unNInt
return $ cWorld . lWorld . itemLocations . at itid .~ Nothing
-- | 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 = w
& doanyitemeffect
& dounequipfunction --the ordering of these is
& pointcid . crInv %~ f -- important
& removeAnySlotEquipment
& pointcid . crEquipment . each %~ g
& pointcid . crInvEquipped %~ IM.delete invid
& pointcid . crInvEquipped %~ IM.mapKeys g
& removeanyactivation
& pointcid . crHotkeys . each %~ g
& pointcid . crInvHotkeys %~ IM.delete invid
& pointcid . crInvHotkeys %~ IM.mapKeys g
& updateselection
& pointcid %~ updateRootItemID
& worldEventFlags . at InventoryChange ?~ ()
-- & updateCreatureItemLocations cid
where
pointcid = cWorld . lWorld . creatures . ix cid
updateselection
| cid == 0 && cr ^? crManipulation . manObject . imSelectedItem == Just invid =
scrollAugInvSel (-1) . scrollAugInvSel 1 . updateInventorySectionItems
| otherwise =
pointcid . crManipulation . manObject . imSelectedItem %~ g
cr = w ^?! cWorld . lWorld . creatures . ix cid
itm = _crInv cr IM.! invid
dounequipfunction = fromMaybe id $ do
rmf <- itm ^? itUse . uequipEffect . eeOnRemove
return $ useE rmf itm cr
doanyitemeffect = fromMaybe id $ do
rmf <- itm ^? itEffect . ieOnDrop
return $ doInvEffect rmf itm cr
removeAnySlotEquipment = fromMaybe id $ do
epos <- w ^? cWorld . lWorld . creatures . ix cid . crInvEquipped . ix invid
return $ pointcid . crEquipment . at epos .~ Nothing
removeanyactivation = fromMaybe id $ do
epos <- w ^? cWorld . lWorld . creatures . ix cid . crInvHotkeys . ix invid
return $ pointcid . crHotkeys . 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
-- 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 . 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 . unNIntMap)
++ activeButtons
oldClose = filt $ mapMaybe updatebyid $ w ^. hud . closeObjects
oldCloseFiltered = intersectBy closeObjEq oldClose currentClose
updatebyid (Left flid) = fmap Left $ w ^? cWorld . lWorld . floorItems . unNIntMap
. ix (_unNInt $ _flItID flid)
updatebyid (Right btid) = fmap Right $ w ^? cWorld . lWorld . buttons . ix (_btID btid)
changeSwapSel :: Int -> World -> World
changeSwapSel yi w
| yi == 0 = 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
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 . 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
-- & cWorld . lWorld . creatures . ix 0 %~ updateRootItemID
& hud . hudElement . diSections . sssExtra . sssSelPos . _Just . _2 .~ k
& worldEventFlags . at InventoryChange ?~ ()
& cWorld . lWorld %~ crUpdateItemLocations 0
& setInvPosFromSS
& cWorld . lWorld %~ crUpdateItemLocations 0 -- the double application is inefficient, but necessary without further changes
-- a rethink is maybe in order
where
updatecreature k =
(crInv %~ IM.safeSwapKeys i k)
. (crManipulation . manObject . imSelectedItem .~ k)
. (crInvEquipped %~ IM.safeSwapKeys i k)
. swapSite i k
. swapSite k i
. (crInvHotkeys %~ 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
swapSite' a b = case cr ^? crInvHotkeys . ix a of
Just epos -> crHotkeys . 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
scrollAugInvSel :: Int -> World -> World
scrollAugInvSel yi w
| yi == 0 = w
| otherwise =
w & hud . hudElement . diSections %~ scrollSelectionSections yi
& worldEventFlags . at InventoryChange ?~ ()
& setInvPosFromSS
& cWorld . lWorld %~ crUpdateItemLocations 0
selectedCloseObject :: World -> Maybe (Either FloorItem Button)
selectedCloseObject w = do
i <-
you w ^? crManipulation . manObject . ispCloseObject
<|> fmap fst (IM.lookupMin =<< w ^? hud . hudElement . diSections . sssSections . ix 3 . ssItems)
w ^? hud . closeObjects . ix i