{- | Contains base datatypes that cannot be seperated into different modules because they are interdependent; circular imports are probably not a good idea. -} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE DeriveGeneric #-} module Dodge.Data ( module Dodge.Data , module Dodge.Data.DamageType , module Dodge.Data.SoundOrigin , Point2 , Sound (..) , soundTime ) where import Dodge.Creature.State.Data import Dodge.Creature.Stance.Data import Dodge.Creature.AlertLevel.Data import Dodge.Debug.Flag.Data import Dodge.Data.Menu import Dodge.Data.SoundOrigin import Dodge.Data.DamageType import Dodge.Config.Data import Dodge.Config.KeyConfig import Dodge.Item.Attachment.Data import Dodge.Item.Data import Dodge.World.Trigger.Data import Preload.Data import Picture.Data import Geometry.Data import Sound.Data import qualified DoubleStack as DS import GHC.Generics import Control.Lens import System.Random import Data.Graph.Inductive import Data.Int (Int16) import qualified Data.Set as S import qualified Data.IntSet as IS import qualified Data.IntMap.Strict as IM import qualified Data.Map as M import SDL (Scancode, MouseButton) data World = World { _keys :: !(S.Set Scancode) , _mouseButtons :: !(S.Set MouseButton) , _cameraCenter :: !Point2 , _cameraRot :: !Float , _cameraZoom :: !Float , _cameraViewFrom :: !Point2 , _creatures :: IM.IntMap Creature , _creaturesZone :: IM.IntMap (IM.IntMap (IM.IntMap Creature)) , _creatureGroups :: IM.IntMap CrGroupParams , _itemPositions :: IM.IntMap ItemPos , _clouds :: IM.IntMap Cloud , _cloudsZone :: IM.IntMap (IM.IntMap (IM.IntMap Cloud)) , _projectiles :: IM.IntMap Projectile , _particles :: ![Particle] , _staticWalls :: [Wall] , _walls :: !(IM.IntMap Wall) , _wallsZone :: IM.IntMap (IM.IntMap (IM.IntMap Wall)) , _forceFields :: IM.IntMap ForceField , _floorItems :: IM.IntMap FloorItem , _randGen :: StdGen , _mousePos :: !(Float,Float) , _testString :: String , _yourID :: !Int , _worldEvents :: !(World -> World) , _pressPlates :: IM.IntMap PressPlate , _buttons :: IM.IntMap Button , _soundQueue :: [(Int,Int16)] , _sounds :: M.Map SoundOrigin Sound , _decorations :: IM.IntMap Picture , _foregroundDecorations :: [Picture] , _corpses :: IM.IntMap (IM.IntMap [Corpse]) , _clickMousePos :: (Float,Float) , _pathGraph :: ~(Gr Point2 Float) , _pathGraph' :: ~[(Point2,Point2)] , _pathPoints :: ~(IM.IntMap (IM.IntMap [(Int,Point2)])) , _pathInc :: ~(M.Map Point2 [Point2]) , _storedLevel :: Maybe World , _menuLayers :: [MenuLayer] , _worldState :: M.Map WorldState Bool , _worldTriggers :: S.Set WorldTrigger , _carteDisplay :: !Bool , _carteCenter :: !Point2 , _carteZoom :: !Float , _carteRot :: !Float , _lightSources :: !(IM.IntMap LightSource) , _tempLightSources :: ![TempLightSource] , _closeActiveObjects :: [Either FloorItem Button] , _seenLocations :: IM.IntMap (World -> Point2,String) , _selLocation :: Int , _keyConfig :: KeyConfigSDL , _config :: Configuration , _sideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)] , _doneSideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)] , _debugFlags :: DebugFlags , _inventoryMode :: InventoryMode , _lClickHammer :: HammerPosition } data InventoryMode = TopInventory | TweakInventory | CombineInventory | InspectInventory deriving (Eq, Ord, Show) data CrGroupParams = CrGroupParams { _crGroupParamID :: Int , _crGroupIDs :: IS.IntSet , _crGroupCenter :: Point2 , _crGroupUpdate :: World -> CrGroupParams -> Maybe CrGroupParams } data Corpse = Corpse { _cpPos :: Point2 , _cpPict :: Picture , _cpRes :: Creature } data Cloud = Cloud { _clID :: Int , _clPos :: Point2 , _clVel :: Point2 , _clPict :: Cloud -> Picture , _clRad :: Float , _clTimer :: Int , _clEffect :: Cloud -> World -> World } data LightSource = LS { _lsID :: !Int , _lsPos :: !Point2 , _lsDir :: !Float , _lsRad :: !Float , _lsIntensity :: !Float } data TempLightSource = TLS { _tlsPos :: !Point2 , _tlsRad :: !Float , _tlsIntensity :: !Float , _tlsUpdate :: World -> TempLightSource -> (World, Maybe TempLightSource) } data Creature = Creature { _crPos :: Point2 , _crOldPos :: Point2 , _crVel :: Point2 , _crDir :: Float , _crMvDir :: Float , _crID :: Int , _crPict :: Creature -> World -> Picture , _crUpdate :: World -> (World -> World,StdGen) -> Creature -> ((World -> World,StdGen), Maybe Creature) , _crRad :: Float , _crMass :: Float , _crHP :: Int , _crMaxHP :: Int , _crInv :: IM.IntMap Item , _crInvSel :: Int , _crLeftInvSel :: Maybe Int , _crState :: CreatureState , _crCorpse :: Picture , _crApplyDamage :: [DamageType] -> Creature -> (World -> World,Creature) , _crStance :: Stance , _crActionPlan :: ActionPlan , _crMeleeCooldown :: Maybe Int , _crAwakeLevel :: AwakeLevel , _crAttentionDir :: AttentionDir , _crAwarenessLevel :: IM.IntMap AwarenessLevel , _crFaction :: Faction , _crGroup :: CrGroup , _crTarget :: Maybe Creature } data WorldState = DoorNumOpen Int | CrNumAlive Int deriving (Eq,Ord) data Button = Button { _btPict :: Picture , _btPos :: Point2 , _btRot :: Float , _btEvent :: Button -> World -> World , _btID :: Int , _btText :: String , _btState :: ButtonState } data ButtonState = BtOn | BtOff | BtNoLabel deriving (Eq, Show) data PressPlate = PressPlate { _ppPict :: Picture , _ppPos :: Point2 , _ppRot :: Float , _ppEvent :: PressPlate -> World -> World , _ppID :: Int , _ppText :: String } data FloorItem = FlIt { _flIt :: Item , _flItPos :: Point2 , _flItRot :: Float, _flItID :: Int} data ItemPos = InInv { _itCrId :: Int , _itInvId :: Int } | OnFloor { _itFlID :: Int } data Item = Weapon { _itName :: String , _wpMaxAmmo :: Int , _wpLoadedAmmo :: Int , _wpAmmo :: Ammo , _wpReloadTime :: Int , _wpReloadState :: Int , _itUseRate :: Int , _itUseTime :: Int , _itUse :: Item -> Creature -> World -> World , _itUseModifiers :: [(Item -> Creature -> World -> World) -> Item -> Creature -> World -> World] , _itLeftClickUse :: Maybe (Creature -> Int -> World -> World) , _wpSpread :: Float , _wpRange :: Float , _itHammer :: HammerPosition , _itFloorPict :: Picture , _itMaxStack :: Int , _itAmount :: Int , _itAimingSpeed :: Float , _itAimingRange :: Float , _itZoom :: ItZoom , _itEquipPict :: Creature -> Int -> Picture , _itScroll :: Float -> Creature -> World -> World , _itIdentity :: ItemIdentity , _itAttachment :: Maybe ItAttachment , _itID :: Maybe Int , _itEffect :: ItEffect , _itInvDisplay :: Item -> String , _itInvColor :: Color , _itTargeting :: Maybe (World -> Maybe Point2, Int -> Item -> Creature -> World -> Picture) , _itWorldTrigger :: Maybe (Int -> World -> Bool) , _itAimStance :: AimStance } | Consumable { _itName :: String , _itMaxStack :: Int , _itAmount :: Int , _cnEffect :: Int -> World -> Maybe World , _itFloorPict :: Picture , _itEquipPict :: Creature -> Int -> Picture , _itIdentity :: ItemIdentity , _itID :: Maybe Int , _itInvDisplay :: Item -> String , _itInvColor :: Color , _itEffect :: ItEffect , _itHammer :: HammerPosition , _itAimStance :: AimStance } | Craftable { _itName :: String , _itMaxStack :: Int , _itAmount :: Int , _itFloorPict :: Picture , _itEquipPict :: Creature -> Int -> Picture , _itIdentity :: ItemIdentity , _itID :: Maybe Int , _itInvDisplay :: Item -> String , _itInvColor :: Color , _itAimStance :: AimStance } | Equipment { _itName :: String , _itMaxStack :: Int , _itAmount :: Int , _itFloorPict :: Picture , _itEquipPict :: Creature -> Int -> Picture , _itIdentity :: ItemIdentity , _itEffect :: ItEffect , _itID :: Maybe Int , _itAimingSpeed :: Float , _itAimingRange :: Float , _itZoom :: ItZoom , _itInvDisplay :: Item -> String , _itInvColor :: Color , _itHammer :: HammerPosition , _itAimStance :: AimStance } | Throwable { _itName :: String , _itMaxStack :: Int , _itAmount :: Int , _itFloorPict :: Picture , _twMaxRange :: Float , _twAccuracy :: Float , _itUse :: Item -> Creature -> World -> World , _itUseRate :: Int , _itUseTime :: Int , _itAimingSpeed :: Float , _itAimingRange :: Float , _itZoom :: ItZoom , _itEquipPict :: Creature -> Int -> Picture , _itIdentity :: ItemIdentity , _itID :: Maybe Int , _itAttachment :: Maybe ItAttachment , _itInvDisplay :: Item -> String , _itInvColor :: Color , _itEffect :: ItEffect , _itHammer :: HammerPosition , _itScrollUp :: Int -> World -> World , _itScrollDown :: Int -> World -> World , _itAimStance :: AimStance } | NoItem data ItEffect = NoItEffect | ItInvEffect {_itInvEffect :: ItEffect -> Creature -> Int -> World -> World -- the Int is the items inventory position ,_itEffectCounter :: Int } | ItEffect {_itInvEffect :: ItEffect -> Creature -> Int -> World -> World ,_itFloorEffect :: Int -> World -> World ,_itEffectCounter :: Int } data ItZoom = ItZoom {_itAimZoomMax :: Float ,_itAimZoomMin :: Float ,_itAimZoomFac :: Float ,_itZoomMax :: Float ,_itZoomMin :: Float ,_itZoomFac :: Float } data IntID a = IntID Int a {- Objects without ids. Update themselves, perhaps with side effects. -} data Particle = Particle { _ptDraw :: Particle -> Picture , _ptUpdate' :: World -> Particle -> (World, Maybe Particle) } | LinearParticle { _ptDraw :: Particle -> Picture , _ptUpdate' :: World -> Particle -> (World, Maybe Particle) , _ptPoints :: [Point2] , _ptTimer :: Int , _ptColor :: Color } | Bul' { _ptDraw :: Particle -> Picture , _ptUpdate' :: World -> Particle -> (World, Maybe Particle) , _btVel' :: Point2 , _btColor' :: Color , _btTrail' :: [Point2] , _btPassThrough' :: Maybe Int , _btWidth' :: Float , _btTimer' :: Int , _btHitEffect' :: HitEffect } | Pt' { _ptDraw :: Particle -> Picture , _ptUpdate' :: World -> Particle -> (World, Maybe Particle) , _btVel' :: Point2 , _btColor' :: Color , _btPos' :: Point2 , _btPassThrough' :: Maybe Int , _btWidth' :: Float , _btTimer' :: Int , _btHitEffect' :: HitEffect } | Shockwave' { _ptDraw :: Particle -> Picture , _ptUpdate' :: World -> Particle -> (World, Maybe Particle) , _btColor' :: Color , _btPos' :: Point2 , _btRad' :: Float , _btDam' :: Int , _btPush' :: Float , _btMaxTime' :: Int , _btTimer' :: Int } type HitEffect = Particle -> [(Point2, Either3 Creature Wall ForceField)] -> World -> (World,Maybe Particle) data Ammo = ShellAmmo { _amPayload :: Point2 -> World -> World , _amString :: String , _amPjParams :: [PjParam] , _amPjDraw :: Projectile -> Picture , _amParamSel :: Int } | BulletAmmo { _amString :: String , _amBulEff :: HitEffect , _amBulWth :: Float , _amBulVel :: Point2 } | GenericAmmo data PjParam = PjParam { _pjMoveParam :: Int -> Item -> Creature -> Projectile -> World -> World , _pjIntParam :: Int , _pjMaxParam :: Int , _pjDisplayParam :: Int -> String } data Projectile = Projectile { _pjPos :: Point2 , _pjStartPos :: Point2 , _pjVel :: Point2 , _pjDraw :: Projectile -> Picture , _pjID :: Int , _pjUpdate :: Projectile -> World -> World } | Shell { _pjPos :: Point2 , _pjStartPos :: Point2 , _pjVel :: Point2 , _pjAcc :: Point2 , _pjDir :: Float , _pjSpin :: Float , _pjDraw :: Projectile -> Picture , _pjID :: Int , _pjUpdate :: Projectile -> World -> World , _pjPayload :: Point2 -> World -> World , _pjTimer :: Int } | LinearShockwave { _pjDraw :: Projectile -> Picture , _pjID :: Int , _pjUpdate :: Projectile -> World -> World , _pjPoints :: [(Point2,Point2)] , _pjTimer :: Int } data Either3 a b c = E3x1 a | E3x2 b | E3x3 c data Wall = Wall { _wlLine :: (Point2,Point2) , _wlID :: Int , _wlColor :: Color , _wlSeen :: Bool , _wlIsSeeThrough :: Bool } | BlockAutoDoor { _wlLine :: (Point2,Point2) , _wlID :: Int , _doorMech :: World -> World , _wlColor :: Color , _wlSeen :: Bool , _blIDs :: [Int] , _blHP :: Int , _wlIsSeeThrough :: Bool } | Door { _wlLine :: (Point2,Point2) , _wlID :: Int , _doorMech :: World -> World , _wlColor :: Color , _wlSeen :: Bool , _wlIsSeeThrough :: Bool , _doorPathable :: Bool , _drPositions :: DS.DS (Point2,Point2) } | Block { _wlLine :: (Point2,Point2) , _wlID :: Int , _wlColor :: Color , _wlSeen :: Bool , _blIDs :: [Int] , _blHP :: Int , _wlIsSeeThrough :: Bool , _blVisible :: Bool , _blDegrades :: [Int] , _blShadows :: [Int] } data ForceField = FF { _ffLine :: [Point2] , _ffID :: Int , _ffColor :: Color , _ffDeflect :: Maybe (StdGen -> Point2 -> ForceField -> (Point2,StdGen)) , _ffState :: FFState } data FFState = FFDestroyable { _ffsHP :: Int } data ActionPlan = Inanimate | ActionPlan {_crImpulse :: [Impulse] ,_crAction :: [Action] ,_crStrategy :: Strategy ,_crGoal :: [Goal] } data Impulse = Move Point2 | MoveForward Float | StepForward | Turn Float | RandomTurn Float | TurnToward Point2 Float | TurnTo Point2 | UseItem | SwitchToItem Int | DropItem | PickupNearby Int | UseWorldObject Int | Bark -- placeholder for various communication types | UseIntrinsicAbility | Melee Int | ChangePosture Posture | MakeSound Int | ChangeStrategy Strategy | AddGoal Goal | ArbitraryImpulseFunction (World -> Creature -> Creature) | ArbitraryImpulse (Creature -> World -> Impulse) | ImpulseUseTargetCID {_impulseUseTargetCID :: Int -> Impulse } | ImpulseUseTarget {_impulseUseTarget :: Creature -> Impulse } | ImpulseUseAheadPos {_impulseUseAheadPos :: Point2 -> Impulse } -- deriving (Eq,Ord,Show) infixr 9 `WaitThen` infixr 9 `DoActionThen` infixr 9 `DoActionWhile` infixr 9 `DoReplicate` infixr 9 `DoImpulsesAlongside` data Action = Attack {_attackTargetID :: Int} | AimAtCloseSlow {_targetID :: Int ,_targetSeenAt :: Point2 ,_aimSpeed :: Float ,_slowAimSpeed :: Float ,_slowAimAngle :: Float } | MeleeAttack {_meleeAttackLastSeen :: Point2 ,_meleeAttackTargetID :: Int } | PathTo {_pathToPoint :: Point2 } | HealSelf | DefendSelf | Protect {_protectCID :: Int } | SearchFor {_searchForCID :: Int } | Search | PickupItem {_pickupItemID :: Int } | ImpulsesList {_impulsesListList :: [[Impulse]] } | DoImpulses {_doImpulsesList :: [Impulse] } | WaitThen {_waitThenTimer :: Int ,_waitThenAction :: Action } | DoActionWhile {_doActionWhileCondition :: (World, Creature) -> Bool ,_doActionWhileAction :: Action } | DoActionWhilePartial {_doActionWhilePartial :: Action ,_doActionWhileCondition :: (World, Creature) -> Bool ,_doActionWhileAction :: Action } | DoActionIf {_doActionIfCondition :: (World, Creature) -> Bool ,_doActionIfAction :: Action } | DoActionIfElse {_doActionIfElseIfAction :: Action ,_doActionIfElseCondition :: (World, Creature) -> Bool ,_doActionIfElseElseAction :: Action } | DoActionWhileInterrupt {_doActionWhileThenDo :: Action ,_doActionWhileThenCondition :: (World, Creature) -> Bool ,_doActionWhileThenThen :: Action } | DoActions {_doActionsList :: [Action] } | DoActionOnce {_doActionOnceAction :: Action } | DoActionThen {_doActionThenFirst :: Action ,_doActionThenSecond :: Action } | DoGuardActions {_doGuardActionsList :: [( (World, Creature) -> Bool, Action, Maybe Action)] } | DoReplicate {_doReplicateTimes :: Int ,_doReplicateAction :: Action } | DoReplicatePartial {_partialAction :: Action ,_doReplicateTimes :: Int ,_doReplicateAction :: Action } | LeadTarget {_leadTargetBy :: Point2 } | NoAction | StartSentinelPost | UseTarget {_useTarget :: Maybe Creature -> Action } | UseTargetCID {_useTargetCID :: Int -> Action } | UseSelf {_useSelf :: Creature -> Action } | UseAheadPos {_useAheadPos :: Point2 -> Action } | ArbitraryAction { _arbitraryAction :: Creature -> World -> Action } | DoActionAlongside -- ^ Repeatedly perform a side action alongside a main action until the main action terminates {_sideAction :: Action ,_mainAction :: Action } | DoImpulsesAlongside -- ^ Repeatedly perform impulses alongside a main action until the main action terminates {_sideImpulses :: [Impulse] ,_mainAction :: Action } deriving (Generic) -- deriving (Eq,Ord,Show) data Strategy = Flank Int | Ambush Int | Lure Int Point2 | Patrol [Point2] | ShootAt Int | FollowImpulses | WatchAndWait | StrategyActions Strategy [Action] | GetTo Point2 | Reload | Flee | MeleeStrike deriving (Generic) -- deriving (Eq,Ord,Show) data Goal = LiveLongAndProsper | Kill Int | SentinelAt Point2 Float makeLenses ''World makeLenses ''Cloud makeLenses ''Creature makeLenses ''LightSource makeLenses ''TempLightSource makeLenses ''Item makeLenses ''ItemPos makeLenses ''ItEffect makeLenses ''ItZoom makeLenses ''FloorItem makeLenses ''Ammo makeLenses ''PjParam makeLenses ''Projectile makeLenses ''Particle makeLenses ''Wall makeLenses ''ForceField makeLenses ''FFState makeLenses ''PressPlate makeLenses ''Button makeLenses ''ActionPlan makeLenses ''Impulse makeLenses ''Action makeLenses ''CrGroupParams numColor :: Int -> Color numColor 0 = (1,0,0,1) numColor 1 = (0,1,0,1) numColor 2 = (0,0,1,1) numColor 3 = (1,1,0,1) numColor 4 = (0,1,1,1) numColor 5 = (1,0,1,1) numColor 6 = (1,0,0.5,1) numColor 7 = (0.5,0,1,1) numColor 8 = (0,0.5,1,1) numColor 9 = (0,1,0.5,1) numColor 10 = (0.5,1,0,1) numColor 11 = (1,0.5,0,1) numColor 12 = (1,1,1,1) numColor _ = (1,1,1,1)