347 lines
12 KiB
Haskell
347 lines
12 KiB
Haskell
module Dodge.Item.Grammar (
|
|
invLDT,
|
|
invAdj,
|
|
invRootMap,
|
|
invRootTrees,
|
|
baseCI,
|
|
allInvLocs,
|
|
) where
|
|
|
|
import Dodge.ItemUseCondition
|
|
import Dodge.Data.UseCondition
|
|
import Dodge.Item.MagAmmoType
|
|
import Dodge.Data.AmmoType
|
|
import Dodge.Item.AmmoSlots
|
|
import Dodge.Data.TriggerType
|
|
import Dodge.BaseTriggerType
|
|
import Dodge.Data.AimStance
|
|
import Dodge.Item.AimStance
|
|
import Control.Applicative
|
|
import qualified Data.IntMap.Strict as IM
|
|
import Data.Maybe
|
|
import qualified Data.Set as S
|
|
import Dodge.Data.ComposedItem
|
|
import Dodge.Data.DoubleTree
|
|
import Dodge.Data.Item
|
|
import Dodge.DoubleTree
|
|
import LensHelp
|
|
import ListHelp
|
|
|
|
tryAttachItems ::
|
|
LabelDoubleTree ItemLink CItem ->
|
|
LabelDoubleTree ItemLink CItem ->
|
|
Maybe (LabelDoubleTree ItemLink CItem)
|
|
tryAttachItems = leftRightCombine leftIsParentCombine rightIsParentCombine
|
|
|
|
useBreakL ::
|
|
[(ItemStructuralFunction, ItemLink)] ->
|
|
[(ItemStructuralFunction, ItemLink)] ->
|
|
LinkTest
|
|
useBreakL llist rlist = LTest ltest rtest
|
|
where
|
|
ltest ldt = do
|
|
let xs =
|
|
dropWhile
|
|
((\s -> not $ S.member s (structureToPotentialFunction ldt)) . fst)
|
|
llist
|
|
(sf, linktype) <- safeHead xs
|
|
return $ LUpdate linktype (set _3 (useBreakL (tail xs) rlist))
|
|
(_2 .~ sf)
|
|
rtest ldt = do
|
|
let xs =
|
|
dropWhile
|
|
((\s -> not $ S.member s (structureToPotentialFunction ldt)) . fst)
|
|
rlist
|
|
(sf, linktype) <- safeHead xs
|
|
return $ LUpdate linktype (set _3 (useBreakL llist (tail xs)))
|
|
(_2 .~ sf)
|
|
|
|
itemToBreakLists ::
|
|
Item ->
|
|
ItemStructuralFunction ->
|
|
([(ItemStructuralFunction, ItemLink)], [(ItemStructuralFunction, ItemLink)])
|
|
itemToBreakLists itm itmf = case (itm ^. itType, itmf) of
|
|
(HELD TORCH, _) -> (getAmmoLinks itm, [])
|
|
(ATTACH UNDERBARRELSLOT, _) -> ([(UnderBarrelPlatformSF, UnderBarrelPlatformLink)], [])
|
|
(_, HeldPlatformSF) ->
|
|
( getAmmoLinks itm
|
|
<> extraWeaponLinksBelow itm
|
|
, [(WeaponTargetingSF, WeaponTargetingLink), (WeaponScopeSF, WeaponScopeLink)]
|
|
<> getAutoSpringLinks itm
|
|
<> extraWeaponLinks itm
|
|
)
|
|
(_, UnderBarrelPlatformSF) ->
|
|
( getAmmoLinks itm,[])
|
|
(DETECTOR {}, _) ->
|
|
( getAmmoLinks itm
|
|
, [(ARHUDSF,SFLink ARHUDSF),(TriggerSF, TriggerLink),(MapperSF,SFLink MapperSF)]
|
|
)
|
|
(MAPPER, _) ->
|
|
( []
|
|
, [(ARHUDSF,SFLink ARHUDSF)]
|
|
)
|
|
(_, GadgetPlatformSF) ->
|
|
( getAmmoLinks itm
|
|
, [(TriggerSF, TriggerLink), (WeaponTargetingSF, WeaponTargetingLink), (WeaponScopeSF, WeaponScopeLink)]
|
|
)
|
|
(_, AmmoMagSF{}) -> fromMaybe ([], []) $ do
|
|
atype <- magAmmoType itm
|
|
let screenanddet = case atype of
|
|
LauncherAmmo ->
|
|
[ (RemoteScreenSF, RemoteScreenLink)
|
|
, (RemoteDetonatorSF, RemoteDetonatorLink)
|
|
]
|
|
_ -> []
|
|
return
|
|
( [ (AmmoModifierSF atype, AmmoModLink)
|
|
, (AmmoTargetingSF atype, AmmoTargetingLink)
|
|
, (AmmoPayloadSF atype, AmmoPayloadLink)
|
|
, (AmmoEffectSF atype, AmmoEffectLink)
|
|
, (SmokeReducerSF, SmokeReducerLink)
|
|
]
|
|
<> screenanddet
|
|
, []
|
|
)
|
|
(_, RemoteScreenSF) ->
|
|
( [(JoystickSF, JoystickLink)]
|
|
, []
|
|
)
|
|
(_, WeaponTargetingSF) -> (getAmmoLinks itm ++ [(ARHUDSF, SFLink ARHUDSF)], [])
|
|
(ATTACH BULLETSYNTH, _) ->
|
|
([(AmmoMagSF ElectricalAmmo, AmmoInLink 0 ElectricalAmmo)], [])
|
|
_ -> ([], [])
|
|
|
|
getAutoSpringLinks :: Item -> [(ItemStructuralFunction, ItemLink)]
|
|
getAutoSpringLinks itm = case itemTriggerType itm of
|
|
HammerTrigger -> [(MakeAutoSF, MakeAutoLink)]
|
|
_ -> []
|
|
|
|
extraWeaponLinks :: Item -> [(ItemStructuralFunction, ItemLink)]
|
|
extraWeaponLinks itm = case itm ^. itType of
|
|
HELD GLAUNCHER -> launcherlinks <> [(GrenadeHitEffectSF,GrenadeHitEffectLink)]
|
|
HELD RLAUNCHER -> launcherlinks
|
|
HELD RLAUNCHERX{} -> launcherlinks
|
|
_ -> []
|
|
where
|
|
launcherlinks = [(ProjectileStabiliserSF,ProjectileStabiliserLink)]
|
|
|
|
extraWeaponLinksBelow :: Item -> [(ItemStructuralFunction, ItemLink)]
|
|
extraWeaponLinksBelow itm
|
|
-- | Just TwoHandUnder <- itm ^? itUse . heldAim . aimStance
|
|
| TwoHandUnder <- itemBaseStance itm
|
|
= [(UnderBarrelSlotSF,UnderBarrelSlotLink)]
|
|
| otherwise = []
|
|
|
|
getAmmoLinks :: Item -> [(ItemStructuralFunction, ItemLink)]
|
|
getAmmoLinks itm =
|
|
map
|
|
(\(i, a) -> (AmmoMagSF a, AmmoInLink i a))
|
|
(IM.toList $ itemAmmoSlots itm)
|
|
|
|
itemToFunction :: Item -> ItemStructuralFunction
|
|
itemToFunction itm = case itm ^. itType of
|
|
DETECTOR {} -> GadgetPlatformSF
|
|
MAPPER -> MapperSF
|
|
ITEMSCAN -> ToggleSF
|
|
INTROSCAN {} -> IntroScanSF
|
|
HELD LASER -> WeaponTargetingSF
|
|
HELD{} -> case itUseCondition itm of
|
|
UseableWhenAimed -> HeldPlatformSF
|
|
--Just MustBeHeld -> UnloadedWeaponSF
|
|
_ -> GadgetPlatformSF
|
|
_
|
|
| Just amtype <- magAmmoType itm-- ^? itConsumables . magType
|
|
, Just _ <- itm ^? itLocation . ilEquipSite . _Just ->
|
|
AmmoMagSF amtype
|
|
AMMOMAG{} -> maybe NoSF AmmoMagSF $ magAmmoType itm -- ^? itConsumables . magType
|
|
ATTACH REMOTESCREEN -> RemoteScreenSF
|
|
ATTACH JOYSTICK -> JoystickSF
|
|
ATTACH REMOTEDETONATOR -> RemoteDetonatorSF
|
|
ATTACH SMOKEREDUCER -> SmokeReducerSF
|
|
ATTACH BULLETSYNTH -> AmmoModifierSF BulletAmmo
|
|
ATTACH ZOOMSCOPE -> WeaponScopeSF
|
|
ATTACH HOMINGMODULE -> AmmoTargetingSF LauncherAmmo
|
|
ARHUD -> ARHUDSF
|
|
ATTACH UNDERBARRELSLOT -> UnderBarrelSlotSF
|
|
BULLETMOD BulletModPayload{} -> AmmoPayloadSF BulletAmmo
|
|
BULLETMOD BulletModEffect{} -> AmmoEffectSF BulletAmmo
|
|
TARGETING{} -> WeaponTargetingSF
|
|
EQUIP WRIST_ECG -> TriggerSF
|
|
EQUIP{} -> EquipmentPlatformSF
|
|
ATTACH SHELLPAYLOAD{} -> AmmoPayloadSF LauncherAmmo
|
|
DROPPER{} -> GadgetPlatformSF
|
|
CLICKER{} -> GadgetPlatformSF
|
|
_ -> NoSF
|
|
|
|
structureToPotentialFunction ::
|
|
LabelDoubleTree ItemLink CItem ->
|
|
S.Set ItemStructuralFunction
|
|
structureToPotentialFunction ldt = case ldt ^. ldtValue . _1 . itType of
|
|
STICKYMOD -> S.singleton GrenadeHitEffectSF
|
|
ATTACH GIMBAL -> S.singleton ProjectileStabiliserSF
|
|
ATTACH GYROSCOPE -> S.singleton ProjectileStabiliserSF
|
|
HELD GLAUNCHER -> S.singleton UnderBarrelPlatformSF
|
|
_ -> S.singleton (ldt ^. ldtValue . _2)
|
|
|
|
baseCI :: Item -> CItem
|
|
baseCI itm = (itm, itemToFunction itm, itemBaseConnections itm)
|
|
|
|
itemBaseConnections :: Item -> LinkTest
|
|
itemBaseConnections itm = case _itType itm of
|
|
HELD LASER -> laserLinkTest itm
|
|
CRAFT SPRING -> springLinkTest
|
|
_ -> uncurry useBreakL $ itemToBreakLists itm (itemToFunction itm)
|
|
|
|
laserLinkTest :: Item -> LinkTest
|
|
laserLinkTest itm = LTest (llleft itm) (llright itm)
|
|
|
|
llleft :: Item -> LabelDoubleTree ItemLink CItem -> Maybe LinkUpdate
|
|
llleft itm =
|
|
_tryLeftLink
|
|
. uncurry useBreakL
|
|
$ itemToBreakLists itm WeaponTargetingSF
|
|
|
|
llright :: Item -> LabelDoubleTree ItemLink CItem -> Maybe LinkUpdate
|
|
llright itm pci = case pci ^. ldtValue . _1 . itType of
|
|
CRAFT TRANSFORMER -> Just (toLasgunUpdate itm)
|
|
_ -> _tryRightLink (uncurry useBreakL $ itemToBreakLists itm WeaponTargetingSF) pci
|
|
|
|
toLasgunUpdate :: Item -> LinkUpdate
|
|
toLasgunUpdate itm =
|
|
LUpdate
|
|
FunctionChangeLink
|
|
(\(par, _, _) -> (par, HeldPlatformSF, uncurry useBreakL $ itemToBreakLists itm HeldPlatformSF))
|
|
(\(chi, _, up) -> (chi, FunctionChangeSF, up))
|
|
|
|
springLinkTest :: LinkTest
|
|
springLinkTest = LTest (const Nothing) $
|
|
\ci -> case ci ^. ldtValue . _1 . itType of
|
|
CRAFT HARDWARE ->
|
|
Just
|
|
( LUpdate
|
|
(FunctionChangeLink)
|
|
(\(par, _, up) -> (par, MakeAutoSF, up))
|
|
(\(chi, _, up) -> (chi, FunctionChangeSF, up))
|
|
)
|
|
_ -> Nothing
|
|
|
|
--itemLinkTestLeft :: Item -> PartiallyCItem -> 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 CItem ItemLink
|
|
leftIsParentCombine' ltree rtree = Nothing
|
|
|
|
leftIsParentCombine :: LDTComb CItem ItemLink
|
|
leftIsParentCombine ltree rtree = do
|
|
lu <- (ltree ^. ldtValue . _3 . tryRightLink) rtree --(rtree ^. ldtValue)
|
|
return $
|
|
ltree & ldtValue %~ (lu ^. luParentUpdate)
|
|
& ldtRight %~ (++ [(lu ^. luLinkType, rtree & ldtValue %~ (lu ^. luChildUpdate))])
|
|
|
|
rightIsParentCombine :: LDTComb CItem ItemLink
|
|
rightIsParentCombine ltree rtree = do
|
|
let l = leftChildList rtree
|
|
xs = dropWhile ((\s -> not $ S.member s (structureToPotentialFunction ltree)) . fst) l
|
|
(sf,linktype) <- safeHead xs
|
|
return $
|
|
rtree & ldtLeft .:~ (linktype, ltree & ldtValue . _2 .~ sf)
|
|
|
|
leftChildList :: LabelDoubleTree ItemLink CItem -> [(ItemStructuralFunction, ItemLink)]
|
|
leftChildList t = foldl' f l (reverse $ t ^.. ldtLeft . each . _1)
|
|
where
|
|
l = fst $ itemToBreakLists (t ^. ldtValue . _1) (t ^. ldtValue . _2)
|
|
f x y = tail $ dropWhile ((/=y) . snd) x
|
|
|
|
rightIsParentCombine' :: LDTComb CItem ItemLink
|
|
rightIsParentCombine' ltree rtree = do
|
|
lu <- (rtree ^. ldtValue . _3 . tryLeftLink) ltree -- (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 CItem]
|
|
invLDT =
|
|
joinItemsInList tryAttachItems . IM.elems
|
|
. fmap (singleLDT . baseCI)
|
|
|
|
-- 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 CItem)
|
|
invRootTrees = IM.fromDistinctAscList . reverse . map getid . invLDT
|
|
where
|
|
getid ::
|
|
LabelDoubleTree ItemLink CItem ->
|
|
(Int, LabelDoubleTree ItemLink CItem)
|
|
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 CItem)
|
|
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 CItem ->
|
|
( IM.IntMap (Int, LocationLDT ItemLink CItem) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink CItem)
|
|
) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink CItem) ->
|
|
IM.IntMap (Int, LocationLDT ItemLink CItem)
|
|
g x ldt =
|
|
(.)
|
|
( IM.insert
|
|
(ldt ^?! locLDT . ldtValue . _1 . itLocation . ilInvID)
|
|
(x, ldt)
|
|
)
|