Files
loop/src/Dodge/WorldEffect.hs
T
2026-04-01 11:45:25 +01:00

174 lines
6.8 KiB
Haskell

{-# LANGUAGE LambdaCase #-}
module Dodge.WorldEffect (
doWdWd,
accessTerminal,
doTmWdWd,
) where
import Dodge.Item.MaxAmmo
import ShortShow
import Data.Traversable (mapAccumR)
import Dodge.Item.MagAmmoType
import qualified Data.IntSet as IS
import Dodge.Data.AmmoType
import Color
import Dodge.Terminal
import NewInt
import Control.Monad
import Data.Foldable
import qualified Data.Map.Strict as M
import Data.Maybe
import Dodge.BlBl
import Dodge.Creature.Impulse.UseItem
import Dodge.Data.Terminal.Status
import Dodge.Data.World
import Dodge.HeldUse
import Dodge.Inventory.Lock
import Dodge.Item.Grammar
import Dodge.SoundLogic
import Dodge.WorldEvent.Cloud
import qualified IntMapHelp as IM
import LensHelp
import System.Random
doWdWd :: WdWd -> World -> World
doWdWd = \case
NoWorldEffect -> id
SetTrigger bool tid -> cWorld . lWorld . triggers . ix tid .~ bool
SetLSCol col lsid -> cWorld . lWorld . lightSources . ix lsid . lsParam . lsCol .~ col
SetTriggerAndSetLSCol bool tid col lsid -> (cWorld . lWorld . lightSources . ix lsid . lsParam . lsCol .~ col)
. (cWorld . lWorld . triggers . ix tid .~ bool)
AccessTerminal mtmid -> accessTerminal mtmid
UnlockInv -> unlockInv
MakeStartCloudAt p -> makeCloudAt CryoReleaseCloud 400 p
TorqueCr x cid -> torqueCr x cid
SoundStart so p sid mi -> soundStart so p sid mi
WdWdNegateTrig trid -> cWorld . lWorld . triggers . ix trid %~ not
WdWdSetSoundFilter x -> wSoundFilter .~ x
MakeTempLight _ 0 -> id
MakeTempLight x t ->
(cWorld . lWorld . lights .:~ x)
. (cWorld . lWorld . worldEvents .:~ MakeTempLight x (t -1))
MakeTempLightFade _ _ 0 -> id
MakeTempLightFade y x t ->
(cWorld . lWorld . lights .:~ x)
. (cWorld . lWorld . worldEvents
.:~ MakeTempLightFade y (x&lsCol . each -~ y) (t -1))
UseInvItem invid pt -> \w -> fromMaybe w (useItem invid pt w)
WdWdBurstFireRepetition cid invid -> \w -> fromMaybe w $ do
cr <- w ^? cWorld . lWorld . creatures . ix cid
loc <- invIndents (fmap (\k -> w ^?! cWorld . lWorld . items . ix k) $ cr ^. crInv) ^? ix (_unNInt invid) . _2
return $ heldEffectMuzzles loc cr w
accessTerminal :: Int -> World -> World
accessTerminal tid w = fromMaybe w $ do
tm <- w ^? cWorld . lWorld . terminals . ix tid
guard (tm ^. tmStatus /= TerminalDeactivated)
return $
w & hud . subInventory .~ DisplayTerminal tid
& cWorld . lWorld . terminals . ix tid %~ tryToBoot
where
tryToBoot tm = case _tmStatus tm of
_ | tm ^. tmRebootOnAccess -> tm
& tmFutureLines .~ _tmBootLines tm
& tmStatus .~ TerminalLineRead
TerminalTextInput{} -> tm
TerminalLineRead -> tm
TerminalPressTo{} -> tm
TerminalOff ->
tm
& tmFutureLines .~ _tmBootLines tm
& tmStatus .~ TerminalLineRead
TerminalDeactivated -> error "managed to boot a deactivated terminal"
torqueCr :: Float -> Int -> World -> World
torqueCr x cid w
| cid == 0 = set randGen g $ over (wCam . camRot) (+ rot) w
| otherwise = set randGen g $ over (cWorld . lWorld . creatures . ix cid . crDir) (+ rot) w
where
(rot, g) = randomR (- x, x) $ _randGen w
doDeathTriggers :: Terminal -> World -> World
doDeathTriggers tm =
(cWorld . lWorld . triggers %~ flip (foldl' $ flip doDeathToggle) xs)
. (cWorld . lWorld . terminals . ix (tm ^. tmID) . tmStatus .~ TerminalDeactivated)
where
xs = M.elems $ _tmToggles tm
doDeathToggle :: TerminalToggle -> IM.IntMap Bool -> IM.IntMap Bool
doDeathToggle (TerminalToggle trid f) = ix trid %~ doBlBl f
doTmWdWd :: TmWdWd -> Terminal -> World -> World
doTmWdWd = \case
TmTmClearDisplayedLines -> \tm ->
cWorld . lWorld . terminals . ix (tm ^. tmID) . tmDisplayedLines .~ []
TmTmSetStatus x -> \tm -> cWorld . lWorld . terminals . ix (tm ^. tmID) . tmStatus .~ x
TmWdId -> const id
TmWdWdPowerDownTerminal -> resetTerminal TerminalOff
TmWdWdDeactivateTerminal -> resetTerminal TerminalDeactivated
TmWdWdLeaveTerminal s -> leaveResetQuitTerminal s
TmWdWdTermSound sid -> \tm w -> fromMaybe w $ do
tpos <- w ^? cWorld . lWorld . buttons . ix (_tmButtonID tm) . btPos
return $ soundStart TerminalSound tpos sid Nothing w
TmWdWdDoDeathTriggers -> doDeathTriggers
TmWdWdfromWdWd f -> \_ -> doWdWd f
TmDistributeAmmo -> tmDistributeAmmo
tmDistributeAmmo :: Terminal -> World -> World
tmDistributeAmmo tm w = fromMaybe w $ do
let mid = tm ^. tmMachineID
sid <- w ^? cWorld . lWorld . machines . ix mid
. mcType . mcdStorageMachine . _Just
McStorage atype aamount <- w ^? cWorld . lWorld . machines . ix sid . mcType
let (newaamount,w') = distributeAmmoToYou atype aamount w
return $ w'
& cWorld . lWorld . machines . ix sid . mcType . mcsAmount .~ newaamount
& cWorld . lWorld . terminals . ix (tm ^. tmID) . tmFutureLines .~
[TLine 1 [TerminalLineConst (g (aamount - newaamount)) white] TmWdId
,TLine 1 [TerminalLineConst (shortShow newaamount <>" "<>show atype<>" AVAILABLE") white] TmWdId
,TLine 1 [] (TmWdWdTermSound (getsid (aamount - newaamount)))
]
where
getsid x | x > 0 = reloadS
| otherwise = reloadFailS
g 0 = "NO SUITABLE RECIPIENTS"
g _ = "SUCCESFUL"
distributeAmmoToYou :: AmmoType -> Int -> World -> (Int,World)
distributeAmmoToYou atype x w = fromMaybe (0,w) $ do
is <- fmap IM.elems $ w ^? cWorld . lWorld . creatures . ix 0 . crInv . unNIntMap
let itms = IM.filter (\itm -> magAmmoType itm == Just atype) $
IM.restrictKeys (w ^. cWorld . lWorld . items) (IS.fromList is)
(x',itmams) = mapAccumR distributeAmmoToItem x itms
return (x', IM.foldlWithKey' f w itmams)
where
f w' _ 0 = w'
f w' i y = w' & cWorld . highlightItems . at i ?~ 20
& cWorld . lWorld . items . ix i . itConsumables . _Just +~ y
distributeAmmoToItem :: Int -> Item -> (Int,Int)
distributeAmmoToItem x itm = fromMaybe (x,0) $ do
m <- maxAmmo itm
cur <- itm ^. itConsumables
let d = m - cur
t = max 0 $ min x d
return (x-t,t)
resetTerminal :: TerminalStatus -> Terminal -> World -> World
resetTerminal x tm =
(cWorld . lWorld . terminals . ix (_tmID tm) . tmStatus .~ x)
. (cWorld . lWorld . terminals . ix (_tmID tm) . tmDisplayedLines .~ [])
. exitTerminalSubInv
leaveResetQuitTerminal :: String -> Terminal -> World -> World
leaveResetQuitTerminal s tm =
(cWorld . lWorld . terminals . ix (_tmID tm) . tmFutureLines
.~ tlSetStatus (TerminalPressTo s) <> tlDoEffect (TmWdWdLeaveTerminal s))
. exitTerminalSubInv
exitTerminalSubInv :: World -> World
exitTerminalSubInv w = case w ^? hud . subInventory . termID of
Just _ -> w & hud . subInventory .~ NoSubInventory
_ -> w