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); }
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; }
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; }
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); }