/// <summary> /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// </summary> /// <param name="entity"></param> /// <param name="direction">Will use the vector's magnitude as the strength of the impulse</param> /// <param name="user"></param> /// <param name="pushbackRatio">The ratio of impulse applied to the thrower</param> internal static void TryThrow(this IEntity entity, Vector2 direction, IEntity?user = null, float pushbackRatio = 1.0f) { if (entity.Deleted || direction == Vector2.Zero || !entity.TryGetComponent(out PhysicsComponent? physicsComponent)) { return; } if (physicsComponent.BodyType == BodyType.Static) { Logger.Warning("Tried to throw entity {entity} but can't throw static bodies!"); return; } if (entity.HasComponent <IMobStateComponent>()) { Logger.Warning("Throwing not supported for mobs!"); return; } if (entity.HasComponent <ItemComponent>()) { entity.EnsureComponent <ThrownItemComponent>().Thrower = user; // Give it a l'il spin. if (!entity.HasTag("NoSpinOnThrow")) { physicsComponent.ApplyAngularImpulse(ThrowAngularImpulse); } else { entity.Transform.LocalRotation = direction.ToWorldAngle() - Math.PI; } if (user != null) { EntitySystem.Get <InteractionSystem>().ThrownInteraction(user, entity); } } physicsComponent.ApplyLinearImpulse(direction); // Give thrower an impulse in the other direction if (user != null && pushbackRatio > 0.0f && user.TryGetComponent(out IPhysBody? body)) { var msg = new ThrowPushbackAttemptEvent(); body.Owner.EntityManager.EventBus.RaiseLocalEvent(body.Owner.Uid, msg); if (!msg.Cancelled) { body.ApplyLinearImpulse(-direction * pushbackRatio); } } }
/// <summary> /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// </summary> /// <param name="entity">The entity being thrown.</param> /// <param name="direction">A vector pointing from the entity to its destination.</param> /// <param name="strength">How much the direction vector should be multiplied for velocity.</param> /// <param name="user"></param> /// <param name="pushbackRatio">The ratio of impulse applied to the thrower</param> internal static void TryThrow(this IEntity entity, Vector2 direction, float strength = 1.0f, IEntity?user = null, float pushbackRatio = 1.0f) { if (entity.Deleted || direction == Vector2.Zero || strength <= 0f || !entity.TryGetComponent(out PhysicsComponent? physicsComponent)) { return; } if (physicsComponent.BodyType == BodyType.Static) { Logger.Warning("Tried to throw entity {entity} but can't throw static bodies!"); return; } if (entity.HasComponent <IMobStateComponent>()) { Logger.Warning("Throwing not supported for mobs!"); return; } if (entity.HasComponent <ItemComponent>()) { entity.EnsureComponent <ThrownItemComponent>().Thrower = user; // Give it a l'il spin. if (!entity.HasTag("NoSpinOnThrow")) { physicsComponent.ApplyAngularImpulse(ThrowAngularImpulse); } else { entity.Transform.LocalRotation = direction.ToWorldAngle() - Math.PI; } if (user != null) { EntitySystem.Get <InteractionSystem>().ThrownInteraction(user, entity); } } var impulseVector = direction.Normalized * strength * physicsComponent.Mass; physicsComponent.ApplyLinearImpulse(impulseVector); // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = (direction / strength).Length; if (time < FlyTime) { physicsComponent.BodyStatus = BodyStatus.OnGround; } else { physicsComponent.BodyStatus = BodyStatus.InAir; Timer.Spawn(TimeSpan.FromSeconds(time - FlyTime), () => { if (physicsComponent.Deleted) { return; } physicsComponent.BodyStatus = BodyStatus.OnGround; }); } // Give thrower an impulse in the other direction if (user != null && pushbackRatio > 0.0f && user.TryGetComponent(out IPhysBody? body)) { var msg = new ThrowPushbackAttemptEvent(); body.Owner.EntityManager.EventBus.RaiseLocalEvent(body.Owner.Uid, msg); if (!msg.Cancelled) { body.ApplyLinearImpulse(-impulseVector * pushbackRatio); } } }
private void HandleThrowPushback(EntityUid uid, SharedBuckleComponent component, ThrowPushbackAttemptEvent args) { if (!component.Buckled) { return; } args.Cancel(); }
/// <summary> /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// </summary> /// <param name="entity">The entity being thrown.</param> /// <param name="direction">A vector pointing from the entity to its destination.</param> /// <param name="strength">How much the direction vector should be multiplied for velocity.</param> /// <param name="user"></param> /// <param name="pushbackRatio">The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced</param> public void TryThrow( EntityUid uid, Vector2 direction, float strength = 1.0f, EntityUid?user = null, float pushbackRatio = 10.0f, PhysicsComponent?physics = null, TransformComponent?transform = null, EntityQuery <PhysicsComponent>?physicsQuery = null, EntityQuery <TransformComponent>?xformQuery = null) { if (strength <= 0 || direction == Vector2.Infinity || direction == Vector2.NaN || direction == Vector2.Zero) { return; } physicsQuery ??= GetEntityQuery <PhysicsComponent>(); if (physics == null && !physicsQuery.Value.TryGetComponent(uid, out physics)) { return; } if (physics.BodyType != BodyType.Dynamic) { Logger.Warning($"Tried to throw entity {ToPrettyString(uid)} but can't throw {physics.BodyType} bodies!"); return; } var comp = EnsureComp <ThrownItemComponent>(uid); comp.Thrower = user; // Give it a l'il spin. if (!_tagSystem.HasTag(uid, "NoSpinOnThrow")) { physics.ApplyAngularImpulse(ThrowAngularImpulse); } else { if (transform == null) { xformQuery ??= GetEntityQuery <TransformComponent>(); transform = xformQuery.Value.GetComponent(uid); } transform.LocalRotation = direction.ToWorldAngle() - Math.PI; } if (user != null) { _interactionSystem.ThrownInteraction(user.Value, uid); } var impulseVector = direction.Normalized * strength * physics.Mass; physics.ApplyLinearImpulse(impulseVector); // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = (direction / strength).Length; if (time < FlyTime) { physics.BodyStatus = BodyStatus.OnGround; _thrownSystem.LandComponent(comp); } else { physics.BodyStatus = BodyStatus.InAir; Timer.Spawn(TimeSpan.FromSeconds(time - FlyTime), () => { if (physics.Deleted) { return; } physics.BodyStatus = BodyStatus.OnGround; _thrownSystem.LandComponent(comp); }); } // Give thrower an impulse in the other direction if (user != null && pushbackRatio > 0.0f && physicsQuery.Value.TryGetComponent(user.Value, out var userPhysics)) { var msg = new ThrowPushbackAttemptEvent(); RaiseLocalEvent(physics.Owner, msg, false); if (!msg.Cancelled) { userPhysics.ApplyLinearImpulse(-impulseVector * pushbackRatio); } } }
/// <summary> /// Tries to throw the entity if it has a physics component, otherwise does nothing. /// </summary> /// <param name="entity">The entity being thrown.</param> /// <param name="direction">A vector pointing from the entity to its destination.</param> /// <param name="strength">How much the direction vector should be multiplied for velocity.</param> /// <param name="user"></param> /// <param name="pushbackRatio">The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced</param> internal static void TryThrow(this EntityUid entity, Vector2 direction, float strength = 1.0f, EntityUid?user = null, float pushbackRatio = 10.0f) { var entities = IoCManager.Resolve <IEntityManager>(); if (entities.GetComponent <MetaDataComponent>(entity).EntityDeleted || strength <= 0f || !entities.TryGetComponent(entity, out PhysicsComponent? physicsComponent)) { return; } if (physicsComponent.BodyType != BodyType.Dynamic) { Logger.Warning($"Tried to throw entity {entities.ToPrettyString(entity)} but can't throw {physicsComponent.BodyType} bodies!"); return; } var comp = entity.EnsureComponent <ThrownItemComponent>(); if (entities.HasComponent <SharedItemComponent>(entity)) { comp.Thrower = user; // Give it a l'il spin. if (!EntitySystem.Get <TagSystem>().HasTag(entity, "NoSpinOnThrow")) { physicsComponent.ApplyAngularImpulse(ThrowAngularImpulse); } else if (direction != Vector2.Zero) { entities.GetComponent <TransformComponent>(entity).LocalRotation = direction.ToWorldAngle() - Math.PI; } if (user != null) { EntitySystem.Get <InteractionSystem>().ThrownInteraction(user.Value, entity); } } var impulseVector = direction.Normalized * strength * physicsComponent.Mass; physicsComponent.ApplyLinearImpulse(impulseVector); // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = (direction / strength).Length; if (time < FlyTime) { physicsComponent.BodyStatus = BodyStatus.OnGround; EntitySystem.Get <ThrownItemSystem>().LandComponent(comp); } else { physicsComponent.BodyStatus = BodyStatus.InAir; Timer.Spawn(TimeSpan.FromSeconds(time - FlyTime), () => { if (physicsComponent.Deleted) { return; } physicsComponent.BodyStatus = BodyStatus.OnGround; EntitySystem.Get <ThrownItemSystem>().LandComponent(comp); }); } // Give thrower an impulse in the other direction if (user != null && pushbackRatio > 0.0f && entities.TryGetComponent(user.Value, out IPhysBody? body)) { var msg = new ThrowPushbackAttemptEvent(); entities.EventBus.RaiseLocalEvent(body.Owner, msg); if (!msg.Cancelled) { body.ApplyLinearImpulse(-impulseVector * pushbackRatio); } } }