Files
loop/src/Dodge/Inventory.hs
T

343 lines
13 KiB
Haskell

--{-# LANGUAGE TupleSections #-}
module Dodge.Inventory (
checkInvSlotsYou,
rmSelectedInvItem,
rmInvItem,
updateCloseObjects,
updateRBList,
closeObjScrollDir,
changeSwapSel,
scrollAugInvSel,
crNumFreeSlots,
crInvSize,
selectedCloseObject,
setInvPosFromSS,
) where
import Control.Applicative
import qualified Data.Map.Strict as M
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.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
& removeAnySlotEquipment -- the ordering
& dounequipfunction -- of these is
& pointcid . crInv %~ f -- important
& pointcid . crLeftInvSel . lisMPos %~ g'
& 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 = 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
-- 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 & setEquipAllocationActivation
| 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
}
& setEquipAllocationActivation
where
mcurrentitemid = do
i <- cr ^? crManipulation . manObject . inInventory . ispItem
cr ^? crInv . ix i . itID
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
setEquipAllocationActivation :: World -> World
setEquipAllocationActivation = setEquipActivation . setEquipAllocation
setEquipAllocation :: World -> World
setEquipAllocation w = fromMaybe w $ do
curpos <- you w ^? crManipulation . manObject . inInventory . ispItem
i <- w ^? rbOptions . opSel
es <- w ^? rbOptions . opEquip . ix i
return $
w & rbOptions . opAllocateEquipment .~ case you w ^? crInvEquipped . ix curpos of
Just epos
| es == epos -> RemoveEquipment{_allocOldPos = epos}
Just epos
| isJust (you w ^? crEquipment . ix es) ->
SwapEquipment
{ _allocOldPos = epos
, _allocNewPos = es
, _allocSwapID = _crEquipment (you w) M.! es
}
Just epos ->
MoveEquipment
{ _allocOldPos = epos
, _allocNewPos = es
}
Nothing
| isJust (you w ^? crEquipment . ix es) ->
ReplaceEquipment
{ _allocNewPos = es
, _allocRemoveID = _crEquipment (you w) M.! es
}
Nothing -> PutOnEquipment{_allocNewPos = es}
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
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