public async Task <DoAfterStatus> DoAfter(DoAfterEventArgs eventArgs)
        {
            // Setup
            var doAfter = new DoAfter(eventArgs);
            // Caller's gonna be responsible for this I guess
            var doAfterComponent = eventArgs.User.GetComponent <DoAfterComponent>();

            doAfterComponent.Add(doAfter);
            DamageableComponent?damageableComponent = null;

            // TODO: If the component's deleted this may not get unsubscribed?
            if (eventArgs.BreakOnDamage && eventArgs.User.TryGetComponent(out damageableComponent))
            {
                damageableComponent.Damaged += doAfter.HandleDamage;
            }

            await doAfter.AsTask;

            if (damageableComponent != null)
            {
                damageableComponent.Damaged -= doAfter.HandleDamage;
            }

            return(doAfter.Status);
        }
Exemple #2
0
        private async void HandleAfterInteract(EntityUid uid, SpawnAfterInteractComponent component, AfterInteractMessage args)
        {
            if (string.IsNullOrEmpty(component.Prototype))
            {
                return;
            }
            if (!_mapManager.TryGetGrid(args.ClickLocation.GetGridId(EntityManager), out var grid))
            {
                return;
            }
            if (!grid.TryGetTileRef(args.ClickLocation, out var tileRef))
            {
                return;
            }

            bool IsTileClear()
            {
                return(tileRef.Tile.IsEmpty == false && args.User.InRangeUnobstructed(args.ClickLocation, popup: true));
            }

            if (!IsTileClear())
            {
                return;
            }

            if (component.DoAfterTime > 0 && TryGet <DoAfterSystem>(out var doAfterSystem))
            {
                var doAfterArgs = new DoAfterEventArgs(args.User, component.DoAfterTime)
                {
                    BreakOnUserMove = true,
                    BreakOnStun     = true,
                    PostCheck       = IsTileClear,
                };
                var result = await doAfterSystem.DoAfter(doAfterArgs);

                if (result != DoAfterStatus.Finished)
                {
                    return;
                }
            }

            if (component.Deleted || component.Owner.Deleted)
            {
                return;
            }

            StackComponent?stack = null;

            if (component.RemoveOnInteract && component.Owner.TryGetComponent(out stack) && !stack.Use(1))
            {
                return;
            }

            EntityManager.SpawnEntity(component.Prototype, args.ClickLocation.SnapToGrid(grid));

            if (component.RemoveOnInteract && stack == null && !component.Owner.Deleted)
            {
                component.Owner.Delete();
            }
        }
        public DoAfter(DoAfterEventArgs eventArgs)
        {
            EventArgs = eventArgs;
            StartTime = IoCManager.Resolve <IGameTiming>().CurTime;

            if (eventArgs.BreakOnUserMove)
            {
                UserGrid = eventArgs.User.Transform.GridPosition;
            }

            if (eventArgs.BreakOnTargetMove)
            {
                // Target should never be null if the bool is set.
                TargetGrid = eventArgs.Target !.Transform.GridPosition;
            }

            // For this we need to stay on the same hand slot and need the same item in that hand slot
            // (or if there is no item there we need to keep it free).
            if (eventArgs.NeedHand && eventArgs.User.TryGetComponent(out HandsComponent handsComponent))
            {
                _activeHand = handsComponent.ActiveHand;
                _activeItem = handsComponent.GetActiveHand;
            }

            Tcs    = new TaskCompletionSource <DoAfterStatus>();
            AsTask = Tcs.Task;
        }
Exemple #4
0
        private async void HandleActivateInWorld(EntityUid uid, DisassembleOnActivateComponent component, ActivateInWorldEvent args)
        {
            if (string.IsNullOrEmpty(component.Prototype))
            {
                return;
            }
            if (!args.User.InRangeUnobstructed(args.Target))
            {
                return;
            }

            if (component.DoAfterTime > 0 && TryGet <DoAfterSystem>(out var doAfterSystem))
            {
                var doAfterArgs = new DoAfterEventArgs(args.User, component.DoAfterTime, component.TokenSource.Token)
                {
                    BreakOnUserMove = true,
                    BreakOnStun     = true,
                };
                var result = await doAfterSystem.DoAfter(doAfterArgs);

                if (result != DoAfterStatus.Finished)
                {
                    return;
                }
                component.TokenSource.Cancel();
            }

            if (component.Deleted || component.Owner.Deleted)
            {
                return;
            }

            var entity = EntityManager.SpawnEntity(component.Prototype, component.Owner.Transform.Coordinates);

            if (args.User.TryGetComponent <HandsComponent>(out var hands) &&
                entity.TryGetComponent <ItemComponent>(out var item))
            {
                hands.PutInHandOrDrop(item);
            }

            component.Owner.Delete();

            return;
        }
