private void Stop(IConsoleShell shell, IPlayerSession?player)
        {
            var resultText = EntitySystem.Get <StationEventSystem>().StopEvent();

            shell.WriteLine(resultText);
        }
Пример #2
0
 public void Execute(IConsoleShell shell, string argStr, string[] args)
 {
     EntitySystem.Get <RoundEndSystem>().EndRound();
 }
Пример #3
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);
        }
        private void SubtractContents(FoodRecipePrototype recipe)
        {
            var totalReagentsToRemove   = new Dictionary <string, FixedPoint2>(recipe.IngredientsReagents);
            var solutionContainerSystem = EntitySystem.Get <SolutionContainerSystem>();

            // this is spaghetti ngl
            foreach (var item in Storage.ContainedEntities)
            {
                if (!_entities.TryGetComponent <SolutionContainerManagerComponent>(item, out var solMan))
                {
                    continue;
                }

                // go over every solution
                foreach (var(_, solution) in solMan.Solutions)
                {
                    foreach (var(reagent, _) in recipe.IngredientsReagents)
                    {
                        // removed everything
                        if (!totalReagentsToRemove.ContainsKey(reagent))
                        {
                            continue;
                        }

                        if (!solution.ContainsReagent(reagent))
                        {
                            continue;
                        }

                        var quant = solution.GetReagentQuantity(reagent);

                        if (quant >= totalReagentsToRemove[reagent])
                        {
                            quant = totalReagentsToRemove[reagent];
                            totalReagentsToRemove.Remove(reagent);
                        }
                        else
                        {
                            totalReagentsToRemove[reagent] -= quant;
                        }

                        solutionContainerSystem.TryRemoveReagent(item, solution, reagent, quant);
                    }
                }
            }

            foreach (var recipeSolid in recipe.IngredientsSolids)
            {
                for (var i = 0; i < recipeSolid.Value; i++)
                {
                    foreach (var item in Storage.ContainedEntities)
                    {
                        var metaData = _entities.GetComponent <MetaDataComponent>(item);
                        if (metaData.EntityPrototype == null)
                        {
                            continue;
                        }

                        if (metaData.EntityPrototype.ID == recipeSolid.Key)
                        {
                            Storage.Remove(item);
                            _entities.DeleteEntity(item);
                            break;
                        }
                    }
                }
            }
        }
        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 Test()
        {
            var server = StartServer(new ServerContentIntegrationOption
            {
                ExtraPrototypes = Prototypes
            });

            await server.WaitIdleAsync();

            var sEntityManager       = server.ResolveDependency <IEntityManager>();
            var sMapManager          = server.ResolveDependency <IMapManager>();
            var sPrototypeManager    = server.ResolveDependency <IPrototypeManager>();
            var sEntitySystemManager = server.ResolveDependency <IEntitySystemManager>();

            EntityUid sDestructibleEntity = default;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;

            await server.WaitPost(() =>
            {
                var gridId      = GetMainGrid(sMapManager).GridEntityId;
                var coordinates = new EntityCoordinates(gridId, 0, 0);

                sDestructibleEntity          = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem <TestDestructibleListenerSystem>();
            });

            await server.WaitAssertion(() =>
            {
                var coordinates             = IoCManager.Resolve <IEntityManager>().GetComponent <TransformComponent>(sDestructibleEntity).Coordinates;
                var bruteDamageGroup        = sPrototypeManager.Index <DamageGroupPrototype>("TestBrute");
                DamageSpecifier bruteDamage = new(bruteDamageGroup, 50);

                Assert.DoesNotThrow(() =>
                {
                    EntitySystem.Get <DamageableSystem>().TryChangeDamage(sDestructibleEntity, bruteDamage, true);
                });

                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                var threshold = sTestThresholdListenerSystem.ThresholdsReached[0].Threshold;

                Assert.That(threshold.Triggered, Is.True);
                Assert.That(threshold.Behaviors.Count, Is.EqualTo(3));

                var spawnEntitiesBehavior = (SpawnEntitiesBehavior)threshold.Behaviors.Single(b => b is SpawnEntitiesBehavior);

                Assert.That(spawnEntitiesBehavior.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnEntitiesBehavior.Spawn.Keys.Single(), Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnEntitiesBehavior.Spawn.Values.Single(), Is.EqualTo(new MinMax {
                    Min = 1, Max = 1
                }));

                var entitiesInRange = IoCManager.Resolve <IEntityLookup>().GetEntitiesInRange(coordinates, 2);
                var found           = false;

                foreach (var entity in entitiesInRange)
                {
                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype == null)
                    {
                        continue;
                    }

                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype?.Name != SpawnedEntityId)
                    {
                        continue;
                    }

                    found = true;
                    break;
                }

                Assert.That(found, Is.True);
            });
        }
 private void ClickSound()
 {
     EntitySystem.Get <AudioSystem>().PlayFromEntity("/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f));
 }
Пример #8
0
 /// <inheritdoc />
 protected override void Shutdown()
 {
     base.Shutdown();
     EntitySystem.Get <ResearchSystem>()?.UnregisterServer(this);
 }
        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);
        }
