using Content.Server._DV.Objectives.Components; using Content.Server.Objectives.Systems; using Content.Server.Stack; using Content.Server.Store.Systems; using Content.Shared._DV.Objectives.Systems; using Content.Shared._DV.Reputation; using Content.Shared.FixedPoint; using Content.Shared.Ghost; using Content.Shared.Hands.EntitySystems; using Content.Shared.Mind; using Robust.Shared.Prototypes; using System.Linq; namespace Content.Server._DV.Objectives.Systems; /// /// Handles reputation + TC gains for . /// public sealed class ContractObjectiveSystem : SharedContractObjectiveSystem { [Dependency] private readonly CodeConditionSystem _codeCondition = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly ReputationSystem _reputation = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StoreSystem _store = default!; private Dictionary _currency = new(); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnTaken); SubscribeLocalEvent(OnCompleted); } private void OnTaken(Entity ent, ref ContractTakenEvent args) { ent.Comp.Contracts = args.Contracts; if (ent.Comp.Prepaid) Pay(ent); } private void OnCompleted(Entity ent, ref ContractCompletedEvent args) { _reputation.GiveReputation(args.Contracts, ent.Comp.Reputation); if (!ent.Comp.Prepaid) Pay(ent); } private void Pay(Entity ent) { if (_reputation.GetContracts(ent.Comp.Contracts) is not {} contracts) return; if (contracts.Comp.Store is {} store) { _currency.Clear(); _currency[ent.Comp.Currency] = ent.Comp.Payment; _store.TryAddCurrency(_currency, store); return; } // try give them TC item there's no store var mind = Comp(contracts); // no mob unlucky if (mind.OwnedEntity is not {} mob) return; // don't spawn tc under ghosts, give the dead body TC instead if (HasComp(mob)) { // cremated, no TC for you! if (GetEntity(mind.OriginalOwnedEntity) is not {} original) return; mob = original; } if (!Exists(mob)) return; // this is copy pasted from store system because it has no API for spawning cash entities var coords = Transform(mob).Coordinates; var amountRemaining = ent.Comp.Payment; var proto = _proto.Index(ent.Comp.Currency); foreach (var value in proto.Cash!.Keys.OrderByDescending(x => x)) { var cashId = proto.Cash[value]; var amountToSpawn = (int) MathF.Floor((float) (amountRemaining / value)); var ents = _stack.SpawnMultiple(cashId, amountToSpawn, coords); if (ents.FirstOrDefault() is {} cash) _hands.PickupOrDrop(mob, cash); amountRemaining -= value * amountToSpawn; } } /// /// Fail all active incomplete contracts with a given component, based on a predicate. /// public void FailContracts(Predicate> pred) where T: Component { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp, out var contract)) { if (_codeCondition.IsCompleted(uid) || !pred((uid, comp))) continue; if (_reputation.GetContracts(contract.Contracts) is {} contracts) _reputation.TryFailContract(contracts, uid); } } /// /// Look up an objective's stored pda and try to fail it. /// public bool TryFailContract(Entity objective) { return Resolve(objective, ref objective.Comp) && _reputation.GetContracts(objective.Comp.Contracts) is {} contracts && _reputation.TryFailContract(contracts, objective); } public override string ContractName(EntityUid objective) { var title = base.ContractName(objective); if (!TryComp(objective, out var contract)) return title; return $"{title} - {contract.Reputation} REP + {contract.Payment} TC"; } }