Files
loop/src/Dodge/Critters.hs
T

401 lines
15 KiB
Haskell

module Dodge.Critters where
-- imports {{{
import Dodge.Data
import Dodge.AIs
import Dodge.CreatureState
import Dodge.Prototypes
import Dodge.Base
import Dodge.Smoke
import Dodge.Item.Weapon
import Dodge.Item.Consumable
import Picture
import Geometry
import Data.List
import Data.Char
import Data.Maybe
import Data.Function
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Codec.BMP
import qualified Data.ByteString as B
import Control.Lens
import Control.Applicative
import Control.Monad.State
import Control.Monad
import System.Random
import qualified Data.Set as S
import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M
import Foreign.ForeignPtr
import Control.Concurrent
---}
--colouredEnemy col = pictures [color (greyN 0.8) $ circleSolid 10, color col $ circLine 10]
colouredEnemy col = pictures [color col $ circleSolid 10, circLine 10]
-- armouredSwarmCrit :: Int -> Creature
-- armouredSwarmCrit n = (basicCreature n)
-- -- { _crUpdate = encircleAI' n
-- { _crUpdate = swarmAI lineOrth n
-- , _crHP = 30
-- , _crPict = equipOnTop goalPict
-- , _crState = basicState {_goals = [[]], _faction = EncircleFlock}
-- , _crInv = IM.fromList [(0,frontArmour)]
-- }
--
-- swarmCrit :: Int -> Creature
-- swarmCrit n = (basicCreature n)
-- -- { _crUpdate = encircleAI' n
-- { _crUpdate = swarmAI lineOrth n
-- , _crHP = 30
-- , _crPict = equipOnTop goalPict
-- , _crState = basicState {_goals = [[]], _faction = EncircleFlock}
-- , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
-- }
--
-- encircleCrit :: Int -> Creature
-- encircleCrit n = (basicCreature n)
-- -- { _crUpdate = encircleAI' n
-- { _crUpdate = swarmAI lineOrth n
-- , _crHP = 30
-- , _crPict = equipOnTop goalPict
-- , _crState = basicState {_goals = [[]], _faction = EncircleFlock}
-- , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
-- }
--
spawnerCrit :: Creature
spawnerCrit = basicCreature
{ _crUpdate = stateUpdate $ spawnerAI chaseCrit
, _crHP = 300
, _crPict = enemyPict blue
, _crState = basicState {_goals = [[WaitFor 0]]
}
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
}
--
-- guardMelee :: Int -> Creature
-- guardMelee n = (basicCreature n)
-- { _crUpdate = meleeAI' n
-- , _crHP = 30
-- , _crPict = equipOnTop goalPict
-- , _crState = basicState {_goals = [[InitGuard]]
-- ,_faction = ChaseCritters}
-- , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
-- }
smallChaseCrit :: Creature
smallChaseCrit = basicCreature
{ _crUpdate = stateUpdate chaseAI
, _crHP = 1
, _crRad = 4
--, _crPict = equipOnTop goalPict
, _crPict = enemyPict green
, _crState = basicState {_goals = [[Wait]]
,_faction = ChaseCritters}
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
, _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 4
}
chaseCrit :: Creature
chaseCrit = basicCreature
{ _crUpdate = stateUpdate chaseAI
, _crHP = 300
-- , _crPict = goalPict -- enemyPict green
, _crPict = enemyPict green
, _crState = basicState {_goals = [[Wait]]
,_faction = ChaseCritters}
, _crInv = IM.empty
-- IM.fromList [(0,frontArmour)]
}
armourChaseCrit :: Creature
armourChaseCrit = basicCreature
{ _crUpdate = stateUpdate chaseAI
, _crHP = 300
, _crPict = enemyPict green
, _crState = basicState {_goals = [[Wait]]}
, _crInv = IM.fromList [(0,frontArmour)]
}
miniGunCrit :: Creature
miniGunCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate miniAI
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,miniGun)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[InitGuard]]}
, _crHP = 500
}
longCrit :: Creature
longCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate sniperAI
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,longGun),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[InitGuard]]}
, _crHP = 300
}
multGunCrit :: Creature
multGunCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate (twitchMissAI 300 350)
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,multGun),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[InitGuard]]}
, _crHP = 300
}
launcherCrit :: Creature
launcherCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate (launcherAI 150 200)
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,launcher),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[Init]]}
, _crHP = 300
}
spreadGunCrit :: Creature
spreadGunCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate chargeAI
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,spreadGun),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[Init]]}
, _crHP = 300
}
pistolCrit :: Creature
pistolCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate (dodgeAI 150 200)
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,pistol),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[InitGuard]]}
, _crHP = 500
}
autoCrit :: Creature
autoCrit = basicCreature
{ _crPict = enemyPict red
--, _crUpdate = checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
, _crUpdate = stateUpdate basicShooterAI
--, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
, _crInv = IM.fromList [(0,autoGun),(1,medkit 100)]
, _crInvSel = 0
, _crRad = 10
, _crAmmo = M.fromList [(PistolBullet, 1000)]
--, _crState = ShooterWait
, _crState = basicState {_goals = [[InitGuard]]}
, _crHP = 300
}
addArmour :: Creature -> Creature
addArmour = over crInv insarmour
where insarmour xs = IM.insert i frontArmour xs
where i = newKey xs
--closeShooterCrit :: Int -> Creature
--closeShooterCrit n = (basicCreature n)
-- { _crPos = startPos
-- , _crPict = equipOnTop goalPict
-- , _crUpdate = closeShooterAI n
-- , _crInv = IM.fromList [(0,ltAutoGun)]
-- , _crInvSel = 0
-- , _crRad = 10
-- , _crAmmo = M.fromList [(PistolBullet, 1000)]
-- , _crState = basicState {_goals = [[InitGuard]]}
-- , _crHP = 50
-- }
-- where startPos = (20*fromIntegral n-550,0)
barrel :: Creature
barrel = basicCreature
{ _crUpdate = updateBarrel
, _crHP = 500
, _crPict = \ _ -> onLayer CrLayer $ pictures [ color orange $ circleSolid 10
, color (greyN 0.5) $ circleSolid 8
]
, _crState = basicState {_goals = [[Wait]]
,_faction = ChaseCritters
,_crSpState = Barrel []
}
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
}
explosiveBarrel :: Creature
explosiveBarrel = basicCreature
{ _crUpdate = updateExpBarrel
, _crHP = 400
, _crPict = \ _ -> onLayer CrLayer $ pictures [ color orange $ circleSolid 10
, color red $ circleSolid 8
]
, _crState = basicState {_goals = [[Wait]]
,_faction = ChaseCritters
,_crSpState = Barrel []
,_crApplyDamage = \_ c -> (id, c)
}
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
}
equipOnTop :: (Creature -> Picture) -> Creature -> Drawing
--equipOnTop f cr = onLayer CrLayer $ pictures $ fst (drawEquipment cr) ++ [f cr] ++ snd (drawEquipment cr)
equipOnTop f cr = pictures [onLayer CrLayer (f cr) , drawEquipment cr]
drawEquipment :: Creature -> Drawing
drawEquipment cr = pictures $ map f $ IM.toList (_crInv cr)
where f (i,it) = case it ^? itEquipPict of
Just g -> g cr i
_ -> blank
--drawEquipment :: Creature -> ([Picture],[Picture])
--drawEquipment cr = (map fst p1, map fst p2)
-- where f (k,it) = join $ (it ^? itEquipPict) <*> (pure cr) <*> (pure k)
-- picts = sortBy (compare `on` snd) $ mapMaybe f $ IM.toList (_crInv cr)
-- (p1,p2) = partition (\ x -> snd x < 0) picts
frontArmouredPict = const $ pictures [ color (greyN 0.8) $ circleSolid 20
, color red $ circLine 20
]
--packCrits :: (Int -> World -> World) -> [Int] -> [Creature]
--packCrits ai is = [(basicCreature i)
-- { _crPos = (150,10+20*fromIntegral i)
-- , _crPict = swarmPict
-- , _crUpdate = ai i
-- --, _crUpdate = swarmAI is i
-- , _crRad = 3
-- , _crHP = 1
-- , _crMass = 2
-- }
-- | i <- is]
--queenBeeCrit :: Int -> Creature
--queenBeeCrit cID = (basicCreature cID)
-- { _crRad = 20
-- , _crCorpse = color (greyN 0.5) $ circleSolid 20
-- , _crPict = const $ pictures [color black $ circSolid 20
-- ,color yellow $ circLine 20
-- ]
-- , _crUpdate = checkDead cID . makeStateAI queenBeeAI cID
-- , _crState = QueenBee 0 20
-- , _crMass = 20
-- }
--antCrit :: Int -> Creature
--antCrit cID = (basicCreature cID)
-- { _crPos = (0,100 + 3 * fromIntegral cID)
-- , _crUpdate = checkDead cID . makeStateAI (antAI 2) cID
-- , _crState = AntMove 50
-- , _crPict = antPic
-- , _crRad = 3
-- , _crHP = 1
-- , _crMass = 2
-- , _crCorpse = color (greyN 0.5) $ circSolid 3
-- }
-- where i = evalState (state (randomR (1::Int,100))) (mkStdGen cID)
--antPic = const $ pictures [ translate (-1) 0 $ circleSolid 2
-- , translate (2) 0 $ circleSolid 1
-- , translate (1) 0 $ circleSolid 1
-- , line [(3,3),(-3,-3)]
-- , line [(-3,3),(3,-3)]
-- , line [(0,-3),(0,3)]
-- ]
flamerPict = const $ pictures [color (light $ light $ light $ dim blue) $ circleSolid 10, circLine 10]
goalPict cr = let r = _crRad cr in case _crState cr of
CrSt {_goals = gls ,_crDamage = crDam }
-- | crDam > _crHP cr -> color white $ circleSolid r
| otherwise -> case head gls of
[] -> sizeColEnemy r white
(MoveToFor p i:_) -> dGoals $ sizeColEnemy r green
(WaitFor x:_) -> dGoals $ sizeColEnemy r yellow
(FireAt p:_) -> dGoals $ sizeColEnemy r red
(Reload:_) -> dGoals $ sizeColEnemy r orange
(PathTo p:_) -> dGoals $ sizeColEnemy r cyan
(SubPathTo p i _:_) -> dGoals $ sizeColEnemy r blue
(Search i:_) -> dGoals $ sizeColEnemy r black
_ -> dGoals $ sizeColEnemy r magenta
where dGoals p = pictures [p, rotate (0 - _crDir cr) $ scale 0.1 0.1 $ color white $ text $ show gls]
_ -> sizeColEnemy r (light $ dim green)
startCr :: Creature
startCr = basicCreature
{ _crPos = (0,0)
, _crOldPos = (0,0)
, _crDir = 0
, _crID = 0
, _crPict = basicCrPict $ greyN 0.8
, _crUpdate = stateUpdate yourControl
, _crRad = 10
, _crMass = 10
, _crHP = 10000
, _crMaxHP = 1500
, _crInv = IM.fromList (zip [0..20]
([pistol,autoGun,launcher,lasGun,grenade
,ltAutoGun,flamer,multGun,spreadGun,remoteLauncher
,longGun
,hvAutoGun
,teslaGun
,latchkey 0
,frontArmour
,miniGun
,medkit 50
]
++ repeat NoItem))
-- startInv
, _crAmmo = M.fromList [(PistolBullet, 0),(LiquidFuel, 100),(Battery, 20000),(Shell,200)]
, _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ pictures [color (greyN 0.8) $ circleSolid 10, circLine 10]
}
smokeGenGun = effectGun "smoke" $ \_ -> spawnSmokeAtCursor
enemyPict :: Color -> Creature -> Drawing
enemyPict col = equipOnTop $ sizeEnemy (light $ light $ light $ light col)
sizeEnemy col cr
| pdam > 200 = color red $ circleSolid $ _crRad cr
| pdam > 100 = color white $ circleSolid $ _crRad cr
| mod pdam 2 == 1 = color white $ circleSolid $ _crRad cr
| otherwise = pictures [color col $ circleSolid $ _crRad cr
, circLine $ _crRad cr ]
where pdam = _crPastDamage $ _crState cr
sizeColEnemy r col = pictures [color col $ circleSolid r, circLine r]
basicCrPict :: Color -> Creature -> Drawing
basicCrPict col cr = pictures [ onLayer CrLayer naked , drawEquipment cr]
where naked | pdam > 200 = color red $ circleSolid $ _crRad cr
| pdam > 100 = color white $ circleSolid $ _crRad cr
| mod pdam 2 == 1 = color white $ circleSolid $ _crRad cr
-- | crDam > _crHP cr && odd (crDam - _crHP cr)
-- = [color white $ circleSolid $ _crRad cr]
| otherwise = pictures [color col $ circleSolid $ _crRad cr, circLine $ _crRad cr]
pdam = _crPastDamage $ _crState cr