Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

robot background passthrough #1672

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/swarm-scenario/Swarm/Game/Display.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module Swarm.Game.Display (
boundaryOverride,
displayAttr,
displayPriority,
displayObscured,
invisible,
childInheritance,

Expand Down Expand Up @@ -98,6 +99,7 @@ data Display = Display
, _boundaryOverride :: Maybe Char
, _displayAttr :: Attribute
, _displayPriority :: Priority
, _displayObscured :: Bool
, _invisible :: Bool
, _childInheritance :: ChildInheritance
}
Expand Down Expand Up @@ -134,6 +136,11 @@ displayAttr :: Lens' Display Attribute
-- on top of lower.
displayPriority :: Lens' Display Priority

-- | True for static "fog of war" overlay. This field is a workaround to allow
-- robot-occupied cells to take on ambient background; it distinguishes
-- displays that have an adoptable background from displays that do not.
displayObscured :: Lens' Display Bool

-- | Whether the entity is currently invisible.
invisible :: Lens' Display Bool

Expand All @@ -157,6 +164,7 @@ instance FromJSONE Display Display where
liftE $ do
let _defaultChar = c
_boundaryOverride = Nothing
_displayObscured = False
_orientationMap <- v .:? "orientationMap" .!= dOM
_curOrientation <- v .:? "curOrientation" .!= (defD ^. curOrientation)
_displayAttr <- (v .:? "attr") .!= (defD ^. displayAttr)
Expand Down Expand Up @@ -220,6 +228,7 @@ defaultEntityDisplay c =
, _boundaryOverride = Nothing
, _displayAttr = AEntity
, _displayPriority = 1
, _displayObscured = False
, _invisible = False
, _childInheritance = Inherit
}
Expand All @@ -245,6 +254,7 @@ defaultRobotDisplay =
, _curOrientation = Nothing
, _displayAttr = ARobot
, _displayPriority = 10
, _displayObscured = False
, _invisible = False
, _childInheritance = Inherit
}
Expand Down
84 changes: 72 additions & 12 deletions src/swarm-tui/Swarm/TUI/View/CellDisplay.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Swarm.TUI.View.CellDisplay where

import Brick
import Control.Lens (to, view, (&), (.~), (^.))
import Control.Monad (guard)
import Data.ByteString (ByteString)
import Data.Hash.Murmur
import Data.List.NonEmpty qualified as NE
Expand All @@ -27,14 +28,19 @@ import Swarm.Game.Display (
defaultEntityDisplay,
displayAttr,
displayChar,
displayObscured,
displayPriority,
getBoundaryDisplay,
hidden,
invisible,
)
import Swarm.Game.Entity
import Swarm.Game.Entity.Cosmetic
import Swarm.Game.Land
import Swarm.Game.Location (Point (..), toHeading)
import Swarm.Game.Robot
import Swarm.Game.Scenario (scenarioCosmetics, scenarioLandscape)
import Swarm.Game.Scenario.Topography.Cell (CellPaintDisplay, PCell (..))
import Swarm.Game.Scenario.Topography.EntityFacade
import Swarm.Game.Scenario.Topography.Structure.Recognition (foundStructures)
import Swarm.Game.Scenario.Topography.Structure.Recognition.Registry (foundByLocation)
Expand All @@ -55,24 +61,40 @@ import Swarm.TUI.Model.Name
import Swarm.TUI.Model.UI.Gameplay
import Swarm.TUI.View.Attribute.Attr
import Swarm.Util (applyWhen)
import Swarm.Util.Content (getContentAt)
import Swarm.Util.Content (getContentAt, getTerrainEntityColor)
import Swarm.Util.Erasable (maybeToErasable)
import Witch (from)
import Witch.Encoding qualified as Encoding

-- | Render a display as a UI widget.
renderDisplay :: Display -> Widget n
renderDisplay disp = withAttr (disp ^. displayAttr . to toAttrName) $ str [displayChar disp]

-- | Returns the background color of either the terrain or
-- any entity in this cell that specifies a background color.
getCellBackground :: UIGameplay -> CellPaintDisplay -> Maybe V.Color
getCellBackground ui mycell = do
(myScenario, _) <- ui ^. scenarioRef
hifi <- getTerrainEntityColor (myScenario ^. scenarioLandscape . scenarioCosmetics) mycell
getBackground $ fmap mkBrickColor hifi

