320 lines
11 KiB
Haskell
320 lines
11 KiB
Haskell
module Dodge.Item.Weapon.Grenade
|
|
where
|
|
import Dodge.Data
|
|
import Dodge.Picture.Layer
|
|
import Dodge.WorldEvent.Explosion
|
|
import Dodge.Item.Weapon.TriggerType
|
|
import Dodge.Item.Weapon.Remote
|
|
import Dodge.Default
|
|
import Dodge.Default.Weapon
|
|
import Dodge.Base
|
|
import Dodge.Zone
|
|
import Dodge.SoundLogic
|
|
import Dodge.Item.Draw
|
|
import Dodge.Item.Weapon.InventoryDisplay
|
|
import Dodge.Item.Weapon.ExtraEffect
|
|
import Dodge.Item.Attachment
|
|
import Picture
|
|
import Geometry
|
|
import ShapePicture
|
|
import Shape
|
|
import qualified IntMapHelp as IM
|
|
|
|
import Data.Maybe
|
|
import Control.Lens
|
|
|
|
grenade :: Item
|
|
grenade = Throwable
|
|
{ _itName = "GRENADE " ++ show fuseTime
|
|
, _itDimension = defaultItemDimension
|
|
, _itCurseStatus = Uncursed
|
|
, _itIdentity = Grenade
|
|
, _itMaxStack = 8
|
|
, _itAmount = 1
|
|
, _itFloorPict = \_ -> (,) emptySH $ onLayer FlItLayer $ polygon $ map toV2 [(-3,-3),(-3,3),(3,3),(3,-3)]
|
|
, _twMaxRange = 150
|
|
, _twAccuracy = 30
|
|
, _itUse = \_ -> throwGrenade makeExplosionAt
|
|
, _itUseModifiers =
|
|
[ useTimeCheckI
|
|
]
|
|
, _itAimingSpeed = 1
|
|
, _itAimingRange = 0
|
|
, _itZoom = defaultItZoom
|
|
, _itAimZoom = defaultItZoom {_itZoomMax = f fuseTime, _itZoomMin = f fuseTime}
|
|
, _itEquipPict = pictureWeaponOnAim' $ \_ -> grenadePic fuseTime
|
|
, _itID = Nothing
|
|
, _itUseRate = 25
|
|
, _itUseTime = 0
|
|
, _itAttachment = ItFuse fuseTime
|
|
, _itInvColor = white
|
|
, _itInvDisplay = basicWeaponDisplay
|
|
, _itEffect = wpRecock
|
|
, _itHammer = HammerUp
|
|
, _itScroll = changeFuse
|
|
, _itAimStance = OneHand
|
|
}
|
|
where
|
|
fuseTime = 50
|
|
f x = 50 / fromIntegral x
|
|
|
|
moveGrenade :: Prop -> World -> World
|
|
moveGrenade pj w
|
|
| _pjTimer pj <= 0 = w
|
|
& props %~ IM.delete pID
|
|
& _pjPayload pj (_pjPos (_props w IM.! pID))
|
|
| otherwise = case collideCircWalls oldPos newPos 4 $ wallsNearPoint newPos w of
|
|
Nothing -> w & props . ix pID %~ normalUpdate
|
|
Just (p,v) -> w
|
|
& soundStart (Tap 0) p tapQuietS Nothing
|
|
& props . ix pID %~ ( ( pjPos .~ p ) . ( pjTimer -~ 1 ) . (pjVel .~ v) )
|
|
where
|
|
pID = _pjID pj
|
|
normalUpdate = (pjTimer -~ 1)
|
|
. (pjZ %~ (max 0 . (+ _pjVelZ pj)))
|
|
. (pjVelZ -~ 0.1)
|
|
. ( pjPos .~ newPos )
|
|
oldPos = _pjPos pj
|
|
newPos = _pjVel pj +.+ oldPos
|
|
|
|
grenadePic :: Int -> SPic
|
|
grenadePic time =
|
|
( colorSH (dark $ dark green) $ upperPrismPolyHalf 5 $ polyCirc 3 5
|
|
, pictures
|
|
[ color green $ arc (degToRad $ (179 * fromIntegral time / 50) - 180 )
|
|
(degToRad $ 180 - (179 * fromIntegral time / 50) )
|
|
5
|
|
]
|
|
)
|
|
|
|
grenadeDraw :: Float -> Prop -> SPic
|
|
grenadeDraw dir prop = translateSPz z $ uncurryV translateSPf p $ rotateSP dir $ grenadePic time
|
|
where
|
|
p = _pjPos prop
|
|
time = _pjTimer prop
|
|
z = _pjZ prop
|
|
|
|
throwGrenade
|
|
:: (Point2 -> World -> World) -- ^ Payload
|
|
-> Creature
|
|
-> World
|
|
-> World
|
|
throwGrenade thePayload cr w = setWp $ removePict $ over props addG w
|
|
where
|
|
n = _crID cr
|
|
addG = IM.insert i $ Bomb
|
|
{ _pjPos = p
|
|
, _pjZ = 10
|
|
, _pjVelZ = 2
|
|
, _pjVel = v
|
|
, _prDraw = grenadeDraw dir
|
|
, _pjID = i
|
|
, _pjUpdate = moveGrenade
|
|
, _pjPayload = thePayload
|
|
, _pjTimer = fuseTime
|
|
}
|
|
j = _crInvSel cr
|
|
removePict = set (creatures . ix n . crInv . ix j . itEquipPict) $ \ _ _ -> (,) emptySH blank
|
|
i = newProjectileKey w
|
|
v' = 1 / (fromIntegral fuseTime * _cameraZoom w) *.* rotateV (_cameraRot w) ( _mousePos w)
|
|
v | magV v' > 6 = 6 *.* normalizeV v'
|
|
| otherwise = v'
|
|
p' = _crPos cr +.+ rotateV (_crDir cr) (V2 (_crRad cr) 0)
|
|
p | circOnSomeWall p' 4 w = _crPos cr +.+ rotateV (_crDir cr) (V2 (_crRad cr-4) 0)
|
|
| otherwise = p'
|
|
dir = argV v
|
|
setWp :: World -> World
|
|
setWp w' = w' & creatures . ix n . crInv . ix j . itEffect .~ throwArmReset 20
|
|
fuseTime = _itFuseTime $ _itAttachment $ _crInv cr IM.! j
|
|
|
|
throwArmReset :: Int -> ItEffect
|
|
throwArmReset x = ItInvEffect {_itInvEffect = f ,_itEffectCounter = x }
|
|
where
|
|
f _ cr i = creatures . ix (_crID cr) . crInv %~ IM.adjust counterDown i
|
|
counterDown it
|
|
| _itEffectCounter (_itEffect it) == 0 = it
|
|
& itHammer .~ HammerUp
|
|
& itEquipPict .~ pictureWeaponOnAim' (\_ -> grenadePic 50)
|
|
| otherwise = it & itEffect . itEffectCounter -~ 1
|
|
|
|
--flameGrenade :: Item
|
|
--flameGrenade = grenade {
|
|
-- _itName = "FLMGREN " ++ show fuseTime
|
|
-- , _itUse = \_ -> throwGrenade makeFlameExplosionAt
|
|
-- }
|
|
-- where
|
|
-- fuseTime = 50 :: Int
|
|
--
|
|
--teslaGrenade :: Item
|
|
--teslaGrenade = grenade {
|
|
-- _itName = "TLSGREN " ++ show fuseTime
|
|
-- , _itUse = \_ -> throwGrenade makeTeslaExplosionAt
|
|
-- }
|
|
-- where
|
|
-- fuseTime = 50 :: Int
|
|
--
|
|
--retireRemoteBomb :: Int -> Int -> Int -> World -> World
|
|
--retireRemoteBomb itid 0 pjid w = w
|
|
-- & pointToItem (_itemPositions w IM.! itid) %~
|
|
-- ( (itAttachment . scopePos .~ V2 0 0)
|
|
-- . (itZoom .~ defaultItZoom)
|
|
-- . (itUse .~ const throwRemoteBomb)
|
|
-- )
|
|
-- & props %~ IM.delete pjid
|
|
--retireRemoteBomb itid t pjid w = setScope w
|
|
-- & props . ix pjid . pjUpdate .~ (\_ -> retireRemoteBomb itid (t-1) pjid)
|
|
-- where
|
|
-- setScope w' = case _itemPositions w' IM.! itid of
|
|
-- InInv cid invid -> w'
|
|
-- & creatures . ix cid . crInv . ix invid . itAttachment
|
|
-- . scopePos .~ (pos -.- _crPos (_creatures w' IM.! cid))
|
|
-- _ -> w'
|
|
-- pos = fromMaybe (V2 0 0) $ w ^? props . ix pjid . pjPos
|
|
|
|
moveRemoteBomb :: Int -> Int -> Int -> World -> World
|
|
moveRemoteBomb itid time pID w
|
|
| time < -4 = updatePicture
|
|
$ set (props .ix pID.pjUpdate) (\_ -> moveRemoteBomb itid (f time) pID)
|
|
w
|
|
| time < 2 = case hitWl of
|
|
Just (p,_) -> soundStart (Tap 0) p tapQuietS Nothing $ halfV updatedWorld
|
|
_ -> halfV updatedWorld
|
|
| otherwise = case hitWl of
|
|
Just (p,_) -> soundStart (Tap 0) p tapQuietS Nothing updatedWorld
|
|
_ -> updatedWorld
|
|
where
|
|
updatedWorld
|
|
= updateV $ set (props . ix pID . pjPos) finalPos
|
|
$ updatePicture
|
|
$ set (props .ix pID.pjUpdate) (\_ -> moveRemoteBomb itid (time-1) pID)
|
|
w
|
|
pj = _props w IM.! pID
|
|
oldPos = _pjPos pj
|
|
newPos = _pjVel pj +.+ oldPos
|
|
-- this is hacky, should use a version of collidePointWalls' that collides
|
|
-- circles and walls
|
|
invShift x = x -.- 5 *.* normalizeV (_pjVel pj)
|
|
hitWl = collideCircWalls oldPos newPos 4 $ wallsNearPoint newPos w
|
|
finalPos = maybe newPos (invShift . fst) hitWl
|
|
setV v = set (props . ix pID . pjVel) v
|
|
updateV = maybe id (setV . snd) hitWl
|
|
halfV = props . ix pID . pjVel %~ (0.5 *.*)
|
|
f x | x < -369 = -10
|
|
| otherwise = x - 1
|
|
updatePicture =
|
|
set (props . ix pID . prDraw)
|
|
(\_ -> (,) mempty $ onLayer PtLayer $ uncurryV translate newPos $ remoteBombPic time)
|
|
|
|
|
|
setRemoteBombScope :: Int -> Prop -> World -> World
|
|
setRemoteBombScope itid pj w' = case _itemPositions w' IM.! itid of
|
|
InInv cid invid
|
|
-> w' & creatures . ix cid . crInv . ix invid . itAttachment
|
|
. scopePos .~ (_pjPos pj -.- _crPos (_creatures w' IM.! cid))
|
|
& creatures . ix cid . crInv . ix invid . itAimZoom
|
|
.~ (defaultItZoom {_itZoomMax = 0.5, _itZoomMin = 0.5})
|
|
_ -> w'
|
|
|
|
defaultThrowable :: Item
|
|
defaultThrowable = grenade
|
|
remoteBomb :: Item
|
|
remoteBomb = defaultThrowable
|
|
{ _itName = "REMOTEBOMB"
|
|
, _itIdentity = RemoteBomb
|
|
, _itMaxStack = 1
|
|
, _itAmount = 1
|
|
, _itFloorPict = \_ -> (,) emptySH $ onLayer FlItLayer $ polygon $ map toV2
|
|
[(-3,-3),(-3,3),(3,3),(3,-3)]
|
|
, _twMaxRange = 150
|
|
, _twAccuracy = 30
|
|
, _itUse = const throwRemoteBomb
|
|
, _itUseModifiers =
|
|
[ hammerCheckI
|
|
]
|
|
, _itAttachment = ItScope (V2 0 0) 0 1 True
|
|
, _itEquipPict = pictureWeaponOnAim' $ \_ -> (,) emptySH remoteBombUnarmedPic
|
|
}
|
|
|
|
|
|
throwRemoteBomb :: Creature -> World -> World
|
|
throwRemoteBomb cr w = setLocation
|
|
$ removePict
|
|
$ resetFire
|
|
$ resetName
|
|
$ over props addG w
|
|
where
|
|
cid = _crID cr
|
|
addG = IM.insert i $ Projectile
|
|
{ _pjPos = p
|
|
, _pjStartPos = p
|
|
, _pjVel = v
|
|
, _prDraw = const mempty
|
|
, _pjID = i
|
|
, _pjUpdate = \_ -> moveRemoteBomb itid 50 i
|
|
}
|
|
i = newProjectileKey w
|
|
v' = 0.02 / _cameraZoom w *.* rotateV (_cameraRot w) ( _mousePos w)
|
|
v | magV v' > 6 = 6 *.* normalizeV v'
|
|
| otherwise = v'
|
|
j = _crInvSel cr
|
|
resetName = set (creatures . ix cid . crInv . ix j . itName) "REMOTE"
|
|
removePict = set (creatures . ix cid . crInv . ix j . itEquipPict) $ \ _ _ -> emptyBlank
|
|
resetFire = set (creatures . ix cid . crInv . ix j . itUse)
|
|
$ \_ -> explodeRemoteBomb itid i
|
|
p' = _crPos cr +.+ rotateV (_crDir cr) (V2 (_crRad cr) 0)
|
|
p | circOnSomeWall p' 4 w = _crPos cr +.+ rotateV (_crDir cr) (V2 (_crRad cr-4) 0)
|
|
| otherwise = p'
|
|
maybeitid = w ^? creatures . ix cid . crInv . ix j . itID . _Just
|
|
setLocation :: World -> World
|
|
setLocation w' = case maybeitid of
|
|
Nothing -> w' & creatures . ix cid . crInv . ix j . itID ?~ newitid
|
|
& itemPositions %~ IM.insert newitid (InInv cid j)
|
|
_ -> w'
|
|
newitid = IM.newKey $ _itemPositions w
|
|
itid = fromMaybe newitid maybeitid
|
|
|
|
explodeRemoteBomb :: Int -> Int -> Creature -> World -> World
|
|
explodeRemoteBomb itid pjid cr w
|
|
= set (props . ix pjid . pjUpdate) (\_ -> retireRemoteBomb itid 30 pjid)
|
|
-- $ set (props . ix pjid . pjDraw) (\_ -> blank)
|
|
$ set (creatures . ix cid . crInv . ix j . itUse) (\_ -> const id)
|
|
$ resetName
|
|
$ resetPict
|
|
-- $ resetScope
|
|
$ makeExplosionAt (_pjPos (_props w IM.! pjid)) w
|
|
-- - $ makeShrapnelBombAt (_pjPos (_props w IM.! pjid)) w
|
|
where
|
|
cid = _crID cr
|
|
resetName = set (creatures . ix cid . crInv . ix j . itName) "REMOTEBOMB"
|
|
resetPict = set (creatures . ix cid . crInv . ix j . itEquipPict )
|
|
(pictureWeaponOnAim' $ \_ -> (,) emptySH remoteBombUnarmedPic)
|
|
-- resetScope = creatures . ix cid . crInv . ix j . itScope . _Just . scopePos .~ (0,0)
|
|
j = _crInvSel $ _creatures w IM.! cid
|
|
remoteBombPic
|
|
:: Int -- ^ time
|
|
-> Picture
|
|
remoteBombPic _ = pictures
|
|
[ color (dark $ dark orange) $ circleSolid 5
|
|
]
|
|
|
|
remoteBombUnarmedPic :: Picture
|
|
remoteBombUnarmedPic = color (dark $ dark orange) $ circleSolid 5
|
|
|
|
retireRemoteBomb :: Int -> Int -> Int -> World -> World
|
|
retireRemoteBomb itid 0 pjid w = w
|
|
& pointToItem (_itemPositions w IM.! itid) %~
|
|
( (itAttachment . scopePos .~ V2 0 0)
|
|
. (itZoom .~ defaultItZoom)
|
|
. (itUse .~ const throwRemoteBomb)
|
|
)
|
|
& props %~ IM.delete pjid
|
|
retireRemoteBomb itid t pjid w = setScope w
|
|
& props . ix pjid . pjUpdate .~ (\_ -> retireRemoteBomb itid (t-1) pjid)
|
|
where
|
|
setScope w' = case _itemPositions w' IM.! itid of
|
|
InInv cid invid -> w'
|
|
& creatures . ix cid . crInv . ix invid . itAttachment
|
|
. scopePos .~ (pos -.- _crPos (_creatures w' IM.! cid))
|
|
_ -> w'
|
|
pos = fromMaybe (V2 0 0) $ w ^? props . ix pjid . pjPos
|