Пример #10
0
        private void UpdateUserInterface()
        {
            if (UserInterface == null)
            {
                return;
            }

            string?error = null;

            // Check if the player is still holding the gas analyzer => if not, don't update
            foreach (var session in UserInterface.SubscribedSessions)
            {
                if (session.AttachedEntity is not {
                    Valid: true
                } playerEntity)
                {
                    return;
                }

                if (!_entities.TryGetComponent(playerEntity, out HandsComponent? handsComponent))
                {
                    return;
                }

                if (handsComponent?.ActiveHandEntity is not {
                    Valid: true
                } activeHandEntity ||
                    !_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
                {
                    return;
                }
            }

            var pos = _entities.GetComponent <TransformComponent>(Owner).Coordinates;

            if (!_checkPlayer && _position.HasValue)
            {
                // Check if position is out of range => don't update
                if (!_position.Value.InRange(_entities, pos, SharedInteractionSystem.InteractionRange))
                {
                    return;
                }

                pos = _position.Value;
            }

            var gridUid  = pos.GetGridUid(_entities);
            var mapUid   = pos.GetMapUid(_entities);
            var position = pos.ToVector2i(_entities, IoCManager.Resolve <IMapManager>());

            var atmosphereSystem = EntitySystem.Get <AtmosphereSystem>();
            var tile             = atmosphereSystem.GetTileMixture(gridUid, mapUid, position);

            if (tile == null)
            {
                error = "No Atmosphere!";
                UserInterface.SetState(
                    new GasAnalyzerBoundUserInterfaceState(
                        0,
                        0,
                        null,
                        error));
                return;
            }

            var gases = new List <GasEntry>();

            for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
            {
                var gas = atmosphereSystem.GetGas(i);

                if (tile.Moles[i] <= Atmospherics.GasMinMoles)
                {
                    continue;
                }

                gases.Add(new GasEntry(gas.Name, tile.Moles[i], gas.Color));
            }

            UserInterface.SetState(
                new GasAnalyzerBoundUserInterfaceState(
                    tile.Pressure,
                    tile.Temperature,
                    gases.ToArray(),
                    error));
        }
Пример #11
0
    public override void Initialize()
    {
        base.Initialize();

        _electrocutionSystem = EntitySystem.Get <ElectrocutionSystem>();
    }
Пример #12
0
        public override void Update(float frameTime)
        {
            base.Update(frameTime);

            if (!Started)
            {
                return;
            }

            if (_waveCounter <= 0)
            {
                Running = false;
                return;
            }
            _cooldown -= frameTime;

            if (_cooldown > 0f)
            {
                return;
            }

            _waveCounter--;

            _cooldown += (MaximumCooldown - MinimumCooldown) * _robustRandom.NextFloat() + MinimumCooldown;

            Box2?playableArea = null;
            var  mapId        = EntitySystem.Get <GameTicker>().DefaultMap;

            foreach (var grid in _mapManager.GetAllGrids())
            {
                if (grid.ParentMapId != mapId || !_entityManager.TryGetComponent(grid.GridEntityId, out PhysicsComponent? gridBody))
                {
                    continue;
                }
                var aabb = gridBody.GetWorldAABB();
                playableArea = playableArea?.Union(aabb) ?? aabb;
            }

            if (playableArea == null)
            {
                EndAfter = float.MinValue;
                return;
            }

            var minimumDistance = (playableArea.Value.TopRight - playableArea.Value.Center).Length + 50f;
            var maximumDistance = minimumDistance + 100f;

            var center = playableArea.Value.Center;

            for (var i = 0; i < MeteorsPerWave; i++)
            {
                var angle         = new Angle(_robustRandom.NextFloat() * MathF.Tau);
                var offset        = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * _robustRandom.NextFloat() + minimumDistance, 0));
                var spawnPosition = new MapCoordinates(center + offset, mapId);
                var meteor        = _entityManager.SpawnEntity("MeteorLarge", spawnPosition);
                var physics       = _entityManager.GetComponent <PhysicsComponent>(meteor);
                physics.BodyStatus     = BodyStatus.InAir;
                physics.LinearDamping  = 0f;
                physics.AngularDamping = 0f;
                physics.ApplyLinearImpulse(-offset.Normalized * MeteorVelocity * physics.Mass);
                physics.ApplyAngularImpulse(
                    // Get a random angular velocity.
                    physics.Mass * ((MaxAngularVelocity - MinAngularVelocity) * _robustRandom.NextFloat() +
                                    MinAngularVelocity));
                // TODO: God this disgusts me but projectile needs a refactor.
                IoCManager.Resolve <IEntityManager>().GetComponent <ProjectileComponent>(meteor).TimeLeft = 120f;
            }
        }
        public void Update(float delta)
        {
            if (Stunned)
            {
                StunnedTimer -= delta;

                if (StunnedTimer <= 0)
                {
                    StunnedTimer = 0f;
                    Dirty();
                }
            }

            if (KnockedDown)
            {
                KnockdownTimer -= delta;

                if (KnockdownTimer <= 0f)
                {
                    EntitySystem.Get <StandingStateSystem>().Standing(Owner);

                    KnockdownTimer = 0f;
                    Dirty();
                }
            }

            if (SlowedDown)
            {
                SlowdownTimer -= delta;

                if (SlowdownTimer <= 0f)
                {
                    SlowdownTimer = 0f;

                    if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement))
                    {
                        movement.RefreshMovementSpeedModifiers();
                    }

                    Dirty();
                }
            }

            if (!StunStart.HasValue || !StunEnd.HasValue ||
                !Owner.TryGetComponent(out ServerAlertsComponent status))
            {
                return;
            }

            var start = StunStart.Value;
            var end   = StunEnd.Value;

            var length   = (end - start).TotalSeconds;
            var progress = (_gameTiming.CurTime - start).TotalSeconds;

            if (progress >= length)
            {
                Owner.SpawnTimer(250, () => status.ClearAlert(AlertType.Stun), StatusRemoveCancellation.Token);
                LastStun = null;
            }
        }
 protected override void OnInteractHand()
 {
     EntitySystem.Get <AudioSystem>()
     .PlayFromEntity("/Audio/Effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.05f));
 }
Пример #15
0
        public static TileAtmosphere?GetTileAtmosphere(this Vector2i indices, GridId gridId)
        {
            var gridAtmos = EntitySystem.Get <AtmosphereSystem>().GetGridAtmosphere(gridId);

            return(gridAtmos.GetTile(indices));
        }
        async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (eventArgs.Target == null)
            {
                return(false);
            }

            if (!_entMan.TryGetComponent(eventArgs.Target.Value, out DamageableComponent? targetDamage))
            {
                return(true);
            }
            else if (DamageContainerID is not null && !DamageContainerID.Equals(targetDamage.DamageContainerID))
            {
                return(true);
            }

            if (!EntitySystem.Get <ActionBlockerSystem>().CanInteract(eventArgs.User))
            {
                return(true);
            }

            if (eventArgs.User != eventArgs.Target &&
                !eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
            {
                return(true);
            }

            if (_entMan.TryGetComponent <SharedStackComponent?>(Owner, out var stack) && !EntitySystem.Get <StackSystem>().Use(Owner, 1, stack))
            {
                return(true);
            }

            var healed = EntitySystem.Get <DamageableSystem>().TryChangeDamage(eventArgs.Target.Value, Damage, true);

            if (healed == null)
            {
                return(true);
            }

            if (eventArgs.Target != eventArgs.User)
            {
                EntitySystem.Get <AdminLogSystem>().Add(LogType.Healed, $"{eventArgs.User} healed {eventArgs.Target} for {healed.Total} damage");
            }
            else
            {
                EntitySystem.Get <AdminLogSystem>().Add(LogType.Healed, $"{eventArgs.User} healed themselves for {healed.Total} damage");
            }

            return(true);
        }
Пример #17
0
        private void UpdateUserInterface()
        {
            if (UserInterface == null)
            {
                return;
            }

            string?error = null;

            // Check if the player is still holding the gas analyzer => if not, don't update
            foreach (var session in UserInterface.SubscribedSessions)
            {
                if (session.AttachedEntity == null)
                {
                    return;
                }

                if (!session.AttachedEntity.TryGetComponent(out IHandsComponent? handsComponent))
                {
                    return;
                }

                var activeHandEntity = handsComponent?.GetActiveHand?.Owner;
                if (activeHandEntity == null || !activeHandEntity.TryGetComponent(out GasAnalyzerComponent? gasAnalyzer))
                {
                    return;
                }
            }

            var pos = Owner.Transform.Coordinates;

            if (!_checkPlayer && _position.HasValue)
            {
                // Check if position is out of range => don't update
                if (!_position.Value.InRange(Owner.EntityManager, pos, SharedInteractionSystem.InteractionRange))
                {
                    return;
                }

                pos = _position.Value;
            }

            var atmosSystem = EntitySystem.Get <AtmosphereSystem>();
            var gam         = atmosSystem.GetGridAtmosphere(pos.GetGridId(Owner.EntityManager));
            var tile        = gam.GetTile(pos)?.Air;

            if (tile == null)
            {
                error = "No Atmosphere!";
                UserInterface.SetState(
                    new GasAnalyzerBoundUserInterfaceState(
                        0,
                        0,
                        null,
                        error));
                return;
            }

            var gases = new List <GasEntry>();

            for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
            {
                var gas = atmosSystem.GetGas(i);

                if (tile.Gases[i] <= Atmospherics.GasMinMoles)
                {
                    continue;
                }

                gases.Add(new GasEntry(gas.Name, tile.Gases[i], gas.Color));
            }

            UserInterface.SetState(
                new GasAnalyzerBoundUserInterfaceState(
                    tile.Pressure,
                    tile.Temperature,
                    gases.ToArray(),
                    error));
        }
Пример #18
0
 protected override void OnKnockdown()
 {
     EntitySystem.Get <StandingStateSystem>().Down(Owner);
 }
Пример #19
0
        public void CreateBoardAndStockParts()
        {
            // Entity might not be initialized yet.
            var boardContainer = Owner.EnsureContainer <Container>(MachineFrameComponent.BoardContainer, out var existedBoard);
            var partContainer  = Owner.EnsureContainer <Container>(MachineFrameComponent.PartContainer, out var existedParts);

            if (string.IsNullOrEmpty(BoardPrototype))
            {
                return;
            }

            var entityManager = Owner.EntityManager;

            if (existedBoard || existedParts)
            {
                // We're done here, let's suppose all containers are correct just so we don't screw SaveLoadSave.
                if (boardContainer.ContainedEntities.Count > 0)
                {
                    return;
                }
            }

            var board = entityManager.SpawnEntity(BoardPrototype, Owner.Transform.Coordinates);

            if (!_boardContainer.Insert(board))
            {
                throw new Exception($"Couldn't insert board with prototype {BoardPrototype} to machine with prototype {Owner.Prototype?.ID ?? "N/A"}!");
            }

            if (!board.TryGetComponent <MachineBoardComponent>(out var machineBoard))
            {
                throw new Exception($"Entity with prototype {BoardPrototype} doesn't have a {nameof(MachineBoardComponent)}!");
            }

            foreach (var(part, amount) in machineBoard.Requirements)
            {
                for (var i = 0; i < amount; i++)
                {
                    var p = entityManager.SpawnEntity(MachinePartComponent.Prototypes[part], Owner.Transform.Coordinates);

                    if (!partContainer.Insert(p))
                    {
                        throw new Exception($"Couldn't insert machine part of type {part} to machine with prototype {Owner.Prototype?.ID ?? "N/A"}!");
                    }
                }
            }

            foreach (var(stackType, amount) in machineBoard.MaterialRequirements)
            {
                var stack = EntitySystem.Get <StackSystem>().Spawn(amount, stackType, Owner.Transform.Coordinates);

                if (stack == null)
                {
                    throw new Exception($"Couldn't spawn stack of type {stackType}!");
                }

                if (!partContainer.Insert(stack))
                {
                    throw new Exception($"Couldn't insert machine material of type {stackType} to machine with prototype {Owner.Prototype?.ID ?? "N/A"}");
                }
            }

            foreach (var(compName, info) in machineBoard.ComponentRequirements)
            {
                for (var i = 0; i < info.Amount; i++)
                {
                    var c = entityManager.SpawnEntity(info.DefaultPrototype, Owner.Transform.Coordinates);

                    if (!partContainer.Insert(c))
                    {
                        throw new Exception($"Couldn't insert machine component part with default prototype '{compName}' to machine with prototype {Owner.Prototype?.ID ?? "N/A"}");
                    }
                }
            }

            foreach (var(tagName, info) in machineBoard.TagRequirements)
            {
                for (var i = 0; i < info.Amount; i++)
                {
                    var c = entityManager.SpawnEntity(info.DefaultPrototype, Owner.Transform.Coordinates);

                    if (!partContainer.Insert(c))
                    {
                        throw new Exception($"Couldn't insert machine component part with default prototype '{tagName}' to machine with prototype {Owner.Prototype?.ID ?? "N/A"}");
                    }
                }
            }
        }
Пример #20
0
 public void InsertIdCard(IdCardComponent card)
 {
     _idSlot.Insert(card.Owner);
     ContainedID = card;
     EntitySystem.Get <AudioSystem>().PlayFromEntity("/Audio/Weapons/Guns/MagIn/batrifle_magin.ogg", Owner);
 }
        // ReSharper disable once InconsistentNaming
        // ReSharper disable once IdentifierTypo
        public void Wzhzhzh()
        {
            if (!HasContents)
            {
                return;
            }

            _busy = true;
            // Convert storage into Dictionary of ingredients
            var solidsDict  = new Dictionary <string, int>();
            var reagentDict = new Dictionary <string, FixedPoint2>();

            foreach (var item in Storage.ContainedEntities)
            {
                // special behavior when being microwaved ;)
                var ev = new BeingMicrowavedEvent(Owner);
                _entities.EventBus.RaiseLocalEvent(item, ev, false);

                if (ev.Handled)
                {
                    _busy   = false;
                    UIDirty = true;
                    return;
                }

                var tagSys = EntitySystem.Get <TagSystem>();

                if (tagSys.HasTag(item, "MicrowaveMachineUnsafe") ||
                    tagSys.HasTag(item, "Metal"))
                {
                    // destroy microwave
                    Broken = true;
                    SetAppearance(MicrowaveVisualState.Broken);
                    SoundSystem.Play(ItemBreakSound.GetSound(), Filter.Pvs(Owner), Owner);
                    return;
                }

                if (tagSys.HasTag(item, "MicrowaveSelfUnsafe") ||
                    tagSys.HasTag(item, "Plastic"))
                {
                    _entities.SpawnEntity(_badRecipeName,
                                          _entities.GetComponent <TransformComponent>(Owner).Coordinates);
                    _entities.QueueDeleteEntity(item);
                }

                var metaData = _entities.GetComponent <MetaDataComponent>(item);
                if (metaData.EntityPrototype == null)
                {
                    continue;
                }

                if (solidsDict.ContainsKey(metaData.EntityPrototype.ID))
                {
                    solidsDict[metaData.EntityPrototype.ID]++;
                }
                else
                {
                    solidsDict.Add(metaData.EntityPrototype.ID, 1);
                }

                if (!_entities.TryGetComponent <SolutionContainerManagerComponent>(item, out var solMan))
                {
                    continue;
                }

                foreach (var(_, solution) in solMan.Solutions)
                {
                    foreach (var reagent in solution.Contents)
                    {
                        if (reagentDict.ContainsKey(reagent.ReagentId))
                        {
                            reagentDict[reagent.ReagentId] += reagent.Quantity;
                        }
                        else
                        {
                            reagentDict.Add(reagent.ReagentId, reagent.Quantity);
                        }
                    }
                }
            }

            // Check recipes
            (FoodRecipePrototype, int)portionedRecipe = _recipeManager.Recipes.Select(
                r => CanSatisfyRecipe(r, solidsDict, reagentDict)).Where(r => r.Item2 > 0).FirstOrDefault();
            FoodRecipePrototype?recipeToCook = portionedRecipe.Item1;

            SetAppearance(MicrowaveVisualState.Cooking);
            var time = _currentCookTimerTime * _cookTimeMultiplier;

            SoundSystem.Play(_startCookingSound.GetSound(), Filter.Pvs(Owner), Owner, AudioParams.Default);
            Owner.SpawnTimer((int)(_currentCookTimerTime * _cookTimeMultiplier), () =>
            {
                if (_lostPower)
                {
                    return;
                }

                AddTemperature(time);

                if (recipeToCook != null)
                {
                    for (int i = 0; i < portionedRecipe.Item2; i++)
                    {
                        SubtractContents(recipeToCook);
                        _entities.SpawnEntity(recipeToCook.Result,
                                              _entities.GetComponent <TransformComponent>(Owner).Coordinates);
                    }
                }

                EjectSolids();

                SoundSystem.Play(_cookingCompleteSound.GetSound(), Filter.Pvs(Owner),
                                 Owner, AudioParams.Default.WithVolume(-1f));

                SetAppearance(MicrowaveVisualState.Idle);
                _busy = false;

                UIDirty = true;
            });
            _lostPower = false;
            UIDirty    = true;
        }
        public void Update(float frameTime)
        {
            if (!Owner.TryGetComponent(out DamageableComponent damageable))
            {
                return;
            }
            Owner.TryGetComponent(out ServerStatusEffectsComponent status);

            var coordinates = Owner.Transform.GridPosition;
            var gridAtmos   = EntitySystem.Get <AtmosphereSystem>().GetGridAtmosphere(coordinates.GridID);
            var tile        = gridAtmos?.GetTile(coordinates);

            var pressure = 1f;
            var highPressureMultiplier = 1f;
            var lowPressureMultiplier  = 1f;

            foreach (var protection in Owner.GetAllComponents <IPressureProtection>())
            {
                highPressureMultiplier *= protection.HighPressureMultiplier;
                lowPressureMultiplier  *= protection.LowPressureMultiplier;
            }

            if (tile?.Air != null)
            {
                pressure = MathF.Max(tile.Air.Pressure, 1f);
            }

            switch (pressure)
            {
            // Low pressure.
            case var p when p <= Atmospherics.WarningLowPressure:
                pressure *= lowPressureMultiplier;

                if (pressure > Atmospherics.WarningLowPressure)
                {
                    goto default;
                }

                damageable.TakeDamage(DamageType.Brute, Atmospherics.LowPressureDamage, Owner);

                if (status == null)
                {
                    break;
                }

                if (pressure <= Atmospherics.HazardLowPressure)
                {
                    status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure2.png", null);
                    break;
                }

                status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure1.png", null);
                break;

            // High pressure.
            case var p when p >= Atmospherics.WarningHighPressure:
                pressure *= highPressureMultiplier;

                if (pressure < Atmospherics.WarningHighPressure)
                {
                    goto default;
                }

                var damage = (int)MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);

                damageable.TakeDamage(DamageType.Brute, damage, Owner);

                if (status == null)
                {
                    break;
                }

                if (pressure >= Atmospherics.HazardHighPressure)
                {
                    status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure2.png", null);
                    break;
                }

                status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure1.png", null);
                break;

            // Normal pressure.
            default:
                status?.RemoveStatusEffect(StatusEffect.Pressure);
                break;
            }
        }
