c4e8046332
Introduce "gadgets" as a structural function, for items that can be used when held and when not held. Click detectors are such an item. Make click detectors correctly attach and use up batteries when used.
241 lines
8.7 KiB
Haskell
241 lines
8.7 KiB
Haskell
module Dodge.Item.Grammar (
|
|
invLDT,
|
|
invAdj,
|
|
invRootMap,
|
|
invRootTrees,
|
|
basePCI,
|
|
allInvLocs,
|
|
) where
|
|
|
|
import Control.Applicative
|
|
import qualified Data.IntMap.Strict as IM
|
|
import Data.Maybe
|
|
import Dodge.Data.ComposedItem
|
|
import Dodge.Data.DoubleTree
|
|
import Dodge.Data.Item
|
|
import Dodge.DoubleTree
|
|
import Dodge.Item.Orientation
|
|
import LensHelp
|
|
import ListHelp
|
|
|
|
tryAttachItems ::
|
|
LabelDoubleTree ItemLink ComposedItem ->
|
|
LabelDoubleTree ItemLink ComposedItem ->
|
|
Maybe (LabelDoubleTree ItemLink ComposedItem)
|
|
tryAttachItems = leftRightCombine leftIsParentCombine rightIsParentCombine
|
|
|
|
useBreakL ::
|
|
[(ItemStructuralFunction, ComposeLinkType)] ->
|
|
[(ItemStructuralFunction, ComposeLinkType)] ->
|
|
LinkTest
|
|
useBreakL x y = useBreakListsLinkTest (map (uncurry noa) x) (map (uncurry noa) y)
|
|
where
|
|
noa a b = (a, ILink b orientAttachment)
|
|
|
|
useBreakListsLinkTest ::
|
|
[(ItemStructuralFunction, ItemLink)] ->
|
|
[(ItemStructuralFunction, ItemLink)] ->
|
|
LinkTest
|
|
useBreakListsLinkTest llist rlist = LTest ltest rtest
|
|
where
|
|
ltest (_, sf, _) = do
|
|
let xs = dropWhile ((/= sf) . fst) llist
|
|
(_, linktype) <- safeHead xs
|
|
return $ LUpdate linktype (set _3 (useBreakListsLinkTest (tail xs) rlist)) id
|
|
rtest (_, sf, _) = do
|
|
let xs = dropWhile ((/= sf) . fst) rlist
|
|
(_, linktype) <- safeHead xs
|
|
return $ LUpdate linktype (set _3 (useBreakListsLinkTest llist (tail xs))) id
|
|
|
|
itemToBreakLists ::
|
|
Item ->
|
|
ItemStructuralFunction ->
|
|
([(ItemStructuralFunction, ComposeLinkType)], [(ItemStructuralFunction, ComposeLinkType)])
|
|
itemToBreakLists itm itmf = case (itm ^. itType, itmf) of
|
|
(HELD TORCH, _) -> (getAmmoLinks itm, [])
|
|
(_, HeldPlatformSF) ->
|
|
( getAmmoLinks itm
|
|
, [(WeaponTargetingSF, WeaponTargetingLink), (WeaponScopeSF, WeaponScopeLink)]
|
|
)
|
|
(_, GadgetPlatformSF) ->
|
|
( getAmmoLinks itm
|
|
, [(TriggerSF,TriggerLink),(WeaponTargetingSF, WeaponTargetingLink), (WeaponScopeSF, WeaponScopeLink)]
|
|
)
|
|
(_, AmmoMagSF{}) -> fromMaybe ([], []) $ do
|
|
atype <- itm ^? itUse . amagType
|
|
return
|
|
(
|
|
[ (AmmoModifierSF atype, AmmoModLink)
|
|
, (AmmoTargetingSF atype, AmmoTargetingLink)
|
|
, (AmmoPayloadSF atype, AmmoPayloadLink)
|
|
, (AmmoEffectSF atype, AmmoEffectLink)
|
|
, (RemoteScreenSF, RemoteScreenLink)
|
|
]
|
|
, []
|
|
)
|
|
(_, WeaponTargetingSF) -> (getAmmoLinks itm ++ [(AugmentedHUDSF, AugmentedHUDLink)], [])
|
|
(ATTACH BULLETSYNTH, _) ->
|
|
([(AmmoMagSF ElectricalAmmo, AmmoInLink 0 ElectricalAmmo)], [])
|
|
_ -> ([], [])
|
|
|
|
getAmmoLinks :: Item -> [(ItemStructuralFunction, ComposeLinkType)]
|
|
getAmmoLinks itm =
|
|
map
|
|
(\(i, a) -> (AmmoMagSF a, AmmoInLink i a))
|
|
(IM.toList $ itm ^. itAmmoSlots)
|
|
|
|
itemToFunction :: Item -> ItemStructuralFunction
|
|
itemToFunction itm = case itm ^. itType of
|
|
HELD DETECTOR{} -> GadgetPlatformSF
|
|
HELD LASER -> WeaponTargetingSF
|
|
HELD{} -> HeldPlatformSF
|
|
AMMOMAG{} -> maybe UncomposableIsolateSF AmmoMagSF $ itm ^? itUse . amagType
|
|
ATTACH REMOTESCREEN -> RemoteScreenSF
|
|
ATTACH BULLETSYNTH -> AmmoModifierSF BulletAmmo
|
|
ATTACH ZOOMSCOPE -> WeaponScopeSF
|
|
ATTACH HOMINGMODULE -> AmmoTargetingSF LauncherAmmo
|
|
ATTACH AUGMENTEDHUD -> AugmentedHUDSF
|
|
BULLETMOD BulletModTrajectory{} -> AmmoTargetingSF BulletAmmo
|
|
BULLETMOD BulletModPayload{} -> AmmoPayloadSF BulletAmmo
|
|
BULLETMOD BulletModEffect{} -> AmmoEffectSF BulletAmmo
|
|
TARGETING{} -> WeaponTargetingSF
|
|
LEFT{} -> EquipmentPlatformSF
|
|
EQUIP WRIST_ECG -> TriggerSF
|
|
EQUIP{} -> EquipmentPlatformSF
|
|
_ -> UncomposableIsolateSF
|
|
|
|
basePCI :: Item -> ComposedItem
|
|
basePCI itm = case _itType itm of
|
|
_ -> (itm, itemToFunction itm, itemBaseConnections itm)
|
|
|
|
itemBaseConnections :: Item -> LinkTest
|
|
itemBaseConnections itm = case _itType itm of
|
|
HELD LASER -> laserLinkTest itm
|
|
_ -> uncurry useBreakL $ itemToBreakLists itm (itemToFunction itm)
|
|
|
|
laserLinkTest :: Item -> LinkTest
|
|
laserLinkTest itm = LTest (llleft itm) (llright itm)
|
|
|
|
llleft :: Item -> ComposedItem -> Maybe LinkUpdate
|
|
llleft itm =
|
|
_tryLeftLink
|
|
. uncurry useBreakL
|
|
$ itemToBreakLists itm WeaponTargetingSF
|
|
|
|
llright :: Item -> ComposedItem -> Maybe LinkUpdate
|
|
llright itm pci = case pci ^. _1 . itType of
|
|
CRAFT TRANSFORMER -> Just (toLasgunUpdate itm)
|
|
_ -> _tryRightLink (uncurry useBreakL $ itemToBreakLists itm WeaponTargetingSF) pci
|
|
|
|
toLasgunUpdate :: Item -> LinkUpdate
|
|
toLasgunUpdate itm =
|
|
LUpdate
|
|
(ILink FunctionChangeLink orientAttachment)
|
|
(\(par, _, _) -> (par, HeldPlatformSF, uncurry useBreakL $ itemToBreakLists itm HeldPlatformSF))
|
|
(\(chi, _, up) -> (chi, FunctionChangeSF, up))
|
|
|
|
--itemLinkTestLeft :: Item -> PartiallyComposedItem -> Maybe LinkUpdate
|
|
--itemLinkTestLeft itm = _tryLeftLink $
|
|
-- uncurry useBreakL $ itemToBreakLists itm
|
|
|
|
type LDTComb a b = LabelDoubleTree b a -> LabelDoubleTree b a -> Maybe (LabelDoubleTree b a)
|
|
|
|
leftIsParentCombine :: LDTComb ComposedItem ItemLink
|
|
leftIsParentCombine ltree rtree = do
|
|
lu <- (ltree ^. ldtValue . _3 . tryRightLink) (rtree ^. ldtValue)
|
|
return $
|
|
ltree & ldtValue %~ (lu ^. luParentUpdate)
|
|
& ldtRight %~ (++ [(lu ^. luLinkType, rtree & ldtValue %~ (lu ^. luChildUpdate))])
|
|
|
|
rightIsParentCombine :: LDTComb ComposedItem ItemLink
|
|
rightIsParentCombine ltree rtree = do
|
|
lu <- (rtree ^. ldtValue . _3 . tryLeftLink) (ltree ^. ldtValue)
|
|
return $
|
|
rtree & ldtValue %~ (lu ^. luParentUpdate)
|
|
& ldtLeft .:~ (lu ^. luLinkType, ltree & ldtValue %~ (lu ^. luChildUpdate))
|
|
|
|
leftRightCombine ::
|
|
LDTComb a b ->
|
|
LDTComb a b ->
|
|
LabelDoubleTree b a ->
|
|
LabelDoubleTree b a ->
|
|
Maybe (LabelDoubleTree b a)
|
|
leftRightCombine f f' t1 t2 =
|
|
f t1 t2
|
|
<|> checkdepth t1 t2
|
|
where
|
|
checkdepth t t'@(LDT x ls rs) = fromMaybe (checktop t t') $ do
|
|
(lab, t'') <- safeHead ls
|
|
tx <- checkdepth t t''
|
|
return $ Just $ LDT x ((lab, tx) : tail ls) rs
|
|
checktop t t' = f' t t'
|
|
|
|
joinItemsInList :: (a -> a -> Maybe a) -> [a] -> [a]
|
|
joinItemsInList f xs = snd $ h (xs, [])
|
|
where
|
|
h ([], zs) = ([], zs)
|
|
h (y : ys, []) = h (ys, [y])
|
|
h (y : ys, z : zs) = case f y z of
|
|
Nothing -> h (ys, y : z : zs)
|
|
Just w -> h (w : ys, zs)
|
|
|
|
-- this puts the first elements in the intmap at the end of the list
|
|
invLDT :: IM.IntMap Item -> [LabelDoubleTree ItemLink ComposedItem]
|
|
invLDT =
|
|
joinItemsInList tryAttachItems . IM.elems
|
|
. fmap (singleLDT . basePCI)
|
|
|
|
-- this assumes the creature inventory is well formed, specifically the
|
|
-- location ids
|
|
-- consider explicitly reseting the inventory ids (but this probably really
|
|
-- should be done upstream anyway in the actually creature inventory)
|
|
invRootMap :: IM.IntMap Item -> IM.IntMap (Maybe Int, DoubleTree Item)
|
|
invRootMap =
|
|
foldMap
|
|
(dtToIntMapWithRoot (^?! itLocation . ilInvID) . fmap (^. _1) . ldtToDT)
|
|
. invLDT
|
|
|
|
-- this assumes the creature inventory is well formed, specifically the
|
|
-- location ids
|
|
-- consider explicitly reseting the inventory ids (but this probably really
|
|
-- should be done upstream anyway in the actually creature inventory)
|
|
-- The first Int in the maybe is the root, the second the parent
|
|
invAdj :: IM.IntMap Item -> IM.IntMap (Maybe (Int, Int), [Int], [Int])
|
|
invAdj = IM.unions . map g . invLDT
|
|
where
|
|
g = dtToLRAdj getid . ldtToDT
|
|
getid (itm, _, _) =
|
|
fromMaybe
|
|
(error ("invAdj item " ++ show (_itID itm) ++ " location: " ++ show (itm ^? itLocation)))
|
|
$ itm ^? itLocation . ilInvID
|
|
|
|
-- returns an intmap with trees for (only!) root items, indexed by inventory position
|
|
invRootTrees :: IM.IntMap Item -> IM.IntMap (LabelDoubleTree ItemLink ComposedItem)
|
|
invRootTrees = IM.fromDistinctAscList . reverse . map getid . invLDT
|
|
where
|
|
getid ::
|
|
LabelDoubleTree ItemLink ComposedItem ->
|
|
(Int, LabelDoubleTree ItemLink ComposedItem)
|
|
getid t = (t ^?! ldtValue . _1 . itLocation . ilInvID, t)
|
|
|
|
-- returns an intmap with indents and locations for all items
|
|
allInvLocs :: IM.IntMap Item -> IM.IntMap (Int, LocationLDT ItemLink ComposedItem)
|
|
allInvLocs inv = foldMap (f . LocLDT TopLDT) (IM.elems (invRootTrees inv)) mempty
|
|
where
|
|
f t = cldtPropagateFold h h g 0 t id
|
|
h x _ _ _ = x + 1
|
|
g ::
|
|
Int ->
|
|
LocationLDT ItemLink ComposedItem ->
|
|
( IM.IntMap (Int, LocationLDT ItemLink ComposedItem) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink ComposedItem)
|
|
) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink ComposedItem) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink ComposedItem)
|
|
g x ldt =
|
|
(.)
|
|
( IM.insert
|
|
(ldt ^?! locLDT . ldtValue . _1 . itLocation . ilInvID)
|
|
(x, ldt)
|
|
)
|