private void HandlePuddleExamined(EntityUid uid, PuddleComponent component, ExaminedEvent args)
 {
     if (EntityManager.TryGetComponent <SlipperyComponent>(uid, out var slippery) && slippery.Slippery)
     {
         args.PushText(Loc.GetString("puddle-component-examine-is-slipper-text"));
     }
 }
 private void OnAnchorChanged(EntityUid uid, PuddleComponent puddle, ref AnchorStateChangedEvent args)
 {
     if (!args.Anchored)
     {
         QueueDel(uid);
     }
 }
Exemplo n.º 3
0
 private void HandlePuddleExamined(EntityUid uid, PuddleComponent component, ExaminedEvent args)
 {
     if (TryComp <StepTriggerComponent>(uid, out var slippery) && slippery.Active)
     {
         args.PushText(Loc.GetString("puddle-component-examine-is-slipper-text"));
     }
 }
        /// <summary>
        /// Tries to get an adjacent coordinate to overflow to, unless it is blocked by a wall on the
        /// same tile or the tile is empty
        /// </summary>
        /// <param name="puddleComponent"></param>
        /// <param name="direction">The direction to get the puddle from, respective to this one</param>
        /// <param name="puddle">The puddle that was found or is to be created, or null if there
        /// is a wall in the way</param>
        /// <returns>true if a puddle was found or created, false otherwise</returns>
        private bool TryGetAdjacentOverflow(PuddleComponent puddleComponent, Direction direction,
                                            [NotNullWhen(true)] out Func <PuddleComponent>?puddle)
        {
            puddle = default;

            // We're most likely in space, do nothing.
            if (!EntityManager.GetComponent <TransformComponent>(puddleComponent.Owner).GridID.IsValid())
            {
                return(false);
            }

            var mapGrid = _mapManager.GetGrid(EntityManager.GetComponent <TransformComponent>(puddleComponent.Owner).GridID);
            var coords  = EntityManager.GetComponent <TransformComponent>(puddleComponent.Owner).Coordinates;

            if (!coords.Offset(direction).TryGetTileRef(out var tile))
            {
                return(false);
            }

            // If space return early, let that spill go out into the void
            if (tile.Value.Tile.IsEmpty)
            {
                return(false);
            }

            if (!EntityManager.GetComponent <TransformComponent>(puddleComponent.Owner).Anchored)
            {
                return(false);
            }

            foreach (var entity in mapGrid.GetInDir(coords, direction))
            {
                if (EntityManager.TryGetComponent(entity, out IPhysBody? physics) &&
                    (physics.CollisionLayer & (int)CollisionGroup.Impassable) != 0)
                {
                    puddle = default;
                    return(false);
                }

                if (EntityManager.TryGetComponent(entity, out PuddleComponent? existingPuddle))
                {
                    if (existingPuddle.Overflown)
                    {
                        return(false);
                    }

                    puddle = () => existingPuddle;
                }
            }

            puddle ??= () =>
            {
                var id = EntityManager.SpawnEntity(
                    EntityManager.GetComponent <MetaDataComponent>(puddleComponent.Owner).EntityPrototype?.ID,
                    mapGrid.DirectionToGrid(coords, direction));
                return(EntityManager.GetComponent <PuddleComponent>(id));
            };

            return(true);
        }
Exemplo n.º 5
0
        private void UpdateVisuals(EntityUid uid, PuddleComponent puddleComponent)
        {
            if (Deleted(puddleComponent.Owner) || EmptyHolder(uid, puddleComponent) ||
                !EntityManager.TryGetComponent <AppearanceComponent>(uid, out var appearanceComponent))
            {
                return;
            }

            // Opacity based on level of fullness to overflow
            // Hard-cap lower bound for visibility reasons
            var volumeScale    = puddleComponent.CurrentVolume.Float() / puddleComponent.OverflowVolume.Float() * puddleComponent.OpacityModifier;
            var puddleSolution = _solutionContainerSystem.EnsureSolution(uid, puddleComponent.SolutionName);


            bool hasEvaporationComponent = EntityManager.TryGetComponent <EvaporationComponent>(uid, out var evaporationComponent);
            bool canEvaporate            = (hasEvaporationComponent &&
                                            (evaporationComponent !.LowerLimit == 0 || puddleComponent.CurrentVolume > evaporationComponent.LowerLimit));

            // "Does this puddle's sprite need changing to the wet floor effect sprite?"
            bool changeToWetFloor = (puddleComponent.CurrentVolume <= puddleComponent.WetFloorEffectThreshold &&
                                     canEvaporate);

            appearanceComponent.SetData(PuddleVisuals.VolumeScale, volumeScale);
            appearanceComponent.SetData(PuddleVisuals.SolutionColor, puddleSolution.Color);
            appearanceComponent.SetData(PuddleVisuals.ForceWetFloorSprite, changeToWetFloor);
        }
        private void OnUnanchored(EntityUid uid, PuddleComponent puddle, UnanchoredEvent unanchoredEvent)
        {
            if (!puddle.Owner.Transform.Anchored)
                return;

            puddle.Owner.QueueDelete();
        }