Пример #23
0
        public void Execute(IConsoleShell shell, string argStr, string[] args)
        {
            if (args.Length < 4 || args.Length > 7)
            {
                shell.WriteError($"Received invalid amount of arguments arguments. Expected 4 to 7, got {args.Length}.\nUsage: {Help}");
                return;
            }

            if (!IoCManager.Resolve <IPrototypeManager>().HasIndex <DecalPrototype>(args[0]))
            {
                shell.WriteError($"Cannot find decalprototype '{args[0]}'.");
            }

            if (!float.TryParse(args[1], out var x))
            {
                shell.WriteError($"Failed parsing x-coordinate '{args[1]}'.");
                return;
            }

            if (!float.TryParse(args[2], out var y))
            {
                shell.WriteError($"Failed parsing y-coordinate'{args[2]}'.");
                return;
            }

            var mapManager = IoCManager.Resolve <IMapManager>();

            if (!int.TryParse(args[3], out var gridIdRaw) || !mapManager.TryGetGrid(new GridId(gridIdRaw), out var grid))
            {
                shell.WriteError($"Failed parsing gridId '{args[3]}'.");
                return;
            }

            var coordinates = new EntityCoordinates(grid.GridEntityId, new Vector2(x, y));

            if (grid.GetTileRef(coordinates).IsSpace())
            {
                shell.WriteError($"Cannot create decal on space tile at {coordinates}.");
                return;
            }

            Color?color    = null;
            var   zIndex   = 0;
            Angle?rotation = null;

            if (args.Length > 4)
            {
                for (int i = 4; i < args.Length; i++)
                {
                    var rawValue = args[i].Split('=');
                    if (rawValue.Length != 2)
                    {
                        shell.WriteError($"Failed parsing parameter: '{args[i]}'");
                        return;
                    }

                    switch (rawValue[0])
                    {
                    case "angle":
                        if (!double.TryParse(rawValue[1], out var degrees))
                        {
                            shell.WriteError($"Failed parsing angle '{rawValue[1]}'.");
                            return;
                        }
                        rotation = Angle.FromDegrees(degrees);
                        break;

                    case "zIndex":
                        if (!int.TryParse(rawValue[1], out zIndex))
                        {
                            shell.WriteError($"Failed parsing zIndex '{rawValue[1]}'.");
                            return;
                        }
                        break;

                    case "color":
                        if (!Color.TryFromName(rawValue[1], out var colorRaw))
                        {
                            shell.WriteError($"Failed parsing color '{rawValue[1]}'.");
                            return;
                        }

                        color = colorRaw;
                        break;

                    default:
                        shell.WriteError($"Unknown parameter key '{rawValue[0]}'.");
                        return;
                    }
                }
            }

            if (EntitySystem.Get <DecalSystem>().TryAddDecal(args[0], coordinates, out var uid, color, rotation, zIndex))
            {
                shell.WriteLine($"Successfully created decal {uid}.");
            }
        public async void TryUncuff(IEntity user, IEntity?cuffsToRemove = null)
        {
            if (_uncuffing)
            {
                return;
            }

            var isOwner = user == Owner;

            if (cuffsToRemove == null)
            {
                cuffsToRemove = LastAddedCuffs;
            }
            else
            {
                if (!_container.ContainedEntities.Contains(cuffsToRemove))
                {
                    Logger.Warning("A user is trying to remove handcuffs that aren't in the owner's container. This should never happen!");
                }
            }

            if (!cuffsToRemove.TryGetComponent <HandcuffComponent>(out var cuff))
            {
                Logger.Warning($"A user is trying to remove handcuffs without a {nameof(HandcuffComponent)}. This should never happen!");
                return;
            }

            if (!isOwner && !ActionBlockerSystem.CanInteract(user))
            {
                user.PopupMessage(Loc.GetString("You can't do that!"));
                return;
            }

            if (!isOwner && !user.InRangeUnobstructed(Owner))
            {
                user.PopupMessage(Loc.GetString("You are too far away to remove the cuffs."));
                return;
            }

            if (!cuffsToRemove.InRangeUnobstructed(Owner))
            {
                Logger.Warning("Handcuffs being removed from player are obstructed or too far away! This should not happen!");
                return;
            }

            user.PopupMessage(Loc.GetString("You start removing the cuffs."));

            var audio = EntitySystem.Get <AudioSystem>();

            if (isOwner)
            {
                if (cuff.StartBreakoutSound != null)
                {
                    audio.PlayFromEntity(cuff.StartBreakoutSound, Owner);
                }
            }
            else
            {
                if (cuff.StartUncuffSound != null)
                {
                    audio.PlayFromEntity(cuff.StartUncuffSound, Owner);
                }
            }


            var uncuffTime       = isOwner ? cuff.BreakoutTime : cuff.UncuffTime;
            var doAfterEventArgs = new DoAfterEventArgs(user, uncuffTime)
            {
                BreakOnUserMove = true,
                BreakOnDamage   = true,
                BreakOnStun     = true,
                NeedHand        = true
            };

            var doAfterSystem = EntitySystem.Get <DoAfterSystem>();

            _uncuffing = true;

            var result = await doAfterSystem.DoAfter(doAfterEventArgs);

            _uncuffing = false;

            if (result != DoAfterStatus.Cancelled)
            {
                if (cuff.EndUncuffSound != null)
                {
                    audio.PlayFromEntity(cuff.EndUncuffSound, Owner);
                }

                _container.ForceRemove(cuffsToRemove);
                cuffsToRemove.Transform.AttachToGridOrMap();
                cuffsToRemove.Transform.WorldPosition = Owner.Transform.WorldPosition;

                if (cuff.BreakOnRemove)
                {
                    cuff.Broken = true;

                    cuffsToRemove.Name        = cuff.BrokenName;
                    cuffsToRemove.Description = cuff.BrokenDesc;

                    if (cuffsToRemove.TryGetComponent <SpriteComponent>(out var sprite) && cuff.BrokenState != null)
                    {
                        sprite.LayerSetState(0, cuff.BrokenState); // TODO: safety check to see if RSI contains the state?
                    }
                }

                CanStillInteract = Owner.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.Hands.Count() > CuffedHandCount;
                OnCuffedStateChanged?.Invoke();
                UpdateAlert();
                Dirty();

                if (CuffedHandCount == 0)
                {
                    user.PopupMessage(Loc.GetString("You successfully remove the cuffs."));

                    if (!isOwner)
                    {
                        user.PopupMessage(Owner, Loc.GetString("{0:theName} uncuffs your hands.", user));
                    }
                }
                else
                {
                    if (!isOwner)
                    {
                        user.PopupMessage(Loc.GetString("You successfully remove the cuffs. {0} of {1:theName}'s hands remain cuffed.", CuffedHandCount, user));
                        user.PopupMessage(Owner, Loc.GetString("{0:theName} removes your cuffs. {1} of your hands remain cuffed.", user, CuffedHandCount));
                    }
                    else
                    {
                        user.PopupMessage(Loc.GetString("You successfully remove the cuffs. {0} of your hands remain cuffed.", CuffedHandCount));
                    }
                }
            }
            else
            {
                user.PopupMessage(Loc.GetString("You fail to remove the cuffs."));
            }

            return;
        }
Пример #25
0
        public override void Effect(ReagentEffectArgs args)
        {
            var scale = ScaleByQuantity ? args.Quantity : FixedPoint2.New(1);

            EntitySystem.Get <DamageableSystem>().TryChangeDamage(args.SolutionEntity, Damage * scale, IgnoreResistances);
        }
        // The main "start pulling" function.
        public bool TryStartPull(SharedPullerComponent puller, SharedPullableComponent pullable)
        {
            if (puller.Pulling == pullable)
            {
                return(true);
            }

            // Pulling a new object : Perform sanity checks.

            if (!EntitySystem.Get <SharedPullingSystem>().CanPull(puller.Owner, pullable.Owner))
            {
                return(false);
            }

            if (!puller.Owner.TryGetComponent <PhysicsComponent>(out var pullerPhysics))
            {
                return(false);
            }

            if (!pullable.Owner.TryGetComponent <PhysicsComponent>(out var pullablePhysics))
            {
                return(false);
            }

            // Ensure that the puller is not currently pulling anything.
            // If this isn't done, then it happens too late, and the start/stop messages go out of order,
            //  and next thing you know it thinks it's not pulling anything even though it is!

            var oldPullable = puller.Pulling;

            if (oldPullable != null)
            {
                if (oldPullable.TryGetComponent <SharedPullableComponent>(out var oldPullableComp))
                {
                    if (!TryStopPull(oldPullableComp))
                    {
                        return(false);
                    }
                }
                else
                {
                    Logger.WarningS("c.go.c.pulling", "Well now you've done it, haven't you? Someone transferred pulling (onto {0}) while presently pulling something that has no Pullable component (on {1})!", pullable.Owner, oldPullable);
                    return(false);
                }
            }

            // Ensure that the pullable is not currently being pulled.
            // Same sort of reasons as before.

            var oldPuller = pullable.Puller;

            if (oldPuller != null)
            {
                if (!TryStopPull(pullable))
                {
                    return(false);
                }
            }

            // Continue with pulling process.

            var pullAttempt = new PullAttemptMessage(pullerPhysics, pullablePhysics);

            RaiseLocalEvent(puller.Owner.Uid, pullAttempt, broadcast: false);

            if (pullAttempt.Cancelled)
            {
                return(false);
            }

            RaiseLocalEvent(pullable.Owner.Uid, pullAttempt);

            if (pullAttempt.Cancelled)
            {
                return(false);
            }

            _pullSm.ForceRelationship(puller, pullable);
            return(true);
        }
Пример #27
0
 public void Execute(IConsoleShell shell, string argStr, string[] args)
 {
     EntitySystem.Get <GameTicker>().RestartRound();
 }
        public void Update()
        {
            UpdateReagents();

            var curTime = _gameTiming.CurTime;

            if (ForceUpdate)
            {
                ForceUpdate = false;
            }
            else if (curTime < (_lastCycle + _cycleDelay))
            {
                if (_updateSpriteAfterUpdate)
                {
                    UpdateSprite();
                }
                return;
            }

            _lastCycle = curTime;


            // Weeds like water and nutrients! They may appear even if there's not a seed planted.
            if (WaterLevel > 10 && NutritionLevel > 2 && _random.Prob(Seed == null ? 0.05f : 0.01f))
            {
                WeedLevel += 1 * HydroponicsSpeedMultiplier * WeedCoefficient;

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // There's a chance for a weed explosion to happen if weeds take over.
            // Plants that are themselves weeds (WeedTolerance > 8) are unaffected.
            if (WeedLevel >= 10 && _random.Prob(0.1f))
            {
                if (Seed == null || WeedLevel >= Seed.WeedTolerance + 2)
                {
                    WeedInvasion();
                }
            }

            // If we have no seed planted, or the plant is dead, stop processing here.
            if (Seed == null || Dead)
            {
                if (_updateSpriteAfterUpdate)
                {
                    UpdateSprite();
                }

                return;
            }

            // There's a small chance the pest population increases.
            // Can only happen when there's a live seed planted.
            if (_random.Prob(0.01f))
            {
                PestLevel += 0.5f * HydroponicsSpeedMultiplier;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Advance plant age here.
            if (SkipAging > 0)
            {
                SkipAging--;
            }
            else
            {
                if (_random.Prob(0.8f))
                {
                    Age += (int)(1 * HydroponicsSpeedMultiplier);
                }

                _updateSpriteAfterUpdate = true;
            }

            // Nutrient consumption.
            if (Seed.NutrientConsumption > 0 && NutritionLevel > 0 && _random.Prob(0.75f))
            {
                NutritionLevel -= MathF.Max(0f, Seed.NutrientConsumption * HydroponicsSpeedMultiplier);
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Water consumption.
            if (Seed.WaterConsumption > 0 && WaterLevel > 0 && _random.Prob(0.75f))
            {
                WaterLevel -= MathF.Max(0f,
                                        Seed.NutrientConsumption * HydroponicsConsumptionMultiplier * HydroponicsSpeedMultiplier);
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            var healthMod = _random.Next(1, 3) * HydroponicsSpeedMultiplier;

            // Make sure the plant is not starving.
            if (_random.Prob(0.35f))
            {
                if (NutritionLevel > 2)
                {
                    Health += healthMod;
                }
                else
                {
                    AffectGrowth(-1);
                    Health -= healthMod;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Make sure the plant is not thirsty.
            if (_random.Prob(0.35f))
            {
                if (WaterLevel > 10)
                {
                    Health += healthMod;
                }
                else
                {
                    AffectGrowth(-1);
                    Health -= healthMod;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            var environment = EntitySystem.Get <AtmosphereSystem>().GetTileMixture(Owner.Transform.Coordinates, true) ??
                              GasMixture.SpaceGas;

            if (Seed.ConsumeGasses.Count > 0)
            {
                _missingGas = 0;

                foreach (var(gas, amount) in Seed.ConsumeGasses)
                {
                    if (environment.GetMoles(gas) < amount)
                    {
                        _missingGas++;
                        continue;
                    }

                    environment.AdjustMoles(gas, -amount);
                }

                if (_missingGas > 0)
                {
                    Health -= _missingGas * HydroponicsSpeedMultiplier;
                    if (DrawWarnings)
                    {
                        _updateSpriteAfterUpdate = true;
                    }
                }
            }

            // Seed pressure resistance.
            var pressure = environment.Pressure;

            if (pressure < Seed.LowPressureTolerance || pressure > Seed.HighPressureTolerance)
            {
                Health          -= healthMod;
                ImproperPressure = true;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else
            {
                ImproperPressure = false;
            }

            // Seed ideal temperature.
            if (MathF.Abs(environment.Temperature - Seed.IdealHeat) > Seed.HeatTolerance)
            {
                Health      -= healthMod;
                ImproperHeat = true;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else
            {
                ImproperHeat = false;
            }

            // Gas production.
            var exudeCount = Seed.ExudeGasses.Count;

            if (exudeCount > 0)
            {
                foreach (var(gas, amount) in Seed.ExudeGasses)
                {
                    environment.AdjustMoles(gas,
                                            MathF.Max(1f, MathF.Round((amount * MathF.Round(Seed.Potency)) / exudeCount)));
                }
            }

            // Toxin levels beyond the plant's tolerance cause damage.
            // They are, however, slowly reduced over time.
            if (Toxins > 0)
            {
                var toxinUptake = MathF.Max(1, MathF.Round(Toxins / 10f));
                if (Toxins > Seed.ToxinsTolerance)
                {
                    Health -= toxinUptake;
                }

                Toxins -= toxinUptake;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Weed levels.
            if (PestLevel > 0)
            {
                // TODO: Carnivorous plants?
                if (PestLevel > Seed.PestTolerance)
                {
                    Health -= HydroponicsSpeedMultiplier;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Weed levels.
            if (WeedLevel > 0)
            {
                // TODO: Parasitic plants.
                if (WeedLevel >= Seed.WeedTolerance)
                {
                    Health -= HydroponicsSpeedMultiplier;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            if (Age > Seed.Lifespan)
            {
                Health -= _random.Next(3, 5) * HydroponicsSpeedMultiplier;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else if (Age < 0) // Revert back to seed packet!
            {
                Seed.SpawnSeedPacket(Owner.Transform.Coordinates);
                RemovePlant();
                ForceUpdate = true;
                Update();
            }

            CheckHealth();

            if (Harvest && Seed.HarvestRepeat == HarvestType.SelfHarvest)
            {
                AutoHarvest();
            }

            // If enough time has passed since the plant was harvested, we're ready to harvest again!
            if (!Dead && Seed.ProductPrototypes.Count > 0)
            {
                if (Age > Seed.Production)
                {
                    if ((Age - _lastProduce) > Seed.Production && !Harvest)
                    {
                        Harvest      = true;
                        _lastProduce = Age;
                    }
                }
                else
                {
                    if (Harvest)
                    {
                        Harvest      = false;
                        _lastProduce = Age;
                    }
                }
            }

            CheckLevelSanity();

            if (_updateSpriteAfterUpdate)
            {
                UpdateSprite();
            }
        }
Пример #29
0
 private void Rustle()
 {
     EntitySystem.Get <AudioSystem>()
     .PlayFromEntity("/Audio/Effects/plant_rustle.ogg", Owner, AudioHelpers.WithVariation(0.25f));
 }
Пример #30
0
        public void DoTargetEntityAction(TargetEntityActionEventArgs args)
        {
            var disarmedActs = args.Target.GetAllComponents <IDisarmedAct>().ToArray();

            if (!args.Performer.InRangeUnobstructed(args.Target))
            {
                return;
            }

            if (disarmedActs.Length == 0)
            {
                if (args.Performer.TryGetComponent(out IActorComponent? actor))
                {
                    // Fall back to a normal interaction with the entity
                    var player      = actor.playerSession;
                    var coordinates = args.Target.Transform.Coordinates;
                    var target      = args.Target.Uid;
                    EntitySystem.Get <InteractionSystem>().HandleClientUseItemInHand(player, coordinates, target);
                    return;
                }

                return;
            }

            if (!args.Performer.TryGetComponent <SharedActionsComponent>(out var actions))
            {
                return;
            }
            if (args.Target == args.Performer || !args.Performer.CanAttack())
            {
                return;
            }

            var random = IoCManager.Resolve <IRobustRandom>();
            var audio  = EntitySystem.Get <AudioSystem>();
            var system = EntitySystem.Get <MeleeWeaponSystem>();

            var diff  = args.Target.Transform.MapPosition.Position - args.Performer.Transform.MapPosition.Position;
            var angle = Angle.FromWorldVec(diff);

            actions.Cooldown(ActionType.Disarm, Cooldowns.SecondsFromNow(_cooldown));

            if (random.Prob(_failProb))
            {
                SoundSystem.Play(Filter.Pvs(args.Performer), "/Audio/Weapons/punchmiss.ogg", args.Performer,
                                 AudioHelpers.WithVariation(0.025f));
                args.Performer.PopupMessageOtherClients(Loc.GetString("{0} fails to disarm {1}!", args.Performer.Name, args.Target.Name));
                args.Performer.PopupMessageCursor(Loc.GetString("You fail to disarm {0}!", args.Target.Name));
                system.SendLunge(angle, args.Performer);
                return;
            }

            system.SendAnimation("disarm", angle, args.Performer, args.Performer, new [] { args.Target });

            var eventArgs = new DisarmedActEventArgs()
            {
                Target = args.Target, Source = args.Performer, PushProbability = _pushProb
            };

            // Sort by priority.
            Array.Sort(disarmedActs, (a, b) => a.Priority.CompareTo(b.Priority));

            foreach (var disarmedAct in disarmedActs)
            {
                if (disarmedAct.Disarmed(eventArgs))
                {
                    return;
                }
            }

            SoundSystem.Play(Filter.Pvs(args.Performer), "/Audio/Effects/thudswoosh.ogg", args.Performer,
                             AudioHelpers.WithVariation(0.025f));
        }