private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
        {
            if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
            {
                return;
            }

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(_transferAmount, targetBloodstream.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                Owner.PopupMessage(user, Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner));
                return;
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = solution.SplitSolution(realTransferAmount);

            if (!targetBloodstream.TryTransferSolution(removedSolution))
            {
                return;
            }

            Owner.PopupMessage(user, Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, targetBloodstream.Owner));
            Dirty();
        }
    private void TryInjectIntoBloodstream(InjectorComponent component, BloodstreamComponent targetBloodstream, EntityUid user)
    {
        // Get transfer amount. May be smaller than _transferAmount if not enough room
        var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.ChemicalSolution.AvailableVolume);

        if (realTransferAmount <= 0)
        {
            _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", targetBloodstream.Owner)),
                               component.Owner, Filter.Entities(user));
            return;
        }

        // Move units from attackSolution to targetSolution
        var removedSolution = _solutions.SplitSolution(user, targetBloodstream.ChemicalSolution, realTransferAmount);

        _blood.TryAddToChemicals((targetBloodstream).Owner, removedSolution, targetBloodstream);

        removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection);

        _popup.PopupEntity(Loc.GetString("injector-component-inject-success-message",
                                         ("amount", removedSolution.TotalVolume),
                                         ("target", targetBloodstream.Owner)), component.Owner, Filter.Entities(user));

        Dirty(component);
        AfterInject(component);
    }
        public GasMixture Clean(EntityUid uid, RespiratorComponent respirator, BloodstreamComponent bloodstream)
        {
            var gasMixture = new GasMixture(bloodstream.Air.Volume)
            {
                Temperature = bloodstream.Air.Temperature
            };

            for (Gas gas = 0; gas < (Gas)Atmospherics.TotalNumberOfGases; gas++)
            {
                float amount;
                var   molesInBlood = bloodstream.Air.GetMoles(gas);

                if (!respirator.NeedsGases.TryGetValue(gas, out var needed))
                {
                    amount = molesInBlood;
                }
                else
                {
                    var overflowThreshold = needed * 5f;

                    amount = molesInBlood > overflowThreshold
                        ? molesInBlood - overflowThreshold
                        : 0;
                }

                gasMixture.AdjustMoles(gas, amount);
                bloodstream.Air.AdjustMoles(gas, -amount);
            }

            return(gasMixture);
        }
Example #4
0
    private void OnReactionAttempt(EntityUid uid, BloodstreamComponent component, ReactionAttemptEvent args)
    {
        if (args.Solution.Name != BloodstreamComponent.DefaultBloodSolutionName &&
            args.Solution.Name != BloodstreamComponent.DefaultChemicalsSolutionName &&
            args.Solution.Name != BloodstreamComponent.DefaultBloodTemporarySolutionName)
        {
            return;
        }

        foreach (var effect in args.Reaction.Effects)
        {
            switch (effect)
            {
            case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream
            case AreaReactionEffect:         // No spontaneous smoke or foam leaking out of blood vessels.
                args.Cancel();
                return;
            }
        }

        // The area-reaction effect canceling is part of avoiding smoke-fork-bombs (create two smoke bombs, that when
        // ingested by mobs create more smoke). This also used to act as a rapid chemical-purge, because all the
        // reagents would get carried away by the smoke/foam. This does still work for the stomach (I guess people vomit
        // up the smoke or spawned entities?).

        // TODO apply organ damage instead of just blocking the reaction?
        // Having cheese-clots form in your veins can't be good for you.
    }
Example #5
0
 private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args)
 {
     component.Solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName);
     if (component.Solution != null)
     {
         component.Solution.MaxVolume = component.InitialMaxVolume;
     }
 }
Example #6
0
    private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args)
    {
        component.ChemicalSolution       = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultChemicalsSolutionName);
        component.BloodSolution          = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodSolutionName);
        component.BloodTemporarySolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodTemporarySolutionName);

        component.ChemicalSolution.MaxVolume       = component.ChemicalMaxVolume;
        component.BloodSolution.MaxVolume          = component.BloodMaxVolume;
        component.BloodTemporarySolution.MaxVolume = component.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well

        // Fill blood solution with BLOOD
        _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent,
                                               component.BloodMaxVolume, out _);
    }
Example #7
0
 private void OnApplyMetabolicMultiplier(EntityUid uid, BloodstreamComponent component, ApplyMetabolicMultiplierEvent args)
 {
     if (args.Apply)
     {
         component.UpdateInterval *= args.Multiplier;
         return;
     }
     component.UpdateInterval /= args.Multiplier;
     // Reset the accumulator properly
     if (component.AccumulatedFrametime >= component.UpdateInterval)
     {
         component.AccumulatedFrametime = component.UpdateInterval;
     }
 }
