コード例 #1
0
        /// <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));
        }
コード例 #2
0
 public ReagentQuantity(string reagentId, ReagentUnit quantity)
 {
     ReagentId = reagentId;
     Quantity  = quantity;
 }
コード例 #3
0
        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);
                }
            }
コード例 #4
0
        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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
コード例 #7
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           = 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);
                }
            });
        }
コード例 #8
0
        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);
        }
コード例 #9
0
 ReagentUnit IReagentReaction.ReagentReactInjection(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume);
コード例 #10
0
 ReagentUnit IMetabolizable.Metabolize(IEntity solutionEntity, string reagentId, float tickTime)
 {
     return(ReagentUnit.New(MetabolismRate * tickTime));
 }
コード例 #11
0
 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;
 }
コード例 #13
0
 public override void ExposeData(ObjectSerializer serializer)
 {
     base.ExposeData(serializer);
     serializer.DataField(ref _initialMaxVolume, "maxVolume", ReagentUnit.New(250));
 }
コード例 #14
0
        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();
        }
コード例 #15
0
 protected virtual void OnReaction(Solution solution, ReactionPrototype reaction, IEntity owner, ReagentUnit unitReactions)
 {
     foreach (var effect in reaction.Effects)
     {
         effect.React(solution, owner, unitReactions.Double());
     }
 }
コード例 #16
0
 public override void Initialize()
 {
     base.Initialize();
     _contents       = Owner.GetComponent <SolutionComponent>();
     _transferAmount = _contents.CurrentVolume;
 }
コード例 #17
0
        /// <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));
        }
コード例 #18
0
 public InjectorComponentState(ReagentUnit currentVolume, ReagentUnit totalVolume, InjectorToggleMode currentMode) : base(ContentNetIDs.REAGENT_INJECTOR)
 {
     CurrentVolume = currentVolume;
     TotalVolume   = totalVolume;
     CurrentMode   = currentMode;
 }
コード例 #19
0
 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;
 }
コード例 #20
0
        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);
        }
コード例 #21
0
        protected override void OnReaction(ReactionPrototype reaction, IEntity owner, ReagentUnit unitReactions)
        {
            base.OnReaction(reaction, owner, unitReactions);

            Get <AudioSystem>().PlayAtCoords(reaction.Sound, owner.Transform.Coordinates);
        }
コード例 #22
0
        /// <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);
        }
コード例 #23
0
 void IExposeData.ExposeData(ObjectSerializer serializer)
 {
     serializer.DataField(ref _metabolismRate, "rate", ReagentUnit.New(1.0));
     serializer.DataField(ref _nutritionFactor, "nutrimentFactor", 30.0f);
 }
コード例 #24
0
        /// <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);
        }
コード例 #25
0
        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);
        }
コード例 #26
0
        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);
                }
            }
コード例 #27
0
 public void Deconstruct(out string reagentId, out ReagentUnit quantity)
 {
     reagentId = ReagentId;
     quantity  = Quantity;
 }
コード例 #28
0
        /// <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);
        }
コード例 #29
0
 ReagentUnit IReagentReaction.ReagentReactTouch(ReagentPrototype reagent, ReagentUnit volume) => Reaction(reagent, volume);
コード例 #30
0
            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);
            }