Exemplo n.º 7
0
        private void OnUnanchored(EntityUid uid, PuddleComponent puddle, UnanchoredEvent unanchoredEvent)
        {
            if (!EntityManager.GetComponent <TransformComponent>(puddle.Owner).Anchored)
            {
                return;
            }

            EntityManager.QueueDeleteEntity(puddle.Owner);
        }
        /// <summary>
        /// Will overflow this entity to neighboring entities if required
        /// </summary>
        private void CheckOverflow(PuddleComponent puddleComponent)
        {
            if (puddleComponent.CurrentVolume <= puddleComponent.OverflowVolume ||
                puddleComponent.Overflown)
            {
                return;
            }

            var nextPuddles = new List <PuddleComponent>()
            {
                puddleComponent
            };
            var overflownPuddles = new List <PuddleComponent>();

            while (puddleComponent.OverflowLeft > FixedPoint2.Zero && nextPuddles.Count > 0)
            {
                foreach (var next in nextPuddles.ToArray())
                {
                    nextPuddles.Remove(next);

                    next.Overflown = true;
                    overflownPuddles.Add(next);

                    var adjacentPuddles = GetAllAdjacentOverflow(next).ToArray();
                    if (puddleComponent.OverflowLeft <= FixedPoint2.Epsilon * adjacentPuddles.Length)
                    {
                        break;
                    }

                    if (adjacentPuddles.Length == 0)
                    {
                        continue;
                    }

                    var numberOfAdjacent = FixedPoint2.New(adjacentPuddles.Length);
                    var overflowSplit    = puddleComponent.OverflowLeft / numberOfAdjacent;
                    foreach (var adjacent in adjacentPuddles)
                    {
                        var adjacentPuddle = adjacent();
                        var quantity       = FixedPoint2.Min(overflowSplit, adjacentPuddle.OverflowVolume);
                        var puddleSolution = _solutionContainerSystem.EnsureSolution(puddleComponent.Owner,
                                                                                     puddleComponent.SolutionName);
                        var spillAmount = _solutionContainerSystem.SplitSolution(puddleComponent.Owner,
                                                                                 puddleSolution, quantity);

                        TryAddSolution(adjacentPuddle.Owner, spillAmount, false, false);
                        nextPuddles.Add(adjacentPuddle);
                    }
                }
            }

            foreach (var puddle in overflownPuddles)
            {
                puddle.Overflown = false;
            }
        }
 /// <summary>
 /// Finds or creates adjacent puddles in random directions from this one
 /// </summary>
 /// <returns>Enumerable of the puddles found or to be created</returns>
 private IEnumerable <Func <PuddleComponent> > GetAllAdjacentOverflow(PuddleComponent puddleComponent)
 {
     foreach (var direction in SharedDirectionExtensions.RandomDirections())
     {
         if (TryGetAdjacentOverflow(puddleComponent, direction, out var puddle))
         {
             yield return(puddle);
         }
     }
 }
Exemplo n.º 10
0
 private void UpdateSlip(EntityUid entityUid, PuddleComponent puddleComponent)
 {
     if ((puddleComponent.SlipThreshold == FixedPoint2.New(-1) ||
          puddleComponent.CurrentVolume < puddleComponent.SlipThreshold) &&
         EntityManager.TryGetComponent(entityUid, out SlipperyComponent? oldSlippery))
     {
         oldSlippery.Slippery = false;
     }
     else if (puddleComponent.CurrentVolume >= puddleComponent.SlipThreshold)
     {
         var newSlippery = EntityManager.EnsureComponent <SlipperyComponent>(entityUid);
         newSlippery.Slippery = true;
     }
 }
Exemplo n.º 11
0
 private void UpdateSlip(EntityUid entityUid, PuddleComponent puddleComponent)
 {
     if ((puddleComponent.SlipThreshold == FixedPoint2.New(-1) ||
          puddleComponent.CurrentVolume < puddleComponent.SlipThreshold) &&
         TryComp(entityUid, out StepTriggerComponent? stepTrigger))
     {
         _stepTrigger.SetActive(entityUid, false, stepTrigger);
     }
     else if (puddleComponent.CurrentVolume >= puddleComponent.SlipThreshold)
     {
         var comp = EnsureComp <StepTriggerComponent>(entityUid);
         _stepTrigger.SetActive(entityUid, true, comp);
     }
 }
