Allow for different item drops on creature death

This commit is contained in:
2021-04-25 02:16:31 +02:00
parent 94ff3d6593
commit 30736997c3
19 changed files with 336 additions and 229 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.Path import Dodge.Path
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.CreatureAction import Dodge.Creature.Action
import Dodge.RandomHelp import Dodge.RandomHelp
import Dodge.WorldEvent import Dodge.WorldEvent
+2 -2
View File
@@ -110,7 +110,7 @@ launcherCrit :: Creature
launcherCrit = defaultCreature launcherCrit = defaultCreature
{ _crPict = enemyPict red { _crPict = enemyPict red
, _crUpdate = stateUpdate (launcherAI 150 200) , _crUpdate = stateUpdate (launcherAI 150 200)
, _crInv = IM.fromList [(0,launcher),(1,medkit 100)] , _crInv = IM.fromList [(0,launcher)]
, _crInvSel = 0 , _crInvSel = 0
, _crRad = 10 , _crRad = 10
, _crState = defaultState {_goals = [[Init]]} , _crState = defaultState {_goals = [[Init]]}
@@ -261,7 +261,7 @@ Items you start with.
-} -}
startInventory = IM.fromList (zip [0..20] startInventory = IM.fromList (zip [0..20]
( (
[launcher [pistol
--,blinkGun --,blinkGun
--,spawnGun lamp --,spawnGun lamp
--,poisonSprayer --,poisonSprayer
@@ -1,12 +1,13 @@
{- Actions performed by creatures within the world
-}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
module Dodge.CreatureAction module Dodge.Creature.Action
( module Dodge.CreatureAction ( module Dodge.Creature.Action
, useItem , useItem
, tryUseItem , tryUseItem
) )
where where
-- imports {{{ import Dodge.Creature.Action.UseItem
import Dodge.CreatureAction.UseItem
import Dodge.WorldEvent.Shockwave import Dodge.WorldEvent.Shockwave
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
@@ -14,22 +15,17 @@ import Dodge.SoundLogic
import Dodge.WorldEvent import Dodge.WorldEvent
import Dodge.Inventory import Dodge.Inventory
import Dodge.LightSources import Dodge.LightSources
import Geometry import Geometry
import Picture import Picture
import Control.Lens import Control.Lens
import Control.Monad import Control.Monad
import Control.Applicative import Control.Applicative
import Data.Maybe import Data.Maybe
import Data.List import Data.List
import System.Random import System.Random
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M import qualified Data.Map as M
-- }}}
moveForwardSpeed :: Float -> Int -> World -> World moveForwardSpeed :: Float -> Int -> World -> World
moveForwardSpeed x n w = over (creatures . ix n . crPos) (+.+ p) w moveForwardSpeed x n w = over (creatures . ix n . crPos) (+.+ p) w
@@ -216,11 +212,6 @@ crAutoReload cr = case cr ^? crInv . ix (_crInvSel cr) . wpLoadedAmmo of
where reloadT = cr ^? crInv . ix (_crInvSel cr) . wpReloadTime where reloadT = cr ^? crInv . ix (_crInvSel cr) . wpReloadTime
maxA = cr ^? crInv . ix (_crInvSel cr) . wpMaxAmmo maxA = cr ^? crInv . ix (_crInvSel cr) . wpMaxAmmo
createItemAt :: Point2 -> FloorItem -> World -> World
createItemAt p it w = over floorItems (IM.insert i (set flItPos p
$ set flItID i it)) w
where i = newKey (_floorItems w)
blinkAction :: Int -> World -> World blinkAction :: Int -> World -> World
blinkAction n w = soundOnce teleSound $ set (creatures . ix n . crPos) p3 blinkAction n w = soundOnce teleSound $ set (creatures . ix n . crPos) p3
$ blinkShockwave n p3 $ blinkShockwave n p3
@@ -254,10 +245,13 @@ reverseDir n = over (creatures . ix n . crDir) (+ pi)
turnBy :: Float -> Int -> World -> World turnBy :: Float -> Int -> World -> World
turnBy a n = over (creatures . ix n . crDir) (+ a) turnBy a n = over (creatures . ix n . crDir) (+ a)
dropItem :: World -> World {-
dropItem w = case yourItem w of Get your creature to drop the item under the cursor.
-}
youDropItem :: World -> World
youDropItem w = case yourItem w of
NoItem -> w NoItem -> w
it -> rmInvItem (_yourID w) $ over floorItems (IM.insert flid theflit) it -> rmSelectedInvItem (_yourID w) $ over floorItems (IM.insert flid theflit)
$ updateLocation $ updateLocation
$ soundOnce putDownSound $ soundOnce putDownSound
$ set randGen g w $ set randGen g w
@@ -272,6 +266,34 @@ dropItem w = case yourItem w of
,_flItRot = rot ,_flItRot = rot
,_flItID = flid} ,_flItID = flid}
{- Drop an item silently. -}
dropItem
:: Int -- ^ Creature id
-> Int -- ^ Inventory position
-> World
-> World
dropItem cid i w = case _crInv cr IM.! i of
NoItem -> w
it -> rmInvItem cid i
. over floorItems (IM.insert flid theflit)
. updateLocation
$ set randGen g w
where
(rot, g) = randomR (-pi,pi) $ _randGen w
offset = _crRad cr *.* unitVectorAtAngle rot
updateLocation w = case it ^? itID of
Just (Just i) -> w & itemPositions . ix i .~ OnFloor flid
_ -> w
flid = newKey $ _floorItems w
theflit = FlIt
{_flIt = set itAmount 1 it
,_flItPos = offset +.+ _crPos cr
,_flItRot = rot
,_flItID = flid
}
where
cr = _creatures w IM.! cid
pickUpItem' :: FloorItem -> World -> World pickUpItem' :: FloorItem -> World -> World
pickUpItem' flit w = case maybeInvSlot of pickUpItem' flit w = case maybeInvSlot of
Nothing -> w Nothing -> w
@@ -1,4 +1,4 @@
module Dodge.CreatureAction.UseItem module Dodge.Creature.Action.UseItem
where where
import Dodge.Data import Dodge.Data
@@ -29,7 +29,7 @@ equippedItemEffect n w = itemEffect n it w
it = _crInv c IM.! _crInvSel c it = _crInv c IM.! _crInvSel c
itemEffect :: Int -> Item -> World -> World itemEffect :: Int -> Item -> World -> World
itemEffect n (Consumable {_cnEffect=eff }) w = fromMaybe w $ fmap (rmInvItem n) $ eff n w itemEffect n (Consumable {_cnEffect=eff }) w = fromMaybe w $ fmap (rmSelectedInvItem n) $ eff n w
itemEffect n (Weapon {_wpFire=eff}) w = eff n w itemEffect n (Weapon {_wpFire=eff}) w = eff n w
itemEffect n (Throwable {_twFire = eff}) w = eff n w itemEffect n (Throwable {_twFire = eff}) w = eff n w
itemEffect _ _ w = w itemEffect _ _ w = w
+5
View File
@@ -0,0 +1,5 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.Data
where
import Control.Lens
+64 -28
View File
@@ -5,7 +5,7 @@ import Dodge.SoundLogic
import Dodge.RandomHelp import Dodge.RandomHelp
import Dodge.WorldEvent import Dodge.WorldEvent
import Dodge.WallCreatureCollisions import Dodge.WallCreatureCollisions
import Dodge.CreatureAction import Dodge.Creature.Action
import Geometry import Geometry
import Picture import Picture
@@ -13,7 +13,7 @@ import Data.List
import Data.Char import Data.Char
import Data.Maybe import Data.Maybe
import Data.Function import Data.Function
import Data.Graph.Inductive.Graph --import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.Query.SP import Data.Graph.Inductive.Query.SP
import Codec.BMP import Codec.BMP
@@ -37,32 +37,73 @@ type CRUpdate = World -> (World -> World,StdGen) -> Creature -> ((World -> World
-- the whole of this update cycle could do with a rethink, it is becoming -- the whole of this update cycle could do with a rethink, it is becoming
-- convoluted -- convoluted
stateUpdate :: CRUpdate -> CRUpdate stateUpdate :: CRUpdate -> CRUpdate
stateUpdate u w (f,g) cr = let (cr', g'') = updateMovement g cr stateUpdate u w (f,g) cr =
in case u w (f,g'') cr' of let (cr', g'') = updateMovement g cr
((f',g') , maybeCr) -> ( (invSideEff cr . movementSideEff cr . dropifdead . f' in case u w (f,g'') cr' of
((f',g') , maybeCr) -> ( (invSideEff cr . movementSideEff cr . deathEff . f'
, g') , g')
, fmap (updateReloadCounter . reducePastDamage . doDamage) , fmap (updateReloadCounter . reducePastDamage . doDamage)
$ crOrCorpse =<< maybeCr $ crOrCorpse =<< maybeCr
) )
where where
crOrCorpse cr | cr ^. crHP > 0 = Just cr crOrCorpse cr | cr ^. crHP > 0 = Just cr
| otherwise = Nothing | otherwise = Nothing
dropifdead | cr ^.crHP > 0 = id deathEff | cr ^.crHP > 0 = id
| otherwise = stopSoundFrom (CrWeaponSound (_crID cr)) | otherwise = stopSoundFrom (CrWeaponSound (_crID cr))
. over decorations addCorpse . over decorations addCorpse
. insertIt . dropByState cr
crBeforeDeath = colCrWall w $ cr crBeforeDeath = colCrWall w $ cr
addCorpse = insertNewKey $ uncurry translate (_crOldPos cr) addCorpse = insertNewKey $ uncurry translate (_crOldPos cr)
$ rotate (_crDir cr) $ rotate (_crDir cr)
(_crCorpse cr) (_crCorpse cr)
maybeIt = evalState (maybeTakeOne $ IM.elems (_crInv cr)) (_randGen w) -- maybeIt = evalState (maybeTakeOne $ IM.elems (_crInv cr)) (_randGen w)
insertIt = case maybeIt of -- insertIt = case maybeIt of
-- Just it -> createItemAt (offset +.+ _crPos crBeforeDeath) -- Just it -> createItemAt (offset +.+ _crOldPos cr)
Just it -> createItemAt (offset +.+ _crOldPos cr) -- (FlIt {_flIt=it,_flItPos=(0,0),_flItRot=rot,_flItID=0})
(FlIt {_flIt=it,_flItPos=(0,0),_flItRot=rot,_flItID=0}) -- Nothing -> id
Nothing -> id -- offset = _crRad cr *.* unitVectorAtAngle rot
-- (rot,_) = randomR (-pi,pi) g
-- | Drop items accoring to the creature state.
dropByState :: Creature -> World -> World
dropByState cr w = foldr (copyItemToFloor cr) w is
where
is :: [Int]
is = case cr ^. crState . crDropsOnDeath of
DropAll -> IM.keys $ _crInv cr
DropSpecific xs -> xs
DropAmount n -> take n $ evalState (shuffle $ IM.keys $ _crInv cr) (_randGen w)
{- Copy an inventory item to the floor. -}
copyItemToFloor
:: Creature
-> Int -- ^ Inventory position
-> World
-> World
copyItemToFloor cr i w = case _crInv cr IM.! i of
NoItem -> w
it -> over floorItems (IM.insert flid theflit)
. updateLocation
$ set randGen g w
where
(rot, g) = randomR (-pi,pi) $ _randGen w
offset = _crRad cr *.* unitVectorAtAngle rot offset = _crRad cr *.* unitVectorAtAngle rot
(rot,_) = randomR (-pi,pi) g updateLocation w = case it ^? itID of
Just (Just i) -> w & itemPositions . ix i .~ OnFloor flid
_ -> w
flid = newKey $ _floorItems w
theflit = FlIt
{_flIt = set itAmount 1 it
,_flItPos = offset +.+ _crPos cr
,_flItRot = rot
,_flItID = flid
}
createItemAt :: Point2 -> FloorItem -> World -> World
createItemAt p it w = over floorItems (IM.insert i (set flItPos p
$ set flItID i it)) w
where i = newKey (_floorItems w)
setOldPos :: Creature -> Creature setOldPos :: Creature -> Creature
setOldPos cr = set crOldPos (_crPos cr) cr setOldPos cr = set crOldPos (_crPos cr) cr
@@ -183,11 +224,6 @@ decreaseToZero :: Int -> Int
decreaseToZero x | x > 0 = x - 1 decreaseToZero x | x > 0 = x - 1
| otherwise = 0 | otherwise = 0
--comb :: (StdGen -> Creature -> World -> World) -> (StdGen -> Creature -> Maybe Creature)
-- -> CRUpdate
--comb
onDeath :: (Creature -> World -> World) -> CRUpdate -> CRUpdate onDeath :: (Creature -> World -> World) -> CRUpdate -> CRUpdate
onDeath h u w (f,g) cr onDeath h u w (f,g) cr
| _crHP cr > 0 = u w (f,g) cr | _crHP cr > 0 = u w (f,g) cr
+95
View File
@@ -0,0 +1,95 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.State.Data
where
import Geometry
import Control.Lens
data ItemDropType
= DropAll
| DropAmount Int
| DropSpecific [Int]
data CrSpState
= Barrel { _piercedPoints :: [Point2]}
| GenCr
deriving (Eq,Show,Ord)
data Goal
= MoveTo Point2
| MoveToFor Point2 Int
| MoveFire Point2 Point2
| PathTo Point2
| PathAlong [Point2]
| SubPathTo Point2 Int Point2
| Wait
| WaitFor Int
| WaitForID Int Int
| FireAt Point2
| FireAtID Int Point2
| Fire
| Reload
| IncreaseAlert Int
| Guard Point2 Point2
| Search Int
| SearchNear Point2
| AimAt Point2 Int
| InitGuard
| Init
| MeleeAttack Int
| InitTrackYou
| TrackYou
| Track Int
| TrackFor Int Int
| TurnByFor Float Int
| TurnTo Point2
| TurnToward Point2
| TurnTowardAngle Float
| StrafeLeftAround Int Point2
| StrafeRightAround Int Point2
| StrafeLeftFor Int
| StrafeRightFor Int
| StrafeLeftForSpeed Int Float
| StrafeRightForSpeed Int Float
| StrafeLeftFire
| StrafeRightFire
| MoveForwardFor Int
| MoveForwardFire
| MoveBackwardFor Int
| MoveByFor Point2 Int
| MoveBackwardFire
| GoalID Int Goal
| AtRange Float
| AtRanges Float Float
| RepeatAction Int Goal
| MakeJudgement
| SetPosture Posture
deriving (Eq,Show)
data Stance = Stance
{_carriage :: Carriage
,_posture :: Posture
}
deriving (Eq,Show)
data Carriage
= Walking { _stepCycle :: Int, _stepToAdd :: Int }
| Standing
| Floating
| Boosting Point2
deriving (Eq,Show)
data Posture = Aiming | AtEase
deriving (Eq,Show)
data Mind = ZombieMind | HumanMind
deriving (Eq,Show)
data Faction
= GenericFaction Int
| ZombieFaction
| EncircleFlock
| ChaseCritters
| SpawnedBy Int
| NoFaction
deriving (Eq,Show)
makeLenses ''CrSpState
makeLenses ''Goal
makeLenses ''Carriage
makeLenses ''Posture
+1 -1
View File
@@ -3,7 +3,7 @@ module Dodge.Creature.YourControl
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.CreatureAction import Dodge.Creature.Action
import Dodge.Creature.State import Dodge.Creature.State
import Dodge.Update.UsingInput import Dodge.Update.UsingInput
import Dodge.Config.KeyConfig import Dodge.Config.KeyConfig
+14 -91
View File
@@ -5,11 +5,15 @@ module Dodge.Data
( module Dodge.Data ( module Dodge.Data
, module Dodge.Data.Menu , module Dodge.Data.Menu
, module Dodge.Data.SoundOrigin , module Dodge.Data.SoundOrigin
, module Dodge.Creature.Data
, module Dodge.Creature.State.Data
, Point2 (..) , Point2 (..)
, Sound (..) , Sound (..)
, soundTime , soundTime
) )
where where
import Dodge.Creature.Data
import Dodge.Creature.State.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.Data.SoundOrigin import Dodge.Data.SoundOrigin
import Dodge.Config.Data import Dodge.Config.Data
@@ -161,93 +165,6 @@ data Creature = Creature
, _crIsAnimate :: Bool , _crIsAnimate :: Bool
} }
data CreatureState = CrSt
{ _goals :: [[Goal]]
, _stance :: Stance
, _faction :: Faction
, _crDamage :: [DamageType]
, _crPastDamage :: Int
, _crSpState :: CrSpState
, _crApplyDamage :: [DamageType] -> Creature -> (World -> World,Creature)
}
data CrSpState
= Barrel { _piercedPoints :: [Point2]}
| GenCr
deriving (Eq,Show,Ord)
data Goal
= MoveTo Point2
| MoveToFor Point2 Int
| MoveFire Point2 Point2
| PathTo Point2
| PathAlong [Point2]
| SubPathTo Point2 Int Point2
| Wait
| WaitFor Int
| WaitForID Int Int
| FireAt Point2
| FireAtID Int Point2
| Fire
| Reload
| IncreaseAlert Int
| Guard Point2 Point2
| Search Int
| SearchNear Point2
| AimAt Point2 Int
| InitGuard
| Init
| MeleeAttack Int
| InitTrackYou
| TrackYou
| Track Int
| TrackFor Int Int
| TurnByFor Float Int
| TurnTo Point2
| TurnToward Point2
| TurnTowardAngle Float
| StrafeLeftAround Int Point2
| StrafeRightAround Int Point2
| StrafeLeftFor Int
| StrafeRightFor Int
| StrafeLeftForSpeed Int Float
| StrafeRightForSpeed Int Float
| StrafeLeftFire
| StrafeRightFire
| MoveForwardFor Int
| MoveForwardFire
| MoveBackwardFor Int
| MoveByFor Point2 Int
| MoveBackwardFire
| GoalID Int Goal
| AtRange Float
| AtRanges Float Float
| RepeatAction Int Goal
| MakeJudgement
| SetPosture Posture
deriving (Eq,Show)
data Stance = Stance
{_carriage :: Carriage
,_posture :: Posture
}
deriving (Eq,Show)
data Carriage
= Walking { _stepCycle :: Int, _stepToAdd :: Int }
| Standing
| Floating
| Boosting Point2
deriving (Eq,Show)
data Posture = Aiming | AtEase
deriving (Eq,Show)
data Mind = ZombieMind | HumanMind
deriving (Eq,Show)
data Faction
= GenericFaction Int
| ZombieFaction
| EncircleFlock
| ChaseCritters
| SpawnedBy Int
| NoFaction
deriving (Eq,Show)
data WorldState data WorldState
= DoorNumOpen Int = DoorNumOpen Int
@@ -583,18 +500,24 @@ data ForceField = FF
} }
data FFState = FFDestroyable { _ffsHP :: Int } data FFState = FFDestroyable { _ffsHP :: Int }
data CreatureState = CrSt
{ _goals :: [[Goal]]
, _stance :: Stance
, _faction :: Faction
, _crDamage :: [DamageType]
, _crPastDamage :: Int
, _crSpState :: CrSpState
, _crApplyDamage :: [DamageType] -> Creature -> (World -> World,Creature)
, _crDropsOnDeath :: ItemDropType
}
makeLenses ''World makeLenses ''World
makeLenses ''Cloud makeLenses ''Cloud
makeLenses ''Creature makeLenses ''Creature
makeLenses ''CreatureState makeLenses ''CreatureState
makeLenses ''CrSpState
makeLenses ''Goal
makeLenses ''LightSource makeLenses ''LightSource
makeLenses ''TempLightSource makeLenses ''TempLightSource
makeLenses ''Stance makeLenses ''Stance
makeLenses ''Carriage
makeLenses ''Posture
makeLenses ''Item makeLenses ''Item
makeLenses ''ItemPos makeLenses ''ItemPos
makeLenses ''ItEffect makeLenses ''ItEffect
+11
View File
@@ -24,6 +24,9 @@ import qualified Data.Set as S
import Data.Graph.Inductive.Graph hiding ((&)) import Data.Graph.Inductive.Graph hiding ((&))
import Data.List import Data.List
{-
Indestructible wall.
-}
defaultWall = Wall defaultWall = Wall
{ _wlLine = [(0,0),(50,0)] { _wlLine = [(0,0),(50,0)]
, _wlID = 0 , _wlID = 0
@@ -32,6 +35,10 @@ defaultWall = Wall
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
} }
{-
Door that opens on approach.
Pathable.
-}
defaultAutoDoor = Door defaultAutoDoor = Door
{ _wlLine = [(0,0),(50,0)] { _wlLine = [(0,0),(50,0)]
, _wlID = 0 , _wlID = 0
@@ -42,6 +49,9 @@ defaultAutoDoor = Door
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = True , _doorPathable = True
} }
{-
Non-pathable door.
-}
defaultDoor = Door defaultDoor = Door
{ _wlLine = [(0,0),(50,0)] { _wlLine = [(0,0),(50,0)]
, _wlID = 0 , _wlID = 0
@@ -79,6 +89,7 @@ defaultState = CrSt
, _crPastDamage = 0 , _crPastDamage = 0
, _crSpState = GenCr , _crSpState = GenCr
, _crApplyDamage = defaultApplyDamage , _crApplyDamage = defaultApplyDamage
, _crDropsOnDeath = DropAmount 1
} }
defaultEquipment = Equipment defaultEquipment = Equipment
{ _itIdentity = Generic { _itIdentity = Generic
+1 -1
View File
@@ -17,7 +17,7 @@ import Dodge.Event.Keyboard
import Dodge.Event.Menu import Dodge.Event.Menu
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.CreatureAction import Dodge.Creature.Action
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.Inventory import Dodge.Inventory
import Geometry import Geometry
+2 -2
View File
@@ -7,7 +7,7 @@ module Dodge.Event.Keyboard
where where
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.CreatureAction import Dodge.Creature.Action
import Dodge.Config.KeyConfig import Dodge.Config.KeyConfig
import Dodge.Room.Placement import Dodge.Room.Placement
import Dodge.LightSources import Dodge.LightSources
@@ -43,7 +43,7 @@ handlePressedKeyInGame :: Scancode -> World -> Maybe World
handlePressedKeyInGame scode w handlePressedKeyInGame scode w
| scode == escapeKey (_keyConfig w) = Nothing | scode == escapeKey (_keyConfig w) = Nothing
| scode == pauseKey (_keyConfig w) = Just $ pauseGame $ escapeMap w | scode == pauseKey (_keyConfig w) = Just $ pauseGame $ escapeMap w
| scode == dropItemKey (_keyConfig w) = Just $ dropItem w | scode == dropItemKey (_keyConfig w) = Just $ youDropItem w
| scode == toggleMapKey (_keyConfig w) = Just $ toggleMap w | scode == toggleMapKey (_keyConfig w) = Just $ toggleMap w
| scode == reloadKey (_keyConfig w) = Just $ fromMaybe w $ reloadWeapon (_yourID w) w | scode == reloadKey (_keyConfig w) = Just $ fromMaybe w $ reloadWeapon (_yourID w) w
| scode == testEventKey (_keyConfig w) = Just $ testEvent w | scode == testEventKey (_keyConfig w) = Just $ testEvent w
+3 -1
View File
@@ -37,7 +37,9 @@ roomTreex = do
t = treeTrunk t = treeTrunk
[[StartRoom] [[StartRoom]
,[Corridor] ,[Corridor]
,[BossAno launcherCrit] ,[BossAno $ addArmour launcherCrit & crHP +~ 800
& crState . crDropsOnDeath .~ DropSpecific [0]
]
,[Corridor] ,[Corridor]
,[OrAno [[DoorAno] ,[OrAno [[DoorAno]
,[Corridor] ,[Corridor]
+16 -4
View File
@@ -49,10 +49,13 @@ numInventorySlots = 9
itNotFull :: Item -> Bool itNotFull :: Item -> Bool
itNotFull it = _itMaxStack it > _itAmount it itNotFull it = _itMaxStack it > _itAmount it
rmInvItem :: Int -> World -> World rmInvItem
rmInvItem n w = :: Int -- ^ Creature id
let i = _crInvSel (_creatures w IM.! n) -> Int -- ^ Inventory position
item = _crInv (_creatures w IM.! n) IM.! i -> World
-> World
rmInvItem n i w =
let item = _crInv (_creatures w IM.! n) IM.! i
itRef = creatures . ix n . crInv . ix i itRef = creatures . ix n . crInv . ix i
in case item of in case item of
Consumable {_itAmount = 1} -> set itRef NoItem w Consumable {_itAmount = 1} -> set itRef NoItem w
@@ -65,6 +68,15 @@ rmInvItem n w =
Throwable {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w Throwable {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w
_ -> set itRef NoItem w _ -> set itRef NoItem w
{-
Delete a creature's selected item, the item will no longer exist.
-}
rmSelectedInvItem
:: Int -- ^ Creature id
-> World
-> World
rmSelectedInvItem cid w = rmInvItem cid (_crInvSel (_creatures w IM.! cid)) w
-- for now, left are floor items, right are buttons -- for now, left are floor items, right are buttons
closestActiveObject :: World -> Maybe (Either FloorItem Button) closestActiveObject :: World -> Maybe (Either FloorItem Button)
closestActiveObject w = listToMaybe $ sortBy (compare `on` dist ypos . pos) $ actObjs closestActiveObject w = listToMaybe $ sortBy (compare `on` dist ypos . pos) $ actObjs
+61 -68
View File
@@ -6,7 +6,7 @@ module Dodge.Item.Weapon
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.CreatureAction import Dodge.Creature.Action
import Dodge.RandomHelp import Dodge.RandomHelp
import Dodge.WorldEvent import Dodge.WorldEvent
import Dodge.Debug import Dodge.Debug
@@ -320,7 +320,7 @@ launcher = defaultGun
, _wpReloadState = 0 , _wpReloadState = 0
, _wpFireRate = 20 , _wpFireRate = 20
, _wpFireState = 0 , _wpFireState = 0
, _wpFire = shoot $ aRocket , _wpFire = shootWithSound (fromIntegral launcherSound) $ aRocketWithPayload makeExplosionAt
, _wpSpread = 0.02 , _wpSpread = 0.02
, _wpRange = 20 , _wpRange = 20
, _itFloorPict = onLayer FlItLayer $ color cyan $ polygon $ rectNESW 5 5 (-5) (-5) , _itFloorPict = onLayer FlItLayer $ color cyan $ polygon $ rectNESW 5 5 (-5) (-5)
@@ -334,17 +334,17 @@ launcher = defaultGun
} }
flameLauncher = launcher flameLauncher = launcher
{ _itName = "FLROCKO" { _itName = "FLROCKO"
, _wpFire = shoot . aRocket' $ makeShellAt makeFlameExplosionAt , _wpFire = shootWithSound (fromIntegral launcherSound) $ aRocketWithPayload makeFlameExplosionAt
} }
poisonLauncher = launcher poisonLauncher = launcher
{ _itName = "POISROCK" { _itName = "POISROCK"
, _wpFire = shoot . aRocket' $ makeShellAt makePoisonExplosionAt , _wpFire = shootWithSound (fromIntegral launcherSound) $ aRocketWithPayload makePoisonExplosionAt
} }
teslaLauncher = launcher teslaLauncher = launcher
{ _itName = "TESLROCK" { _itName = "TESLROCK"
, _wpFire = shoot . aRocket' $ makeShellAt makeTeslaExplosionAt , _wpFire = shootWithSound (fromIntegral launcherSound) $ aRocketWithPayload makeTeslaExplosionAt
} }
bezierGun = defaultAutoGun bezierGun = defaultAutoGun
@@ -700,7 +700,6 @@ aLaser cid w = over particles' ( (:) (makeLaserAt phaseV pos dir (Just cid)))
phaseV = fromMaybe 1 $ cr ^? crInv . ix j . itAttachment . _Just . itPhaseV phaseV = fromMaybe 1 $ cr ^? crInv . ix j . itAttachment . _Just . itPhaseV
j = _crInvSel cr j = _crInvSel cr
aTractorBeam :: Int -> Int -> World -> World aTractorBeam :: Int -> Int -> World -> World
aTractorBeam col cid w aTractorBeam col cid w
= set (creatures . ix cid . crInv . ix itRef . wpFire) = set (creatures . ix cid . crInv . ix itRef . wpFire)
@@ -712,21 +711,23 @@ aTractorBeam col cid w
dir = _crDir cr dir = _crDir cr
itRef = _crInvSel cr itRef = _crInvSel cr
-- | The aRocket' function allows us to define the shell to be used aRocketWithPayload
aRocket' :: (Int -> Int -> Point2 -> Float -> Projectile) -> Int -> World -> World :: (Point2 -> World -> World)
aRocket' shell cid w -- ^ Payload
= soundOnce (fromIntegral launcherSound) -> Int -- ^ Creature id
$ over projectiles (IM.insert i (shell i cid pos dir)) w -> World
where i = newProjectileKey w -> World
cr = (_creatures w IM.! cid) aRocketWithPayload pl cid w = over projectiles (IM.insert i theShell) w
pos = _crPos cr +.+ ((_crRad cr +1) *.* unitVectorAtAngle dir) where
dir = _crDir cr i = newProjectileKey w
cr = (_creatures w IM.! cid)
aRocket :: Int -> World -> World pos = _crPos cr +.+ ((_crRad cr +1) *.* unitVectorAtAngle dir)
aRocket = aRocket' (makeShellAt shellExplosionAt) dir = _crDir cr
theShell = makeShellAt pl i cid pos dir
makeShellAt makeShellAt
:: (Point2 -> World -> World) -- ^ Payload :: (Point2 -> World -> World)
-- ^ Payload
-> Int -- ^ Projectile id -> Int -- ^ Projectile id
-> Int -- ^ Creature id -> Int -- ^ Creature id
-> Point2 -- ^ Start position -> Point2 -- ^ Start position
@@ -736,68 +737,61 @@ makeShellAt pl i cid pos dir = Shell
{ _pjPos = pos { _pjPos = pos
, _pjStartPos = pos , _pjStartPos = pos
, _pjVel = rotateV dir (1,0) , _pjVel = rotateV dir (1,0)
, _pjPict = blank -- onLayer PtLayer $ uncurry translate pos $ rotate (radToDeg dir) shellPic , _pjPict = blank
, _pjID = i , _pjID = i
, _pjUpdate = moveShell 50 i cid 0 (rotateV dir (3,0)) , _pjUpdate = moveShell 50 i cid 0 (rotateV dir (3,0))
, _pjPayload = pl , _pjPayload = pl
} }
moveShell :: Int -> Int -> Int -> Float -> Point2 -> World -> World moveShell
:: Int -- ^ Timer (frames)
-> Int -- ^ Projectile id
-> Int -- ^ Creature id
-> Float -- ^ Rotation
-> Point2 -- ^ Acceleration
-> World -> World
moveShell time i cid rot accel w moveShell time i cid rot accel w
| time > 40 = if circOnSomeWall oldPos 4 w | time > 40 = if circOnSomeWall oldPos 4 w
then doExplode then doExplode
else over (projectiles . ix i . pjPos) (+.+ vel) else w
$ set (projectiles . ix i . pjPict) piclow & projectiles . ix i . pjPos %~ (+.+ vel)
$ set (projectiles . ix i . pjUpdate) & projectiles . ix i . pjPict .~ piclow
(moveShell (time-1) i cid rot (rotateV rot accel)) & projectiles . ix i . pjUpdate .~ moveShell (time-1) i cid rot (rotateV rot accel)
w | isJust thingHit = doExplode
| time == 35 = case thingHit of | time == 35 = w
Just p -> doExplode & projectiles . ix i . pjPos %~ (+.+ vel)
Nothing -> over (projectiles . ix i . pjPos) (+.+ vel) & projectiles . ix i . pjPict .~ pic
$ set (projectiles . ix i . pjPict) pic & projectiles . ix i . pjUpdate .~ moveShell (time-1) i cid spin accel
$ set (projectiles . ix i . pjUpdate) | time >= 20 = w
(moveShell (time-1) i cid spin accel) & projectiles . ix i . pjPos %~ (+.+ vel)
w & projectiles . ix i . pjPict .~ pic
| time >= 20 = case thingHit of & projectiles . ix i . pjUpdate .~ moveShell (time-1) i cid rot (rotateV rot accel)
Just p -> projectileExplosion oldPos | time > -99 = w
$ over projectiles (IM.delete i) w & projectiles . ix i . pjPos %~ (+.+ vel)
Nothing -> over (projectiles . ix i . pjPos) (+.+ vel) & randGen .~ g
$ set (projectiles . ix i . pjPict) pic & projectiles . ix i . pjPict .~ pic
$ set (projectiles . ix i . pjUpdate) & projectiles . ix i . pjUpdate .~ (moveShell (time-1) i cid rot (rotateV rot accel))
(moveShell (time-1) i cid rot (rotateV rot accel)) & projectiles . ix i . pjVel %~ (\v -> accel +.+ frict *.* v)
w & soundFromPos (ShellSound i) newPos (fromIntegral smokeTrailSound) (1) 250
| time > -99 = case thingHit of & makeFlameletTimed (oldPos -.- vel) (vel +.+ rotateV (pi+sparkD) accel) Nothing 3 10
Just p -> doExplode & smokeGen
Nothing -> over (projectiles . ix i . pjPos) (+.+ vel) | time > -200 = w
$ set randGen g & projectiles . ix i . pjPos %~ (+.+ vel)
$ set (projectiles . ix i . pjPict) pic & projectiles . ix i . pjPict .~ pic
$ set (projectiles . ix i . pjUpdate) & projectiles . ix i . pjUpdate .~ moveShell (time-1) i cid rot (rotateV rot accel)
(moveShell (time-1) i cid rot (rotateV rot accel))
$ over (projectiles . ix i . pjVel) (\v -> accel +.+ frict *.* v)
$ soundFromPos (ShellSound i) newPos (fromIntegral smokeTrailSound) (1) 250
$ makeFlameletTimed oldPos
(0.5 *.* rotateV (pi+sparkD) accel) Nothing 3 10
$ smokeGen
w
| time > -200 = case thingHit of
Just p -> doExplode
Nothing -> over (projectiles . ix i . pjPos) (+.+ vel)
$ set (projectiles . ix i . pjPict) pic
$ set (projectiles . ix i . pjUpdate)
(moveShell (time-1) i cid rot (rotateV rot accel))
w
| otherwise = doExplode | otherwise = doExplode
where where
doExplode = projectileExplosion oldPos doExplode = w
$ stopSoundFrom (ShellSound i) & projectileExplosion oldPos
$ over projectiles (IM.delete i) w & stopSoundFrom (ShellSound i)
& projectiles %~ IM.delete i
pj = _projectiles w IM.! i pj = _projectiles w IM.! i
oldPos = _pjPos pj oldPos = _pjPos pj
vel = _pjVel pj vel = _pjVel pj
projectileExplosion = _pjPayload pj projectileExplosion = _pjPayload pj
newPos = oldPos +.+ vel newPos = oldPos +.+ vel
(frict,g) = randomR (0.6,0.9) $ _randGen w (frict,g) = randomR (0.6,0.9) $ _randGen w
(sparkD,_) = randomR (-0.5,0.5) $ _randGen w (sparkD,_) = randomR (-0.2,0.2) $ _randGen w
dir = argV $ vel dir = argV $ vel
pic = onLayer PtLayer $ uncurry translate newPos $ rotate (argV accel) shellPic pic = onLayer PtLayer $ uncurry translate newPos $ rotate (argV accel) shellPic
piclow = onLayerL [levLayer CrLayer - 2] piclow = onLayerL [levLayer CrLayer - 2]
@@ -812,7 +806,6 @@ moveShell time i cid rot accel w
r1 = _randGen w & evalState (randInCirc 10) r1 = _randGen w & evalState (randInCirc 10)
smokeGen = makeSmokeCloudAt (oldPos +.+ r1 +.+ 30 *.* (normalizeV (oldPos -.- newPos))) smokeGen = makeSmokeCloudAt (oldPos +.+ r1 +.+ 30 *.* (normalizeV (oldPos -.- newPos)))
normalizeAnglePi angle | normalizeAngle angle > pi = normalizeAngle angle - 2*pi normalizeAnglePi angle | normalizeAngle angle > pi = normalizeAngle angle - 2*pi
| otherwise = normalizeAngle angle | otherwise = normalizeAngle angle
+1 -1
View File
@@ -5,7 +5,7 @@ module Dodge.Item.Weapon.TriggerType
where where
import Dodge.Data import Dodge.Data
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.CreatureAction (reloadWeapon) import Dodge.Creature.Action (reloadWeapon)
import Dodge.WorldEvent (muzzleFlashAt,tempLightForAt) import Dodge.WorldEvent (muzzleFlashAt,tempLightForAt)
import Dodge.WorldEvent.Cloud import Dodge.WorldEvent.Cloud
import Dodge.RandomHelp import Dodge.RandomHelp
+8 -6
View File
@@ -1,5 +1,5 @@
{- {-
Rooms containing particularly challenging creatures. Rooms containing particularly challenging creatures, that may drop useful loot.
-} -}
module Dodge.Room.Boss module Dodge.Room.Boss
where where
@@ -23,10 +23,10 @@ roomOctogon x = Room
, _rmPath = [((0,x),(0,-(x+40))) , _rmPath = [((0,x),(0,-(x+40)))
,((0,-(x+40)),(0,x))] ,((0,-(x+40)),(0,x))]
, _rmPS = , _rmPS =
[PS (x-10,x-10) 0 $ putLamp [PS (fx,fx) 0 $ putLamp
,PS (10-x,x-10) 0 $ putLamp ,PS (-fx,fx) 0 $ putLamp
,PS (10-x,10-x) 0 $ putLamp ,PS (fx,-fx) 0 $ putLamp
,PS (x-10,10-x) 0 $ putLamp ,PS (-fx,-fx) 0 $ putLamp
,crystalLine (-x,x/2) (negate (x/2), x) ,crystalLine (-x,x/2) (negate (x/2), x)
,crystalLine (x,x/2) (x/2, x) ,crystalLine (x,x/2) (x/2, x)
,crystalLine (x/2,-x) (x,negate (x/2)) ,crystalLine (x/2,-x) (x,negate (x/2))
@@ -35,6 +35,8 @@ roomOctogon x = Room
] ]
, _rmBound = rectNSWE x (-x) (-x) x , _rmBound = rectNSWE x (-x) (-x) x
} }
where
fx = 4 * x / 5
bossRoom :: RandomGen g => Creature -> State g Room bossRoom :: RandomGen g => Creature -> State g Room
bossRoom cr = pure $ roomOctogon 300 & rmPS %~ ( PS (0,100) (pi/2) (PutCrit cr) :) bossRoom cr = pure $ roomOctogon 300 & rmPS %~ ( PS (0,100) (negate $ pi/2) (PutCrit cr) :)
+6
View File
@@ -0,0 +1,6 @@
{-
Rooms that contain valuable items, typically protected in some manner.
-}
module Dodge.Room.Treasure
where
import Geometry
+4 -4
View File
@@ -1,13 +1,13 @@
{-
Functions that affect the world according to what pressed buttons are stored in a Set.
-}
module Dodge.Update.UsingInput module Dodge.Update.UsingInput
where where
import Dodge.Data import Dodge.Data
import Dodge.Creature.Action.UseItem
import Dodge.CreatureAction.UseItem
import Geometry import Geometry
import SDL import SDL
import qualified Data.Set as S import qualified Data.Set as S
import Control.Lens import Control.Lens