Example #8
0
        private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
        {
            if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
            {
                return;
            }

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(_transferAmount, targetBloodstream.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                Owner.PopupMessage(user, Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner));
                return;
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = solution.SplitSolution(realTransferAmount);

            if (!solution.CanAddSolution(removedSolution))
            {
                return;
            }

            // TODO: Account for partial transfer.

            foreach (var(reagentId, quantity) in removedSolution.Contents)
            {
                if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent))
                {
                    continue;
                }
                removedSolution.RemoveReagent(reagentId, reagent.ReactionEntity(solution.Owner, ReactionMethod.Injection, quantity));
            }

            solution.TryAddSolution(removedSolution);

            foreach (var(reagentId, quantity) in removedSolution.Contents)
            {
                if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent))
                {
                    continue;
                }
                reagent.ReactionEntity(targetBloodstream.Owner, ReactionMethod.Injection, quantity);
            }

            Owner.PopupMessage(user, Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, targetBloodstream.Owner));
            Dirty();
        }
Example #9
0
    private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args)
    {
        if (args.DamageDelta is null)
        {
            return;
        }

        // TODO probably cache this or something. humans get hurt a lot
        if (!_prototypeManager.TryIndex <DamageModifierSetPrototype>(component.DamageBleedModifiers, out var modifiers))
        {
            return;
        }

        var bloodloss = DamageSpecifier.ApplyModifierSet(args.DamageDelta, modifiers);

        if (bloodloss.Empty)
        {
            return;
        }

        var oldBleedAmount = component.BleedAmount;
        var total          = bloodloss.Total;
        var totalFloat     = total.Float();

        TryModifyBleedAmount(uid, totalFloat, component);

        var prob          = Math.Clamp(totalFloat / 50, 0, 1);
        var healPopupProb = Math.Clamp(Math.Abs(totalFloat) / 25, 0, 1);

        if (totalFloat > 0 && _robustRandom.Prob(prob))
        {
            TryModifyBloodLevel(uid, (-total) / 5, component);
            SoundSystem.Play(Filter.Pvs(uid), component.InstantBloodSound.GetSound(), uid, AudioParams.Default);
        }
        else if (totalFloat < 0 && oldBleedAmount > 0 && _robustRandom.Prob(healPopupProb))
        {
            // Magically, this damage has healed some bleeding, likely
            // because it's burn damage that cauterized their wounds.

            // We'll play a special sound and popup for feedback.
            SoundSystem.Play(Filter.Pvs(uid), component.BloodHealedSound.GetSound(), uid, AudioParams.Default);
            _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), uid,
                                     Filter.Entities(uid));
            ;
        }
    }
Example #10
0
    private void OnHealthBeingExamined(EntityUid uid, BloodstreamComponent component, HealthBeingExaminedEvent args)
    {
        if (component.BleedAmount > 10)
        {
            args.Message.PushNewline();
            args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", uid)));
        }
        else if (component.BleedAmount > 0)
        {
            args.Message.PushNewline();
            args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", uid)));
        }

        if (GetBloodLevelPercentage(uid, component) < component.BloodlossThreshold)
        {
            args.Message.PushNewline();
            args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", uid)));
        }
    }
Example #11
0
 private void OnBeingGibbed(EntityUid uid, BloodstreamComponent component, BeingGibbedEvent args)
 {
     SpillAllSolutions(uid, component);
 }
    private void DrawFromBlood(EntityUid user, EntityUid target, InjectorComponent component, Solution injectorSolution, BloodstreamComponent stream, FixedPoint2 transferAmount)
    {
        var drawAmount  = (float)transferAmount;
        var bloodAmount = drawAmount;
        var chemAmount  = 0f;

        if (stream.ChemicalSolution.CurrentVolume > 0f) // If they have stuff in their chem stream, we'll draw some of that
        {
            bloodAmount = drawAmount * 0.85f;
            chemAmount  = drawAmount * 0.15f;
        }

        var bloodTemp = stream.BloodSolution.SplitSolution(bloodAmount);
        var chemTemp  = stream.ChemicalSolution.SplitSolution(chemAmount);

        _solutions.TryAddSolution(component.Owner, injectorSolution, bloodTemp);
        _solutions.TryAddSolution(component.Owner, injectorSolution, chemTemp);

        _popup.PopupEntity(Loc.GetString("injector-component-draw-success-message",
                                         ("amount", transferAmount),
                                         ("target", Identity.Entity(target, EntityManager))), component.Owner, Filter.Entities(user));

        Dirty(component);
        AfterDraw(component);
    }