Exemplo n.º 12
0
        private void UpdateVisuals(EntityUid uid, PuddleComponent puddleComponent)
        {
            if (Deleted(puddleComponent.Owner) || EmptyHolder(uid, puddleComponent) ||
                !EntityManager.TryGetComponent <AppearanceComponent>(uid, out var appearanceComponent))
            {
                return;
            }

            // Opacity based on level of fullness to overflow
            // Hard-cap lower bound for visibility reasons
            var volumeScale    = puddleComponent.CurrentVolume.Float() / puddleComponent.OverflowVolume.Float();
            var puddleSolution = _solutionContainerSystem.EnsureSolution(uid, puddleComponent.SolutionName);

            appearanceComponent.SetData(PuddleVisuals.VolumeScale, volumeScale);
            appearanceComponent.SetData(PuddleVisuals.SolutionColor, puddleSolution.Color);
        }
Exemplo n.º 13
0
        public async Task PuddlePauseTest()
        {
            var server = StartServer();

            await server.WaitIdleAsync();

            var sMapManager            = server.ResolveDependency <IMapManager>();
            var sPauseManager          = server.ResolveDependency <IPauseManager>();
            var sTileDefinitionManager = server.ResolveDependency <ITileDefinitionManager>();
            var sGameTiming            = server.ResolveDependency <IGameTiming>();
            var sEntityManager         = server.ResolveDependency <IEntityManager>();

            MapId             sMapId = default;
            IMapGrid          sGrid;
            GridId            sGridId      = default;
            IEntity           sGridEntity  = null;
            EntityCoordinates sCoordinates = default;

            // Spawn a paused map with one tile to spawn puddles on
            await server.WaitPost(() =>
            {
                sMapId = sMapManager.CreateMap();
                sPauseManager.SetMapPaused(sMapId, true);
                sGrid              = sMapManager.CreateGrid(sMapId);
                sGridId            = sGrid.Index;
                sGridEntity        = sEntityManager.GetEntity(sGrid.GridEntityId);
                sGridEntity.Paused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1444

                var tileDefinition = sTileDefinitionManager["underplating"];
                var tile           = new Tile(tileDefinition.TileId);
                sCoordinates       = sGrid.ToCoordinates();

                sGrid.SetTile(sCoordinates, tile);
            });

            // Check that the map and grid are paused
            await server.WaitAssertion(() =>
            {
                Assert.True(sPauseManager.IsGridPaused(sGridId));
                Assert.True(sPauseManager.IsMapPaused(sMapId));
                Assert.True(sGridEntity.Paused);
            });

            float           sEvaporateTime        = default;
            PuddleComponent sPuddle               = null;
            Solution        solution              = null;
            ReagentUnit     sPuddleStartingVolume = default;

            // Spawn a puddle
            await server.WaitAssertion(() =>
            {
                var solution = new Solution("water", ReagentUnit.New(20));
                sPuddle      = solution.SpillAt(sCoordinates, "PuddleSmear");

                // Check that the puddle was created
                Assert.NotNull(sPuddle);

                sPuddle.Owner.Paused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1445

                Assert.True(sPuddle.Owner.Paused);

                // Check that the puddle is going to evaporate
                Assert.Positive(sPuddle.EvaporateTime);

                // Should have a timer component added to it for evaporation
                Assert.True(sPuddle.Owner.TryGetComponent(out TimerComponent _));

                sEvaporateTime        = sPuddle.EvaporateTime;
                sPuddleStartingVolume = sPuddle.CurrentVolume;
            });

            // Wait enough time for it to evaporate if it was unpaused
            var sTimeToWait = (5 + (int)Math.Ceiling(sEvaporateTime * sGameTiming.TickRate)) * 2;
            await server.WaitRunTicks(sTimeToWait);

            // No evaporation due to being paused
            await server.WaitAssertion(() =>
            {
                Assert.True(sPuddle.Owner.Paused);
                Assert.True(sPuddle.Owner.TryGetComponent(out TimerComponent _));

                // Check that the puddle still exists
                Assert.False(sPuddle.Owner.Deleted);
            });

            // Unpause the map
            await server.WaitPost(() =>
            {
                sPauseManager.SetMapPaused(sMapId, false);
            });

            // Check that the map, grid and puddle are unpaused
            await server.WaitAssertion(() =>
            {
                Assert.False(sPauseManager.IsMapPaused(sMapId));
                Assert.False(sPauseManager.IsGridPaused(sGridId));
                Assert.False(sPuddle.Owner.Paused);

                // Check that the puddle still exists
                Assert.False(sPuddle.Owner.Deleted);
            });

            // Wait enough time for it to evaporate
            await server.WaitRunTicks(sTimeToWait);

            // Puddle evaporation should have ticked
            await server.WaitAssertion(() =>
            {
                // Check that the puddle is unpaused
                Assert.False(sPuddle.Owner.Paused);

                // Check that the puddle has evaporated some of its volume
                Assert.That(sPuddle.CurrentVolume, Is.LessThan(sPuddleStartingVolume));

                // If its new volume is zero it should have been deleted
                if (sPuddle.CurrentVolume == ReagentUnit.Zero)
                {
                    Assert.True(sPuddle.Deleted);
                }
            });
        }