-- | Render the 'Display' for a specific location.
drawLoc :: UIGameplay -> GameState -> Cosmic Coords -> Widget Name
drawLoc ui g cCoords@(Cosmic _ coords) =
if shouldHideWorldCell ui coords
then str " "
else boldStructure drawCell
else boldStructure $ passthroughBackgroundForRobot drawCell
where
showRobots = ui ^. uiShowRobots
we = ui ^. uiWorldEditor . worldOverdraw
drawCell = renderDisplay $ displayLoc showRobots we g cCoords

(combinedDisplay, maybeBgForRobot) = displayLoc ui showRobots we g cCoords
drawCell = renderDisplay combinedDisplay

passthroughBackgroundForRobot =
case maybeBgForRobot of
Just c -> modifyDefAttr (`V.withBackColor` c)
Nothing -> id

boldStructure = applyWhen isStructure $ modifyDefAttr (`V.withStyle` V.bold)
where
Expand Down Expand Up @@ -145,7 +167,7 @@ displayEntityCell ::
Cosmic Coords ->
[Display]
displayEntityCell worldEditor ri coords =
maybeToList $ assignBoundaryOverride . displayForEntity <$> maybeEntityPaint
maybeToList $ assignBoundaryOverride . displayForEntity ri <$> maybeEntityPaint
where
maybeEntityPaint = getEntPaintAtCoord coords

Expand All @@ -160,29 +182,66 @@ displayEntityCell worldEditor ri coords =
offsettedCoord = (`addTuple` xy) <$> coords
Coords xy = locToCoords $ P $ toHeading d

displayForEntity :: EntityPaint -> Display
displayForEntity e = applyWhen (not $ isKnownFunc ri e) hidden $ getDisplay e
displayForEntity :: RenderingInput -> EntityPaint -> Display
displayForEntity ri e = applyWhen (not $ isKnownFunc ri e) hidden $ getDisplay e

-- | Get the 'Display' for a specific location, by combining the
-- 'Display's for the terrain, entity, and robots at the location, and
-- taking into account "static" based on the distance to the robot
-- being @view@ed.
displayLoc :: Bool -> WorldOverdraw -> GameState -> Cosmic Coords -> Display
displayLoc showRobots we g cCoords@(Cosmic _ coords) =
staticDisplay g coords
<> displayLocRaw we ri robots cCoords
--
-- In case a robot occupies the cell, propagates the background color
-- that should be displayed "underneath" the robot.
displayLoc ::
UIGameplay ->
-- | Should show robots
Bool ->
WorldOverdraw ->
GameState ->
Cosmic Coords ->
(Display, Maybe V.Color)
displayLoc ui showRobots we g cCoords@(Cosmic _ coords) =
(combinedDisplay, maybeRobotPassthroughBg)
where
ri =
RenderingInput
(g ^. landscape . multiWorld)
(getEntityIsKnown $ mkEntityKnowledge g)
(g ^. landscape . terrainAndEntities . terrainMap)
tm

robots =
combinedDisplay =
staticDisplay g coords
<> terrainEntityRobotDisplay

tm = g ^. landscape . terrainAndEntities . terrainMap
(terrain, maybeEntity) =
EU.getEditorContentAt
tm
we
(multiworldInfo ri)
cCoords

hasVisibleRobot =
not (combinedDisplay ^. displayObscured)
&& not (all (view invisible) robotDisplays)

cellPaint =
Cell
terrain
(toFacade <$> maybeToErasable maybeEntity)
[]

maybeRobotPassthroughBg = do
guard hasVisibleRobot
getCellBackground ui cellPaint

robotDisplays =
if showRobots
then displayRobotCell g cCoords
else []

terrainEntityRobotDisplay = displayLocRaw we ri robotDisplays cCoords

-- | Get the 'Display' for a specific location, by combining the
-- 'Display's for the terrain, entity, and robots at the location.
displayLocRaw ::
Expand Down Expand Up @@ -210,6 +269,7 @@ displayStatic s =
defaultEntityDisplay (staticChar s)
& displayPriority .~ maxBound -- Static has higher priority than anything else
& displayAttr .~ AEntity
& displayObscured .~ True

-- | Given a value from 0--15, considered as 4 bits, pick the
-- character with the corresponding quarter pixels turned on.
Expand Down
Loading