/// <summary> /// Gets component data to be used to update the user interface client-side. /// </summary> /// <returns>Returns a <see cref="SharedChemMasterComponent.ChemMasterBoundUserInterfaceState"/></returns> private ChemMasterBoundUserInterfaceState GetUserInterfaceState() { var beaker = _beakerContainer.ContainedEntity; if (beaker == null) { return(new ChemMasterBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0), "", Owner.Name, null, BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume)); } var solution = beaker.GetComponent <SolutionComponent>(); return(new ChemMasterBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume, beaker.Name, Owner.Name, solution.ReagentList.ToList(), BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume)); }
public ReagentQuantity(string reagentId, ReagentUnit quantity) { ReagentId = reagentId; Quantity = quantity; }
public virtual bool TryUseFood(IEntity?user, IEntity?target, UtensilComponent?utensilUsed = null) { if (!Owner.TryGetComponent(out SolutionContainerComponent? solution)) { return(false); } if (user == null) { return(false); } if (UsesRemaining <= 0) { user.PopupMessage(Loc.GetString("{0:TheName} is empty!", Owner)); return(false); } var trueTarget = target ?? user; if (!trueTarget.TryGetComponent(out IBody? body) || !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs)) { return(false); } var utensils = utensilUsed != null ? new List <UtensilComponent> { utensilUsed } : null; if (_utensilsNeeded != UtensilType.None) { utensils = new List <UtensilComponent>(); var types = UtensilType.None; if (user.TryGetComponent(out HandsComponent? hands)) { foreach (var item in hands.GetAllHeldItems()) { if (!item.Owner.TryGetComponent(out UtensilComponent? utensil)) { continue; } utensils.Add(utensil); types |= utensil.Types; } } if (!types.HasFlag(_utensilsNeeded)) { trueTarget.PopupMessage(user, Loc.GetString("You need to be holding a {0} to eat that!", _utensilsNeeded)); return(false); } } if (!user.InRangeUnobstructed(trueTarget, popup: true)) { return(false); } var transferAmount = ReagentUnit.Min(_transferAmount, solution.CurrentVolume); var split = solution.SplitSolution(transferAmount); var firstStomach = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split)); if (firstStomach == null) { trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); return(false); } // TODO: Account for partial transfer. split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); _entitySystem.GetEntitySystem <AudioSystem>() .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f)); trueTarget.PopupMessage(user, Loc.GetString("Nom")); // If utensils were used if (utensils != null) { foreach (var utensil in utensils) { utensil.TryBreak(user); } } if (UsesRemaining > 0) { return(true); } if (string.IsNullOrEmpty(_trashPrototype)) { Owner.Delete(); return(true); } //We're empty. Become trash. var position = Owner.Transform.Coordinates; var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); // If the user is holding the item if (user.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.IsHolding(Owner)) { Owner.Delete(); // Put the trash in the user's hand if (finisher.TryGetComponent(out ItemComponent? item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); } }
async Task <bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { var user = eventArgs.User; var usingItem = eventArgs.Using; if (usingItem == null || usingItem.Deleted || !EntitySystem.Get <ActionBlockerSystem>().CanInteract(user)) { return(false); } if (usingItem.TryGetComponent(out SeedComponent? seeds)) { if (Seed == null) { if (seeds.Seed == null) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-empty-seed-packet-message")); usingItem.QueueDelete(); return(false); } user.PopupMessageCursor(Loc.GetString("plant-holder-component-plant-success-message", ("seedName", seeds.Seed.SeedName), ("seedNoun", seeds.Seed.SeedNoun))); Seed = seeds.Seed; Dead = false; Age = 1; Health = Seed.Endurance; _lastCycle = _gameTiming.CurTime; usingItem.QueueDelete(); CheckLevelSanity(); UpdateSprite(); return(true); } user.PopupMessageCursor(Loc.GetString("plant-holder-component-already-seeded-message", ("name", Owner.Name))); return(false); } if (usingItem.HasTag("Hoe")) { if (WeedLevel > 0) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-remove-weeds-message", ("name", Owner.Name))); user.PopupMessageOtherClients(Loc.GetString("plant-holder-component-remove-weeds-others-message", ("otherName", user.Name))); WeedLevel = 0; UpdateSprite(); } else { user.PopupMessageCursor(Loc.GetString("plant-holder-component-no-weeds-message")); } return(true); } if (usingItem.HasTag("Shovel")) { if (Seed != null) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-remove-plant-message", ("name", Owner.Name))); user.PopupMessageOtherClients(Loc.GetString("plant-holder-component-remove-plant-others-message", ("name", user.Name))); RemovePlant(); } else { user.PopupMessageCursor(Loc.GetString("plant-holder-component-no-plant-message")); } return(true); } if (usingItem.TryGetComponent(out ISolutionInteractionsComponent? solution) && solution.CanDrain) { var amount = ReagentUnit.New(5); var sprayed = false; if (usingItem.TryGetComponent(out SprayComponent? spray)) { sprayed = true; amount = ReagentUnit.New(1); if (!string.IsNullOrEmpty(spray.SpraySound)) { SoundSystem.Play(Filter.Pvs(usingItem), spray.SpraySound, usingItem, AudioHelpers.WithVariation(0.125f)); } } var split = solution.Drain(amount); if (split.TotalVolume == 0) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-empty-message", ("owner", usingItem))); return(true); } user.PopupMessageCursor(Loc.GetString(sprayed ? "plant-holder-component-spray-message" : "plant-holder-component-transfer-message", ("owner", Owner), ("amount", split.TotalVolume))); _solutionContainer?.TryAddSolution(split); ForceUpdateByExternalCause(); return(true); } if (usingItem.HasTag("PlantSampleTaker")) { if (Seed == null) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-nothing-to-sample-message")); return(false); } if (Sampled) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-already-sampled-message")); return(false); } if (Dead) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-dead-plant-message")); return(false); } var seed = Seed.SpawnSeedPacket(user.Transform.Coordinates); seed.RandomOffset(0.25f); user.PopupMessageCursor(Loc.GetString("plant-holder-component-take-sample-message", ("seedName", Seed.DisplayName))); Health -= (_random.Next(3, 5) * 10); if (_random.Prob(0.3f)) { Sampled = true; } // Just in case. CheckLevelSanity(); ForceUpdateByExternalCause(); return(true); } if (usingItem.HasTag("BotanySharp")) { return(DoHarvest(user)); } if (usingItem.HasComponent <ProduceComponent>()) { user.PopupMessageCursor(Loc.GetString("plant-holder-component-compost-message", ("owner", Owner), ("usingItem", usingItem))); user.PopupMessageOtherClients(Loc.GetString("plant-holder-component-compost-others-message", ("user", user), ("usingItem", usingItem), ("owner", Owner))); if (usingItem.TryGetComponent(out SolutionContainerComponent? solution2)) { // This deliberately discards overfill. _solutionContainer?.TryAddSolution(solution2.SplitSolution(solution2.Solution.TotalVolume)); ForceUpdateByExternalCause(); } usingItem.QueueDelete(); return(true); } return(false); }
async Task <bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { var user = eventArgs.User; var usingItem = eventArgs.Using; if (usingItem == null || usingItem.Deleted || !ActionBlockerSystem.CanInteract(user)) { return(false); } if (usingItem.TryGetComponent(out SeedComponent? seeds)) { if (Seed == null) { if (seeds.Seed == null) { user.PopupMessageCursor(Loc.GetString("The packet seems to be empty. You throw it away.")); usingItem.Delete(); return(false); } user.PopupMessageCursor(Loc.GetString("You plant the {0} {1}.", seeds.Seed.SeedName, seeds.Seed.SeedNoun)); Seed = seeds.Seed; Dead = false; Age = 1; Health = Seed.Endurance; _lastCycle = _gameTiming.CurTime; usingItem.Delete(); CheckLevelSanity(); UpdateSprite(); return(true); } user.PopupMessageCursor(Loc.GetString("The {0} already has seeds in it!", Owner.Name)); return(false); } if (usingItem.HasTag("Hoe")) { if (WeedLevel > 0) { user.PopupMessageCursor(Loc.GetString("You remove the weeds from the {0}.", Owner.Name)); user.PopupMessageOtherClients(Loc.GetString("{0} starts uprooting the weeds.", user.Name)); WeedLevel = 0; UpdateSprite(); } else { user.PopupMessageCursor(Loc.GetString("This plot is devoid of weeds! It doesn't need uprooting.")); } return(true); } if (usingItem.HasTag("Shovel")) { if (Seed != null) { user.PopupMessageCursor(Loc.GetString("You remove the plant from the {0}.", Owner.Name)); user.PopupMessageOtherClients(Loc.GetString("{0} removes the plant.", user.Name)); RemovePlant(); } else { user.PopupMessageCursor(Loc.GetString("There is no plant to remove.")); } return(true); } if (usingItem.TryGetComponent(out ISolutionInteractionsComponent? solution) && solution.CanDrain) { var amount = ReagentUnit.New(5); var sprayed = false; if (usingItem.TryGetComponent(out SprayComponent? spray)) { sprayed = true; amount = ReagentUnit.New(1); EntitySystem.Get <AudioSystem>().PlayFromEntity(spray.SpraySound, usingItem, AudioHelpers.WithVariation(0.125f)); } var split = solution.Drain(amount); if (split.TotalVolume == 0) { user.PopupMessageCursor(Loc.GetString("{0:TheName} is empty!", usingItem)); return(true); } user.PopupMessageCursor(Loc.GetString( sprayed ? "You spray {0:TheName}" : "You transfer {1}u to {0:TheName}", Owner, split.TotalVolume)); _solutionContainer?.TryAddSolution(split); ForceUpdateByExternalCause(); return(true); } if (usingItem.HasTag("PlantSampleTaker")) { if (Seed == null) { user.PopupMessageCursor(Loc.GetString("There is nothing to take a sample of!")); return(false); } if (Sampled) { user.PopupMessageCursor(Loc.GetString("This plant has already been sampled.")); return(false); } if (Dead) { user.PopupMessageCursor(Loc.GetString("This plant is dead.")); return(false); } var seed = Seed.SpawnSeedPacket(user.Transform.Coordinates); seed.RandomOffset(0.25f); user.PopupMessageCursor(Loc.GetString($"You take a sample from the {Seed.DisplayName}.")); Health -= (_random.Next(3, 5) * 10); if (_random.Prob(0.3f)) { Sampled = true; } // Just in case. CheckLevelSanity(); ForceUpdateByExternalCause(); return(true); } if (usingItem.HasTag("BotanySharp")) { return(DoHarvest(user)); } if (usingItem.HasComponent <ProduceComponent>()) { user.PopupMessageCursor(Loc.GetString("You compost {1:theName} into {0:theName}.", Owner, usingItem)); user.PopupMessageOtherClients(Loc.GetString("{0:TheName} composts {1:theName} into {2:theName}.", user, usingItem, Owner)); if (usingItem.TryGetComponent(out SolutionContainerComponent? solution2)) { // This deliberately discards overfill. _solutionContainer?.TryAddSolution(solution2.SplitSolution(solution2.Solution.TotalVolume)); ForceUpdateByExternalCause(); } usingItem.Delete(); return(true); } return(false); }
public bool TryDoInject(IEntity?target, IEntity user) { if (target == null || !EligibleEntity(target)) { return(false); } string?msgFormat = null; if (target == user) { msgFormat = "hypospray-component-inject-self-message"; } else if (EligibleEntity(user) && ClumsyComponent.TryRollClumsy(user, ClumsyFailChance)) { msgFormat = "hypospray-component-inject-self-clumsy-message"; target = user; } var solutionsSys = EntitySystem.Get <SolutionContainerSystem>(); solutionsSys.TryGetSolution(Owner, SolutionName, out var hypoSpraySolution); if (hypoSpraySolution == null || hypoSpraySolution.CurrentVolume == 0) { user.PopupMessageCursor(Loc.GetString("hypospray-component-empty-message")); return(true); } if (!solutionsSys.TryGetInjectableSolution(target.Uid, out var targetSolution)) { user.PopupMessage(user, Loc.GetString("hypospray-cant-inject", ("target", target))); return(false); } user.PopupMessage(Loc.GetString(msgFormat ?? "hypospray-component-inject-other-message", ("other", target))); if (target != user) { target.PopupMessage(Loc.GetString("hypospray-component-feel-prick-message")); var meleeSys = EntitySystem.Get <MeleeWeaponSystem>(); var angle = Angle.FromWorldVec(target.Transform.WorldPosition - user.Transform.WorldPosition); meleeSys.SendLunge(angle, user); } SoundSystem.Play(Filter.Pvs(user), _injectSound.GetSound(), user); // Get transfer amount. May be smaller than _transferAmount if not enough room var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.AvailableVolume); if (realTransferAmount <= 0) { user.PopupMessage(user, Loc.GetString("hypospray-component-transfer-already-full-message", ("owner", target))); return(true); } // Move units from attackSolution to targetSolution var removedSolution = EntitySystem.Get <SolutionContainerSystem>() .SplitSolution(Owner.Uid, hypoSpraySolution, realTransferAmount); if (!targetSolution.CanAddSolution(removedSolution)) { return(true); } removedSolution.DoEntityReaction(target, ReactionMethod.Injection); EntitySystem.Get <SolutionContainerSystem>().TryAddSolution(target.Uid, targetSolution, removedSolution);
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 = null; GridId sGridId = default; IEntity sGridEntity = null; EntityCoordinates sCoordinates = default; TimerComponent sTimerComponent = null; // 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; 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 sTimerComponent)); 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 sTimerComponent)); // 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); } }); }
public static PuddleComponent?SpillAt(this TileRef tileRef, Solution solution, string prototype, bool overflow = true, bool sound = true) { if (solution.TotalVolume <= 0) { return(null); } var mapManager = IoCManager.Resolve <IMapManager>(); var entityManager = IoCManager.Resolve <IEntityManager>(); var serverEntityManager = IoCManager.Resolve <IServerEntityManager>(); // If space return early, let that spill go out into the void if (tileRef.Tile.IsEmpty) { return(null); } var gridId = tileRef.GridIndex; if (!mapManager.TryGetGrid(gridId, out var mapGrid)) { return(null); // Let's not spill to invalid grids. } // Get normalized co-ordinate for spill location and spill it in the centre // TODO: Does SnapGrid or something else already do this? var spillGridCoords = mapGrid.GridTileToLocal(tileRef.GridIndices); PuddleComponent?puddle = null; var spilt = false; var spillEntities = IoCManager.Resolve <IEntityLookup>().GetEntitiesIntersecting(mapGrid.ParentMapId, spillGridCoords.Position).ToArray(); foreach (var spillEntity in spillEntities) { if (spillEntity.TryGetComponent(out ISolutionInteractionsComponent? solutionContainerComponent) && solutionContainerComponent.CanRefill) { solutionContainerComponent.Refill( solution.SplitSolution(ReagentUnit.Min(solutionContainerComponent.RefillSpaceAvailable, solutionContainerComponent.MaxSpillRefill)) ); } } foreach (var spillEntity in spillEntities) { if (!spillEntity.TryGetComponent(out PuddleComponent? puddleComponent)) { continue; } if (!overflow && puddleComponent.WouldOverflow(solution)) { return(null); } if (!puddleComponent.TryAddSolution(solution, sound)) { continue; } puddle = puddleComponent; spilt = true; break; } // Did we add to an existing puddle if (spilt) { return(puddle); } var puddleEnt = serverEntityManager.SpawnEntity(prototype, spillGridCoords); var newPuddleComponent = puddleEnt.GetComponent <PuddleComponent>(); newPuddleComponent.TryAddSolution(solution, sound); return(newPuddleComponent); }
ReagentUnit IReagentReaction.ReagentReactInjection(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume);
ReagentUnit IMetabolizable.Metabolize(IEntity solutionEntity, string reagentId, float tickTime) { return(ReagentUnit.New(MetabolismRate * tickTime)); }
public void ExposeData(ObjectSerializer serializer) { serializer.DataField(ref _amount, "amount", ReagentUnit.New(1)); serializer.DataField(ref _catalyst, "catalyst", false); }
public ReagentDispenserBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, List <ReagentDispenserInventoryEntry> inventory, string dispenserName, List <Solution.ReagentQuantity> containerReagents, ReagentUnit selectedDispenseAmount) { HasPower = hasPower; HasBeaker = hasBeaker; BeakerCurrentVolume = beakerCurrentVolume; BeakerMaxVolume = beakerMaxVolume; ContainerName = containerName; Inventory = inventory; DispenserName = dispenserName; ContainerReagents = containerReagents; SelectedDispenseAmount = selectedDispenseAmount; }
public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _initialMaxVolume, "maxVolume", ReagentUnit.New(250)); }
private void TryCreatePackage(IEntity user, UiAction action, int pillAmount, int bottleAmount) { var random = IoCManager.Resolve <IRobustRandom>(); if (BufferSolution.CurrentVolume == 0) { return; } if (action == UiAction.CreateBottles) { var individualVolume = BufferSolution.CurrentVolume / ReagentUnit.New(bottleAmount); if (individualVolume < ReagentUnit.New(1)) { return; } var actualVolume = ReagentUnit.Min(individualVolume, ReagentUnit.New(30)); for (int i = 0; i < bottleAmount; i++) { var bottle = Owner.EntityManager.SpawnEntity("bottle", Owner.Transform.GridPosition); var bufferSolution = BufferSolution.Solution.SplitSolution(actualVolume); bottle.TryGetComponent <SolutionComponent>(out var bottleSolution); bottleSolution?.Solution.AddSolution(bufferSolution); //Try to give them the bottle if (user.TryGetComponent <HandsComponent>(out var hands) && bottle.TryGetComponent <ItemComponent>(out var item)) { if (hands.CanPutInHand(item)) { hands.PutInHand(item); continue; } } //Put it on the floor bottle.Transform.GridPosition = user.Transform.GridPosition; //Give it an offset var x_negative = random.Prob(0.5f) ? -1 : 1; var y_negative = random.Prob(0.5f) ? -1 : 1; bottle.Transform.LocalPosition += new Vector2(random.NextFloat() * 0.2f * x_negative, random.NextFloat() * 0.2f * y_negative); } } else //Pills { var individualVolume = BufferSolution.CurrentVolume / ReagentUnit.New(pillAmount); if (individualVolume < ReagentUnit.New(1)) { return; } var actualVolume = ReagentUnit.Min(individualVolume, ReagentUnit.New(50)); for (int i = 0; i < pillAmount; i++) { var pill = Owner.EntityManager.SpawnEntity("pill", Owner.Transform.GridPosition); var bufferSolution = BufferSolution.Solution.SplitSolution(actualVolume); pill.TryGetComponent <SolutionComponent>(out var pillSolution); pillSolution?.Solution.AddSolution(bufferSolution); //Try to give them the bottle if (user.TryGetComponent <HandsComponent>(out var hands) && pill.TryGetComponent <ItemComponent>(out var item)) { if (hands.CanPutInHand(item)) { hands.PutInHand(item); continue; } } //Put it on the floor pill.Transform.GridPosition = user.Transform.GridPosition; //Give it an offset var x_negative = random.Prob(0.5f) ? -1 : 1; var y_negative = random.Prob(0.5f) ? -1 : 1; pill.Transform.LocalPosition += new Vector2(random.NextFloat() * 0.2f * x_negative, random.NextFloat() * 0.2f * y_negative); } } UpdateUserInterface(); }
protected virtual void OnReaction(Solution solution, ReactionPrototype reaction, IEntity owner, ReagentUnit unitReactions) { foreach (var effect in reaction.Effects) { effect.React(solution, owner, unitReactions.Double()); } }
public override void Initialize() { base.Initialize(); _contents = Owner.GetComponent <SolutionComponent>(); _transferAmount = _contents.CurrentVolume; }
/// <summary> /// Gets component data to be used to update the user interface client-side. /// </summary> /// <returns>Returns a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/></returns> private ReagentDispenserBoundUserInterfaceState GetUserInterfaceState() { var beaker = _beakerContainer.ContainedEntity; if (beaker == null) { return(new ReagentDispenserBoundUserInterfaceState(false, ReagentUnit.New(0), ReagentUnit.New(0), "", Inventory, Owner.Name, null, _dispenseAmount)); } var solution = beaker.GetComponent <SolutionComponent>(); return(new ReagentDispenserBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume, beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList(), _dispenseAmount)); }
public InjectorComponentState(ReagentUnit currentVolume, ReagentUnit totalVolume, InjectorToggleMode currentMode) : base(ContentNetIDs.REAGENT_INJECTOR) { CurrentVolume = currentVolume; TotalVolume = totalVolume; CurrentMode = currentMode; }
public ChemMasterBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName, string dispenserName, List <Solution.ReagentQuantity> containerReagents, List <Solution.ReagentQuantity> bufferReagents, bool bufferModeTransfer, ReagentUnit bufferCurrentVolume, ReagentUnit bufferMaxVolume) { HasPower = hasPower; HasBeaker = hasBeaker; BeakerCurrentVolume = beakerCurrentVolume; BeakerMaxVolume = beakerMaxVolume; ContainerName = containerName; DispenserName = dispenserName; ContainerReagents = containerReagents; BufferReagents = bufferReagents; BufferModeTransfer = bufferModeTransfer; BufferCurrentVolume = bufferCurrentVolume; BufferMaxVolume = bufferMaxVolume; }
public bool TryUseFood(IEntity?user, IEntity?target, UtensilComponent?utensilUsed = null) { var solutionContainerSys = EntitySystem.Get <SolutionContainerSystem>(); if (!solutionContainerSys.TryGetSolution(Owner, SolutionName, out var solution)) { return(false); } if (user == null) { return(false); } if (UsesRemaining <= 0) { user.PopupMessage(Loc.GetString("food-component-try-use-food-is-empty", ("entity", Owner))); DeleteAndSpawnTrash(user); return(false); } var trueTarget = target ?? user; if (!trueTarget.TryGetComponent(out SharedBodyComponent? body) || !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs)) { return(false); } var utensils = utensilUsed != null ? new List <UtensilComponent> { utensilUsed } : null; if (_utensilsNeeded != UtensilType.None) { utensils = new List <UtensilComponent>(); var types = UtensilType.None; if (user.TryGetComponent(out HandsComponent? hands)) { foreach (var item in hands.GetAllHeldItems()) { if (!item.Owner.TryGetComponent(out UtensilComponent? utensil)) { continue; } utensils.Add(utensil); types |= utensil.Types; } } if (!types.HasFlag(_utensilsNeeded)) { trueTarget.PopupMessage(user, Loc.GetString("food-you-need-to-hold-utensil", ("utensil", _utensilsNeeded))); return(false); } } if (!user.InRangeUnobstructed(trueTarget, popup: true)) { return(false); } var transferAmount = TransferAmount != null?ReagentUnit.Min((ReagentUnit)TransferAmount, solution.CurrentVolume) : solution.CurrentVolume; var split = solutionContainerSys.SplitSolution(Owner.Uid, solution, transferAmount); var firstStomach = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split)); if (firstStomach == null) { solutionContainerSys.TryAddSolution(Owner.Uid, solution, split); trueTarget.PopupMessage(user, Loc.GetString("food-you-cannot-eat-any-more")); return(false); } // TODO: Account for partial transfer. split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); SoundSystem.Play(Filter.Pvs(trueTarget), UseSound.GetSound(), trueTarget, AudioParams.Default.WithVolume(-1f)); trueTarget.PopupMessage(user, Loc.GetString(_eatMessage)); // If utensils were used if (utensils != null) { foreach (var utensil in utensils) { utensil.TryBreak(user); } } if (UsesRemaining > 0) { return(true); } if (string.IsNullOrEmpty(TrashPrototype)) { Owner.Delete(); return(true); } DeleteAndSpawnTrash(user); return(true); }
protected override void OnReaction(ReactionPrototype reaction, IEntity owner, ReagentUnit unitReactions) { base.OnReaction(reaction, owner, unitReactions); Get <AudioSystem>().PlayAtCoords(reaction.Sound, owner.Transform.Coordinates); }
/// <summary> /// Adds reagent of an Id to the container. /// </summary> /// <param name="targetUid"></param> /// <param name="targetSolution">Container to which we are adding reagent</param> /// <param name="reagentId">The Id of the reagent to add.</param> /// <param name="quantity">The amount of reagent to add.</param> /// <param name="acceptedQuantity">The amount of reagent successfully added.</param> /// <returns>If all the reagent could be added.</returns> public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, ReagentUnit quantity, out ReagentUnit acceptedQuantity) { acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume; targetSolution.AddReagent(reagentId, acceptedQuantity); if (acceptedQuantity > 0) { UpdateChemicals(targetUid, targetSolution, true); } return(acceptedQuantity == quantity); }
void IExposeData.ExposeData(ObjectSerializer serializer) { serializer.DataField(ref _metabolismRate, "rate", ReagentUnit.New(1.0)); serializer.DataField(ref _nutritionFactor, "nutrimentFactor", 30.0f); }
/// <summary> /// Removes reagent of an Id to the container. /// </summary> /// <param name="targetUid"></param> /// <param name="container">Solution container from which we are removing reagent</param> /// <param name="reagentId">The Id of the reagent to remove.</param> /// <param name="quantity">The amount of reagent to remove.</param> /// <returns>If the reagent to remove was found in the container.</returns> public bool TryRemoveReagent(EntityUid targetUid, Solution?container, string reagentId, ReagentUnit quantity) { if (container == null || !container.ContainsReagent(reagentId)) { return(false); } container.RemoveReagent(reagentId, quantity); UpdateChemicals(targetUid, container); return(true); }
public async Task <bool> InteractUsing(InteractUsingEventArgs eventArgs) { var user = eventArgs.User; var usingItem = eventArgs.Using; if (usingItem == null || usingItem.Deleted || !ActionBlockerSystem.CanInteract(user)) { return(false); } if (usingItem.TryGetComponent(out SeedComponent? seeds)) { if (Seed == null) { if (seeds.Seed == null) { user.PopupMessageCursor(Loc.GetString("The packet seems to be empty. You throw it away.")); usingItem.Delete(); return(false); } user.PopupMessageCursor(Loc.GetString("You plant the {0} {1}.", seeds.Seed.SeedName, seeds.Seed.SeedNoun)); Seed = seeds.Seed; Dead = false; Age = 1; Health = Seed.Endurance; _lastCycle = _gameTiming.CurTime; usingItem.Delete(); CheckLevelSanity(); UpdateSprite(); return(true); } user.PopupMessageCursor(Loc.GetString("The {0} already has seeds in it!", Owner.Name)); return(false); } if (usingItem.HasComponent <HoeComponent>()) { if (WeedLevel > 0) { user.PopupMessageCursor(Loc.GetString("You remove the weeds from the {0}.", Owner.Name)); user.PopupMessageOtherClients(Loc.GetString("{0} starts uprooting the weeds.", user.Name)); WeedLevel = 0; UpdateSprite(); } else { user.PopupMessageCursor(Loc.GetString("This plot is devoid of weeds! It doesn't need uprooting.")); } return(true); } if (usingItem.TryGetComponent(out SolutionContainerComponent? solution) && solution.CanRemoveSolutions) { var amount = 5f; var sprayed = false; if (usingItem.TryGetComponent(out SprayComponent? spray)) { sprayed = true; amount = 1f; EntitySystem.Get <AudioSystem>().PlayFromEntity(spray.SpraySound, usingItem, AudioHelpers.WithVariation(0.125f)); } var chemAmount = ReagentUnit.New(amount); var split = solution.Solution.SplitSolution(chemAmount <= solution.Solution.TotalVolume ? chemAmount : solution.Solution.TotalVolume); user.PopupMessageCursor(Loc.GetString(sprayed ? $"You spray {Owner.Name} with {usingItem.Name}." : $"You transfer {split.TotalVolume.ToString()}u to {Owner.Name}")); _solutionContainer?.TryAddSolution(split); SkipAging++; // We're forcing an update cycle, so one age hasn't passed. ForceUpdate = true; Update(); return(true); } if (usingItem.HasComponent <PlantSampleTakerComponent>()) { if (Seed == null) { user.PopupMessageCursor(Loc.GetString("There is nothing to take a sample of!")); return(false); } if (Sampled) { user.PopupMessageCursor(Loc.GetString("This plant has already been sampled.")); return(false); } if (Dead) { user.PopupMessageCursor(Loc.GetString("This plant is dead.")); return(false); } var seed = Seed.SpawnSeedPacket(user.Transform.Coordinates); seed.RandomOffset(0.25f); user.PopupMessageCursor(Loc.GetString($"You take a sample from the {Seed.DisplayName}.")); Health -= (_random.Next(3, 5) * 10); if (_random.Prob(0.3f)) { Sampled = true; } // Just in case. CheckLevelSanity(); SkipAging++; // We're forcing an update cycle, so one age hasn't passed. ForceUpdate = true; Update(); return(true); } if (usingItem.HasComponent <BotanySharpComponent>()) { return(DoHarvest(user)); } return(false); }
public virtual bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null) { if (user == null) { return(false); } if (UsesRemaining <= 0) { user.PopupMessage(user, Loc.GetString("{0:TheName} is empty!", Owner)); return(false); } var trueTarget = target ?? user; if (!trueTarget.TryGetComponent(out StomachComponent stomach)) { return(false); } var utensils = utensilUsed != null ? new List <UtensilComponent> { utensilUsed } : null; if (_utensilsNeeded != UtensilType.None) { utensils = new List <UtensilComponent>(); var types = UtensilType.None; if (user.TryGetComponent(out HandsComponent hands)) { foreach (var item in hands.GetAllHeldItems()) { if (!item.Owner.TryGetComponent(out UtensilComponent utensil)) { continue; } utensils.Add(utensil); types |= utensil.Types; } } if (!types.HasFlag(_utensilsNeeded)) { trueTarget.PopupMessage(user, Loc.GetString("You need to be holding a {0} to eat that!", _utensilsNeeded)); return(false); } } if (!InteractionChecks.InRangeUnobstructed(user, trueTarget.Transform.MapPosition)) { return(false); } var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume); var split = _contents.SplitSolution(transferAmount); if (!stomach.TryTransferSolution(split)) { _contents.TryAddSolution(split); trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); return(false); } _entitySystem.GetEntitySystem <AudioSystem>() .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f)); trueTarget.PopupMessage(user, Loc.GetString("Nom")); // If utensils were used if (utensils != null) { foreach (var utensil in utensils) { utensil.TryBreak(user); } } if (UsesRemaining > 0) { return(true); } if (string.IsNullOrEmpty(_trashPrototype)) { Owner.Delete(); return(true); } //We're empty. Become trash. var position = Owner.Transform.GridPosition; var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); // If the user is holding the item if (user.TryGetComponent(out HandsComponent handsComponent) && handsComponent.IsHolding(Owner)) { Owner.Delete(); // Put the trash in the user's hand if (finisher.TryGetComponent(out ItemComponent item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); } }
public void Deconstruct(out string reagentId, out ReagentUnit quantity) { reagentId = ReagentId; quantity = Quantity; }
/// <summary> /// Perform a reaction on a solution. This assumes all reaction criteria are met. /// Removes the reactants from the solution, then returns a solution with all products. /// </summary> private Solution PerformReaction(Solution solution, IEntity owner, ReactionPrototype reaction, ReagentUnit unitReactions) { //Remove reactants foreach (var reactant in reaction.Reactants) { if (!reactant.Value.Catalyst) { var amountToRemove = unitReactions * reactant.Value.Amount; solution.RemoveReagent(reactant.Key, amountToRemove); } } //Create products var products = new Solution(); foreach (var product in reaction.Products) { products.AddReagent(product.Key, product.Value * unitReactions); } // Trigger reaction effects OnReaction(solution, reaction, owner, unitReactions); return(products); }
ReagentUnit IReagentReaction.ReagentReactTouch(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume);
protected override void Activate(IEntity user, SolutionContainerComponent component) { if (!user.TryGetComponent <HandsComponent>(out var hands) || hands.GetActiveHand == null) { return; } if (!hands.GetActiveHand.Owner.TryGetComponent <SolutionContainerComponent>(out var handSolutionComp) || !handSolutionComp.CanAddSolutions || !component.CanRemoveSolutions) { return; } var transferQuantity = ReagentUnit.Min(handSolutionComp.MaxVolume - handSolutionComp.CurrentVolume, component.CurrentVolume, ReagentUnit.New(10)); if (transferQuantity <= 0) { return; } var transferSolution = component.SplitSolution(transferQuantity); handSolutionComp.TryAddSolution(transferSolution); }