Files
loop/src/Dodge/Item/Weapon/Booster.hs
T

148 lines
4.3 KiB
Haskell

module Dodge.Item.Weapon.Booster
( boosterGun
) where
import Dodge.Data
import Dodge.Base
import Dodge.Zone
import Dodge.Base.Collide
import Dodge.Default.Weapon
import Dodge.Item.Data
import Geometry
import qualified IntMapHelp as IM
import Dodge.Picture.Layer
import Picture
import Dodge.Item.Attachment.Data
import ShapePicture
import Shape
import Data.Maybe
import Control.Lens
{- | Move a creature towards the mouse position, with shockwave -}
boostPoint
:: Float -- ^ boost amount
-> Creature
-> World
-> Either Point2 Point2
boostPoint x cr w = case mayp2 of
Nothing -> Right p1
Just p2 -> Left $ mvPointTowardAtSpeed r cpos $ fst p2
where
cpos = _crPos cr
r = 1.5 * _crRad cr
p1 = cpos +.+ x *.* safeNormalizeV (mouseWorldPos w -.- cpos)
mayp2 = reflectPointWalls cpos p1 $ wallsAlongLine cpos p1 w
boostSelfL
:: Float -- ^ boost amount
-> Creature
-> Int -- ^ item inventory id
-> World
-> World
boostSelfL x cr invid w = case boostPoint x cr w of
Left p -> crEff p (wpLoadedAmmo .~ 0)
Right p -> crEff p (wpLoadedAmmo -~ 1)
where
cid = _crID cr
cpos = _crPos cr
r = _crRad cr
pid = fromMaybe (IM.newKey $ _props w)
(cr ^? crInv . ix invid . itAttachment . itInt)
crEff p ammoEff = addBoostShockwave pid p (r *.* normalizeV (p -.- cpos)) w
& creatures . ix cid %~
(crPos .~ p)
. (crInv . ix invid %~
ammoEff
. (itEffect . itEffectCounter .~ 1)
. (itAttachment .~ ItInt pid)
)
boostSelf
:: Float -- ^ boost amount
-> Creature
-> World
-> World
boostSelf x cr = boostSelfL x cr (_crInvSel cr)
addBoostShockwave
:: Int
-> Point2
-> Point2
-> World
-> World
addBoostShockwave pjid p v w = w & props %~
IM.insertWith f pjid thePJ
where
thePJ = LinearShockwave
{ _prDraw = drawBoostShockwave
, _pjPos = p
, _pjID = pjid
, _pjUpdate = updateLinearShockwave
, _pjPoints = [(p,v)]
, _pjTimer = maxT
}
f newVal oldVal = newVal & pjPoints %~ (++ _pjPoints oldVal)
updateLinearShockwave :: Prop -> World -> World
updateLinearShockwave pj w
| t < 1 = w & props %~ IM.delete pjid
| otherwise = w & props . ix (_pjID pj) . pjTimer -~ 1
where
pjid = _pjID pj
t = _pjTimer pj
drawBoostShockwave :: Prop -> SPic
drawBoostShockwave pj = (,) mempty $ setLayer 1 $ onLayer UPtLayer $ pictures $
theArc ++
[ lineCol $ zip (reverse lps) $ map (`withAlpha` white) [0,0.05..]
, lineCol $ zip (reverse rps) $ map (`withAlpha` white) [0,0.05..]
]
where
-- drawing half a circle here is not perfect, a slightly smaller arc would fit
-- better, but this depends upon the angle formed by the following lines, which
-- is not fixed (it varies with speed and angle of last turn)
theArc = maybeToList $ do
(hp,hv) <- safeHead pvs
r <- safeHead xs
return $ color (snd $ last lpairs) $ uncurryV translate hp
$ arc (argV hv - pi/2) (argV hv + pi/2) $ r * magV hv
cols = map (`withAlpha` white) [0,0.05..]
lpairs = zip (reverse lps) cols
pvs = _pjPoints pj
t = _pjTimer pj
xs = take t $ drop (20 - t) [1,1.2..]
lps = zipWith f pvs xs
rps = zipWith g pvs xs
f (p,v) x = p +.+ x *.* vNormal v
g (p,v) x = p -.- x *.* vNormal v
maxT :: Int
maxT = 20
boosterGun :: Item
boosterGun = defaultGun
{ _itName = "BOOSTER"
, _itIdentity = Blinker
, _wpMaxAmmo = 100
, _wpLoadedAmmo = 100
, _wpReloadTime = 20
, _wpReloadState = 0
, _itUseRate = 0
, _itUseTime = 0
, _itUse = \_ -> boostSelf 10
, _itLeftClickUse = Just $ boostSelfL 10
, _wpSpread = 0.05
, _wpRange = 20
, _itFloorPict = \_ -> (,) emptySH $ onLayer FlItLayer $ polygon $ map toV2 [(-2,-2),(-2,2),(2,2),(2,0),(0,0),(0,-2)]
, _itAimingSpeed = 1
, _itAimingRange = 0
, _itEffect = resetAttachmentID
}
resetAttachmentID :: ItEffect
resetAttachmentID = ItInvEffect f 0
where
f iteff cr invid w
| _itEffectCounter iteff < 0 = w & pointToIt . itAttachment .~ NoItAttachment
| otherwise = w & pointToIt . itEffect . itEffectCounter -~ 1
where
pointToIt = creatures . ix (_crID cr) . crInv . ix invid