Exemplo n.º 14
0
 private void OnUpdate(EntityUid uid, PuddleComponent component, SolutionChangedEvent args)
 {
     UpdateSlip(uid, component);
     UpdateVisuals(uid, component);
 }
Exemplo n.º 15
0
        private void OnInit(EntityUid uid, PuddleComponent component, ComponentInit args)
        {
            var solution = _solutionContainerSystem.EnsureSolution(uid, component.SolutionName);

            solution.MaxVolume = FixedPoint2.New(1000);
        }
Exemplo n.º 16
0
        public async Task PuddlePauseTest()
        {
            var server = StartServer();

            await server.WaitIdleAsync();

            var sMapManager            = server.ResolveDependency <IMapManager>();
            var sTileDefinitionManager = server.ResolveDependency <ITileDefinitionManager>();
            var sGameTiming            = server.ResolveDependency <IGameTiming>();
            var entityManager          = server.ResolveDependency <IEntityManager>();

            MapId             sMapId = default;
            IMapGrid          sGrid;
            GridId            sGridId      = default;
            EntityUid         sGridEntity  = default;
            EntityCoordinates sCoordinates = default;

            // Spawn a paused map with one tile to spawn puddles on
            await server.WaitPost(() =>
            {
                sMapId = sMapManager.CreateMap();
                sMapManager.SetMapPaused(sMapId, true);
                sGrid       = sMapManager.CreateGrid(sMapId);
                sGridId     = sGrid.Index;
                sGridEntity = sGrid.GridEntityId;
                entityManager.GetComponent <MetaDataComponent>(sGridEntity).EntityPaused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1444

                var tileDefinition = sTileDefinitionManager["underplating"];
                var tile           = new Tile(tileDefinition.TileId);
                sCoordinates       = sGrid.ToCoordinates();

                sGrid.SetTile(sCoordinates, tile);
            });

            // Check that the map and grid are paused
            await server.WaitAssertion(() =>
            {
                Assert.True(sMapManager.IsGridPaused(sGridId));
                Assert.True(sMapManager.IsMapPaused(sMapId));
            });

            float                evaporateTime = default;
            PuddleComponent      puddle        = null;
            MetaDataComponent    meta          = null;
            EvaporationComponent evaporation;

            var amount = 2;

            var entitySystemManager = server.ResolveDependency <IEntitySystemManager>();
            var spillSystem         = entitySystemManager.GetEntitySystem <SpillableSystem>();

            // Spawn a puddle
            await server.WaitAssertion(() =>
            {
                var solution = new Solution("Water", FixedPoint2.New(amount));
                puddle       = spillSystem.SpillAt(solution, sCoordinates, "PuddleSmear");
                meta         = entityManager.GetComponent <MetaDataComponent>(puddle.Owner);

                // Check that the puddle was created
                Assert.NotNull(puddle);

                evaporation = entityManager.GetComponent <EvaporationComponent>(puddle.Owner);

                meta.EntityPaused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1445

                Assert.True(meta.EntityPaused);

                // Check that the puddle is going to evaporate
                Assert.Positive(evaporation.EvaporateTime);

                // Should have a timer component added to it for evaporation
                Assert.That(evaporation.Accumulator, Is.EqualTo(0f));

                evaporateTime = evaporation.EvaporateTime;
            });

            // Wait enough time for it to evaporate if it was unpaused
            var sTimeToWait = (5 + (int)Math.Ceiling(amount * evaporateTime * sGameTiming.TickRate));
            await server.WaitRunTicks(sTimeToWait);

            // No evaporation due to being paused
            await server.WaitAssertion(() =>
            {
                Assert.True(meta.EntityPaused);

                // Check that the puddle still exists
                Assert.False(meta.EntityDeleted);
            });

            // Unpause the map
            await server.WaitPost(() => { sMapManager.SetMapPaused(sMapId, false); });

            // Check that the map, grid and puddle are unpaused
            await server.WaitAssertion(() =>
            {
                Assert.False(sMapManager.IsMapPaused(sMapId));
                Assert.False(sMapManager.IsGridPaused(sGridId));
                Assert.False(meta.EntityPaused);

                // Check that the puddle still exists
                Assert.False(meta.EntityDeleted);
            });

            // Wait enough time for it to evaporate
            await server.WaitRunTicks(sTimeToWait);

            // Puddle evaporation should have ticked
            await server.WaitAssertion(() =>
            {
                // Check that puddle has been deleted
                Assert.True(puddle.Deleted);
            });
        }