public void StartOpeningStripper(EntityUid user, StrippableComponent component) { if (component.CancelTokens.ContainsKey(user)) { return; } if (TryComp <ActorComponent>(user, out var actor)) { if (component.Owner.GetUIOrNull(StrippingUiKey.Key)?.SessionHasOpen(actor.PlayerSession) == true) { return; } } var token = new CancellationTokenSource(); var doAfterArgs = new DoAfterEventArgs(user, component.OpenDelay, token.Token, component.Owner) { BreakOnStun = true, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, TargetCancelledEvent = new OpenStrippingCancelledEvent(user), TargetFinishedEvent = new OpenStrippingCompleteEvent(user), }; component.CancelTokens[user] = token; _doAfterSystem.DoAfter(doAfterArgs); }
// construct the doafter and start it private void StartListening(EntityUid user, EntityUid target, StethoscopeComponent comp) { comp.CancelToken = new CancellationTokenSource(); _doAfterSystem.DoAfter(new DoAfterEventArgs(user, comp.Delay, comp.CancelToken.Token, target: target) { BroadcastFinishedEvent = new ListenSuccessfulEvent(user, target, comp), BroadcastCancelledEvent = new ListenCancelledEvent(user, comp), BreakOnTargetMove = true, BreakOnUserMove = true, BreakOnStun = true, NeedHand = true }); }
/// <summary> /// Sync version of UseTool. /// </summary> /// <param name="tool">The tool entity.</param> /// <param name="user">The entity using the tool.</param> /// <param name="target">Optionally, a target to use the tool on.</param> /// <param name="fuel">An optional amount of fuel or energy to consume-</param> /// <param name="doAfterDelay">A doAfter delay in seconds.</param> /// <param name="toolQualitiesNeeded">The tool qualities needed to use the tool.</param> /// <param name="doAfterCompleteEvent">An event to raise once the doAfter is completed successfully.</param> /// <param name="doAfterCancelledEvent">An event to raise once the doAfter is canceled.</param> /// <param name="doAfterEventTarget">Where to direct the do-after events. If null, events are broadcast</param> /// <param name="doAfterCheck">An optional check to perform for the doAfter.</param> /// <param name="toolComponent">The tool component.</param> /// <param name="cancelToken">Token to provide to do_after for cancelling</param> /// <returns>Whether initially, using the tool succeeded. If there's a doAfter delay, you'll need to listen to /// the <see cref="doAfterCompleteEvent"/> and <see cref="doAfterCancelledEvent"/> being broadcast /// to see whether using the tool succeeded or not. If the <see cref="doAfterDelay"/> is zero, /// this simply returns whether using the tool succeeded or not.</returns> public bool UseTool( EntityUid tool, EntityUid user, EntityUid?target, float fuel, float doAfterDelay, IEnumerable <string> toolQualitiesNeeded, object?doAfterCompleteEvent = null, object?doAfterCancelledEvent = null, EntityUid?doAfterEventTarget = null, Func <bool>?doAfterCheck = null, ToolComponent?toolComponent = null, CancellationToken?cancelToken = null) { // No logging here, after all that'd mean the caller would need to check if the component is there or not. if (!Resolve(tool, ref toolComponent, false)) { return(false); } if (!ToolStartUse(tool, user, fuel, toolQualitiesNeeded, toolComponent)) { return(false); } if (doAfterDelay > 0f) { var doAfterArgs = new DoAfterEventArgs(user, doAfterDelay / toolComponent.SpeedModifier, cancelToken ?? default, target) { ExtraCheck = doAfterCheck, BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, BroadcastFinishedEvent = doAfterCompleteEvent != null ? new ToolDoAfterComplete(doAfterCompleteEvent, doAfterCancelledEvent, tool, user, fuel, doAfterEventTarget) : null, BroadcastCancelledEvent = doAfterCancelledEvent != null ? new ToolDoAfterCancelled(doAfterCancelledEvent, doAfterEventTarget) : null, }; _doAfterSystem.DoAfter(doAfterArgs); return(true); } return(ToolFinishUse(tool, user, fuel, toolComponent)); }
private void DisarmBombDoafter(EntityUid uid, EntityUid user, NukeComponent nuke) { nuke.DisarmCancelToken = new(); var doafter = new DoAfterEventArgs(user, nuke.DisarmDoafterLength, nuke.DisarmCancelToken.Value, uid) { TargetCancelledEvent = new NukeDisarmCancelledEvent(), TargetFinishedEvent = new NukeDisarmSuccessEvent(), BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, }; _doAfterSystem.DoAfter(doafter); _popups.PopupEntity(Loc.GetString("nuke-component-doafter-warning"), user, Filter.Entities(user), PopupType.LargeCaution); }
async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { //No changing mode mid-RCD var startingMode = _mode; var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GetGridId(Owner.EntityManager)); var tile = mapGrid.GetTileRef(eventArgs.ClickLocation); var snapPos = mapGrid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center); //Using an RCD isn't instantaneous var cancelToken = new CancellationTokenSource(); var doAfterEventArgs = new DoAfterEventArgs(eventArgs.User, _delay, cancelToken.Token, eventArgs.Target) { BreakOnDamage = true, BreakOnStun = true, NeedHand = true, ExtraCheck = () => IsRCDStillValid(eventArgs, mapGrid, tile, snapPos, startingMode) //All of the sanity checks are here }; var result = await doAfterSystem.DoAfter(doAfterEventArgs); if (result == DoAfterStatus.Cancelled) { return(true); } switch (_mode) { //Floor mode just needs the tile to be a space tile (subFloor) case RcdMode.Floors: mapGrid.SetTile(eventArgs.ClickLocation, new Tile(_tileDefinitionManager["floor_steel"].TileId)); break; //We don't want to place a space tile on something that's already a space tile. Let's do the inverse of the last check. case RcdMode.Deconstruct: if (!tile.IsBlockedTurf(true)) //Delete the turf { mapGrid.SetTile(snapPos, Tile.Empty); } else //Delete what the user targeted { eventArgs.Target.Delete(); } break; //Walls are a special behaviour, and require us to build a new object with a transform rather than setting a grid tile, thus we early return to avoid the tile set code. case RcdMode.Walls: var ent = _serverEntityManager.SpawnEntity("solid_wall", mapGrid.GridTileToLocal(snapPos)); ent.Transform.LocalRotation = Owner.Transform.LocalRotation; //Now apply icon smoothing. break; case RcdMode.Airlock: var airlock = _serverEntityManager.SpawnEntity("Airlock", mapGrid.GridTileToLocal(snapPos)); airlock.Transform.LocalRotation = Owner.Transform.LocalRotation; //Now apply icon smoothing. break; default: return(true); //I don't know why this would happen, but sure I guess. Get out of here invalid state! } _entitySystemManager.GetEntitySystem <AudioSystem>().PlayFromEntity("/Audio/Items/deconstruct.ogg", Owner); _ammo--; return(true); }
private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink) { // cannot stack do-afters if (drink.CancelToken != null) { drink.CancelToken.Cancel(); drink.CancelToken = null; return(true); } if (!EntityManager.HasComponent <SharedBodyComponent>(target)) { return(false); } if (!drink.Opened) { _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open", ("owner", EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), drink.Owner, Filter.Entities(user)); return(true); } if (!_solutionContainerSystem.TryGetDrainableSolution(drink.Owner, out var drinkSolution) || drinkSolution.DrainAvailable <= 0) { _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-is-empty", ("entity", EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), drink.Owner, Filter.Entities(user)); return(true); } if (_foodSystem.IsMouthBlocked(target, user)) { return(true); } if (!_interactionSystem.InRangeUnobstructed(user, drink.Owner, popup: true)) { return(true); } var forceDrink = user != target; if (forceDrink) { EntityManager.TryGetComponent(user, out MetaDataComponent? meta); var userName = meta?.EntityName ?? string.Empty; _popupSystem.PopupEntity(Loc.GetString("drink-component-force-feed", ("user", userName)), user, Filter.Entities(target)); // logging _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(user):user} is forcing {ToPrettyString(target):target} to drink {ToPrettyString(drink.Owner):drink} {SolutionContainerSystem.ToPrettyString(drinkSolution)}"); } drink.CancelToken = new CancellationTokenSource(); _doAfterSystem.DoAfter(new DoAfterEventArgs(user, forceDrink ? drink.ForceFeedDelay : drink.Delay, drink.CancelToken.Token, target) { BreakOnUserMove = true, BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = true, MovementThreshold = 0.01f, TargetFinishedEvent = new DrinkEvent(user, drink, drinkSolution), BroadcastCancelledEvent = new DrinkCancelledEvent(drink), NeedHand = true, }); return(true); }
public bool TryFeed(EntityUid user, EntityUid target, FoodComponent food) { // if currently being used to feed, cancel that action. if (food.CancelToken != null) { food.CancelToken.Cancel(); food.CancelToken = null; return(true); } if (food.Owner == user || //Suppresses self-eating EntityManager.TryGetComponent <MobStateComponent>(food.Owner, out var mobState) && mobState.IsAlive()) // Suppresses eating alive mobs { return(false); } // Target can't be fed if (!EntityManager.HasComponent <SharedBodyComponent>(target)) { return(false); } if (!_solutionContainerSystem.TryGetSolution(food.Owner, food.SolutionName, out var foodSolution)) { return(false); } if (food.UsesRemaining <= 0) { _popupSystem.PopupEntity(Loc.GetString("food-system-try-use-food-is-empty", ("entity", food.Owner)), user, Filter.Entities(user)); DeleteAndSpawnTrash(food, user); return(false); } if (IsMouthBlocked(target, user)) { return(false); } if (!TryGetRequiredUtensils(user, food, out var utensils)) { return(false); } if (!_interactionSystem.InRangeUnobstructed(user, food.Owner, popup: true)) { return(true); } var forceFeed = user != target; food.CancelToken = new CancellationTokenSource(); if (forceFeed) { EntityManager.TryGetComponent(user, out MetaDataComponent? meta); var userName = meta?.EntityName ?? string.Empty; _popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)), user, Filter.Entities(target)); // logging _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(user):user} is forcing {ToPrettyString(target):target} to eat {ToPrettyString(food.Owner):food} {SolutionContainerSystem.ToPrettyString(foodSolution)}"); } var moveBreak = user != target; _doAfterSystem.DoAfter(new DoAfterEventArgs(user, forceFeed ? food.ForceFeedDelay : food.Delay, food.CancelToken.Token, target) { BreakOnUserMove = moveBreak, BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = moveBreak, MovementThreshold = 0.01f, TargetFinishedEvent = new FeedEvent(user, food, foodSolution, utensils), BroadcastCancelledEvent = new ForceFeedCancelledEvent(food), NeedHand = true, }); return(true); }
/// <summary> /// Attempt to force someone else to drink some of a drink. Returns true if any interaction took place, /// including generation of pop-up messages. /// </summary> private bool TryForceDrink(EntityUid uid, EntityUid userUid, EntityUid targetUid, DrinkComponent?drink = null) { if (!Resolve(uid, ref drink)) { return(false); } // cannot stack do-afters if (drink.CancelToken != null) { drink.CancelToken.Cancel(); drink.CancelToken = null; return(true); } if (!EntityManager.HasComponent <SharedBodyComponent>(targetUid)) { return(false); } if (!drink.Opened) { _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open", ("owner", Name: EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), uid, Filter.Entities(userUid)); return(true); } if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var drinkSolution) || drinkSolution.DrainAvailable <= 0) { _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-is-empty", ("entity", Name: EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), uid, Filter.Entities(userUid)); return(true); } if (_foodSystem.IsMouthBlocked(targetUid, userUid)) { return(true); } EntityManager.TryGetComponent(userUid, out MetaDataComponent? meta); var userName = meta?.EntityName ?? string.Empty; _popupSystem.PopupEntity(Loc.GetString("drink-component-force-feed", ("user", userName)), userUid, Filter.Entities(targetUid)); drink.CancelToken = new(); _doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, drink.ForceFeedDelay, drink.CancelToken.Token, targetUid) { BreakOnUserMove = true, BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = true, MovementThreshold = 1.0f, TargetFinishedEvent = new ForceDrinkEvent(userUid, drink, drinkSolution), BroadcastCancelledEvent = new ForceDrinkCancelledEvent(drink), }); // logging _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(userUid):user} is forcing {ToPrettyString(targetUid):target} to drink {ToPrettyString(uid):drink} {SolutionContainerSystem.ToPrettyString(drinkSolution):solution}"); return(true); }
/// <summary> /// Attempts to force feed a target. Returns true if any interaction occurred, including pop-up generation /// </summary> public bool TryForceFeed(EntityUid uid, EntityUid user, EntityUid target, FoodComponent?food = null) { if (!Resolve(uid, ref food)) { return(false); } // if currently being used to force-feed, cancel that action. if (food.CancelToken != null) { food.CancelToken.Cancel(); food.CancelToken = null; return(true); } if (!EntityManager.HasComponent <SharedBodyComponent>(target)) { return(false); } if (!_solutionContainerSystem.TryGetSolution(uid, food.SolutionName, out var foodSolution)) { return(false); } if (food.UsesRemaining <= 0) { _popupSystem.PopupEntity(Loc.GetString("food-system-try-use-food-is-empty", ("entity", uid)), user, Filter.Entities(user)); DeleteAndSpawnTrash(food, user); return(true); } if (IsMouthBlocked(target, user)) { return(true); } if (!TryGetRequiredUtensils(user, food, out var utensils)) { return(true); } EntityManager.TryGetComponent(user, out MetaDataComponent? meta); var userName = meta?.EntityName ?? string.Empty; _popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)), user, Filter.Entities(target)); food.CancelToken = new(); _doAfterSystem.DoAfter(new DoAfterEventArgs(user, food.ForceFeedDelay, food.CancelToken.Token, target) { BreakOnUserMove = true, BreakOnDamage = true, BreakOnStun = true, BreakOnTargetMove = true, MovementThreshold = 1.0f, TargetFinishedEvent = new ForceFeedEvent(user, food, foodSolution, utensils), BroadcastCancelledEvent = new ForceFeedCancelledEvent(food) }); // logging _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{user} is forcing {target} to eat {uid}"); return(true); }