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); } }
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); }
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(); }
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); } } }
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; } }
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); } }
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); }
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); } }); }
private void OnUpdate(EntityUid uid, PuddleComponent component, SolutionChangedEvent args) { UpdateSlip(uid, component); UpdateVisuals(uid, component); }
private void OnInit(EntityUid uid, PuddleComponent component, ComponentInit args) { var solution = _solutionContainerSystem.EnsureSolution(uid, component.SolutionName); solution.MaxVolume = FixedPoint2.New(1000); }
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); }); }