Exemple #5
0
        private async Task <IEntity?> Construct(IEntity user, string materialContainer, ConstructionGraphPrototype graph, ConstructionGraphEdge edge, ConstructionGraphNode targetNode)
        {
            // We need a place to hold our construction items!
            var container = ContainerManagerComponent.Ensure <Container>(materialContainer, user, out var existed);

            if (existed)
            {
                user.PopupMessageCursor(Loc.GetString("You can't start another construction now!"));
                return(null);
            }

            var containers = new Dictionary <string, Container>();

            var doAfterTime = 0f;

            // HOLY SHIT THIS IS SOME HACKY CODE.
            // But I'd rather do this shit than risk having collisions with other containers.
            Container GetContainer(string name)
            {
                if (containers !.ContainsKey(name))
                {
                    return(containers[name]);
                }

                while (true)
                {
                    var random = _robustRandom.Next();
                    var c      = ContainerManagerComponent.Ensure <Container>(random.ToString(), user !, out var existed);

                    if (existed)
                    {
                        continue;
                    }

                    containers[name] = c;
                    return(c);
                }
            }

            void FailCleanup()
            {
                foreach (var entity in container !.ContainedEntities.ToArray())
                {
                    container.Remove(entity);
                }

                foreach (var cont in containers !.Values)
                {
                    foreach (var entity in cont.ContainedEntities.ToArray())
                    {
                        cont.Remove(entity);
                    }
                }

                // If we don't do this, items are invisible for some f*****g reason. Nice.
                Timer.Spawn(1, ShutdownContainers);
            }

            void ShutdownContainers()
            {
                container !.Shutdown();
                foreach (var c in containers !.Values.ToArray())
                {
                    c.Shutdown();
                }
            }

            var failed = false;

            var steps = new List <ConstructionGraphStep>();

            foreach (var step in edge.Steps)
            {
                doAfterTime += step.DoAfter;

                var handled = false;

                switch (step)
                {
                case MaterialConstructionGraphStep materialStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!materialStep.EntityValid(entity, out var sharedStack))
                        {
                            continue;
                        }

                        var stack = (StackComponent)sharedStack;

                        if (!stack.Split(materialStep.Amount, user.ToCoordinates(), out var newStack))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(materialStep.Store))
                        {
                            if (!container.Insert(newStack))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(materialStep.Store).Insert(newStack))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;

                case ComponentConstructionGraphStep componentStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!componentStep.EntityValid(entity))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(componentStep.Store))
                        {
                            if (!container.Insert(entity))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(componentStep.Store).Insert(entity))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;

                case PrototypeConstructionGraphStep prototypeStep:
                    foreach (var entity in EnumerateNearby(user))
                    {
                        if (!prototypeStep.EntityValid(entity))
                        {
                            continue;
                        }

                        if (string.IsNullOrEmpty(prototypeStep.Store))
                        {
                            if (!container.Insert(entity))
                            {
                                continue;
                            }
                        }
                        else if (!GetContainer(prototypeStep.Store).Insert(entity))
                        {
                            continue;
                        }

                        handled = true;
                        break;
                    }

                    break;
                }

                if (handled == false)
                {
                    failed = true;
                    break;
                }

                steps.Add(step);
            }

            if (failed)
            {
                user.PopupMessageCursor(Loc.GetString("You don't have the materials to build that!"));
                FailCleanup();
                return(null);
            }

            var doAfterSystem = Get <DoAfterSystem>();

            var doAfterArgs = new DoAfterEventArgs(user, doAfterTime)
            {
                BreakOnDamage     = true,
                BreakOnStun       = true,
                BreakOnTargetMove = false,
                BreakOnUserMove   = true,
                NeedHand          = true,
            };

            if (await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Cancelled)
            {
                FailCleanup();
                return(null);
            }

            var newEntity = EntityManager.SpawnEntity(graph.Nodes[edge.Target].Entity, user.Transform.Coordinates);

            // Yes, this should throw if it's missing the component.
            var construction = newEntity.GetComponent <ConstructionComponent>();

            // We attempt to set the pathfinding target.
            construction.Target = targetNode;

            // We preserve the containers...
            foreach (var(name, cont) in containers)
            {
                var newCont = ContainerManagerComponent.Ensure <Container>(name, newEntity);

                foreach (var entity in cont.ContainedEntities.ToArray())
                {
                    cont.ForceRemove(entity);
                    newCont.Insert(entity);
                }
            }

            // We now get rid of all them.
            ShutdownContainers();

            // We have step completed steps!
            foreach (var step in steps)
            {
                foreach (var completed in step.Completed)
                {
                    await completed.PerformAction(newEntity, user);
                }
            }

            // And we also have edge completed effects!
            foreach (var completed in edge.Completed)
            {
                await completed.PerformAction(newEntity, user);
            }

            return(newEntity);
        }