/// <summary> /// Knocks down the mob, making it fall to the ground. /// </summary> /// <param name="seconds">How many seconds the mob will stay on the ground</param> public void Knockdown(float seconds) { seconds = MathF.Min(_knockdownTimer + (seconds * KnockdownTimeModifier), _knockdownCap); if (seconds <= 0f) { return; } StandingStateHelper.Down(Owner); _knockdownTimer = seconds; _lastStun = _gameTiming.CurTime; SetStatusEffect(); Dirty(); }
/// <summary> /// Stuns the entity, disallowing it from doing many interactions temporarily. /// </summary> /// <param name="seconds">How many seconds the mob will stay stunned</param> public void Stun(float seconds) { seconds = MathF.Min(_stunnedTimer + (seconds * StunTimeModifier), _stunCap); if (seconds <= 0f) { return; } StandingStateHelper.DropAllItemsInHands(Owner, false); _stunnedTimer = seconds; _lastStun = _gameTiming.CurTime; SetStatusEffect(); Dirty(); }
public void ExperiencePressureDifference(int cycle, float pressureDifference, Direction direction, float pressureResistanceProbDelta, GridCoordinates throwTarget) { if (ControlledComponent == null) { return; } // TODO ATMOS stuns? var transform = ControlledComponent.Owner.Transform; var pressureComponent = ControlledComponent.Owner.GetComponent <MovedByPressureComponent>(); var maxForce = MathF.Sqrt(pressureDifference) * 2.25f; var moveProb = 100f; if (pressureComponent.PressureResistance > 0) { moveProb = MathF.Abs((pressureDifference / pressureComponent.PressureResistance * ProbabilityBasePercent) - ProbabilityOffset); } if (moveProb > ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f)) && !float.IsPositiveInfinity(pressureComponent.MoveResist) && (!ControlledComponent.Anchored && (maxForce >= (pressureComponent.MoveResist * MoveForcePushRatio))) || (ControlledComponent.Anchored && (maxForce >= (pressureComponent.MoveResist * MoveForceForcePushRatio)))) { if (maxForce > ThrowForce && throwTarget != GridCoordinates.InvalidGrid) { var moveForce = MathF.Min(maxForce * MathF.Clamp(moveProb, 0, 100) / 100f, 50f); var pos = throwTarget.Position - transform.GridPosition.Position; LinearVelocity = pos * moveForce; } else { var moveForce = MathF.Min(maxForce * MathF.Clamp(moveProb, 0, 100) / 100f, 25f); LinearVelocity = direction.ToVec() * moveForce; } pressureComponent.LastHighPressureMovementAirCycle = cycle; } }
/// <summary> /// Throw an entity at the position of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>, /// without overshooting. /// </summary> /// <param name="thrownEnt">The entity to throw.</param> /// <param name="throwForceMax"> /// The MAXIMUM force to throw the entity with. /// Throw force increases with distance to target, this is the maximum force allowed. /// </param> /// <param name="targetLoc"> /// The target location to throw at. /// This function will try to land at this exact spot, /// if <paramref name="throwForceMax"/> is large enough to allow for it to be reached. /// </param> /// <param name="sourceLoc"> /// The position to start the throw from. /// </param> /// <param name="spread"> /// If true, slightly spread the actual throw angle. /// </param> /// <param name="throwSourceEnt"> /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in. /// </param> public static void ThrowTo(IEntity thrownEnt, float throwForceMax, GridCoordinates targetLoc, GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null) { var mapManager = IoCManager.Resolve <IMapManager>(); var timing = IoCManager.Resolve <IGameTiming>(); // Calculate the force necessary to land a throw based on throw duration, mass and distance. var distance = (targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager)).Length; var throwDuration = ThrownItemComponent.DefaultThrowTime; var mass = 1f; if (thrownEnt.TryGetComponent(out IPhysicsComponent physicsComponent)) { mass = physicsComponent.Mass; } var velocityNecessary = distance / throwDuration; var impulseNecessary = velocityNecessary * mass; var forceNecessary = impulseNecessary * (1f / timing.TickRate); // Then clamp it to the max force allowed and call Throw(). Throw(thrownEnt, MathF.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); }
/// <summary> /// Slows down the mob's walking/running speed temporarily /// </summary> /// <param name="seconds">How many seconds the mob will be slowed down</param> /// <param name="walkModifierOverride">Walk speed modifier. Set to 0 or negative for default value. (0.5f)</param> /// <param name="runModifierOverride">Run speed modifier. Set to 0 or negative for default value. (0.5f)</param> public void Slowdown(float seconds, float walkModifierOverride = 0f, float runModifierOverride = 0f) { seconds = MathF.Min(_slowdownTimer + (seconds * SlowdownTimeModifier), _slowdownCap); if (seconds <= 0f) { return; } WalkModifierOverride = walkModifierOverride; RunModifierOverride = runModifierOverride; _slowdownTimer = seconds; _lastStun = _gameTiming.CurTime; if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) { movement.RefreshMovementSpeedModifiers(); } SetStatusEffect(); Dirty(); }
public static float Median(float a, float b, float c) { return(MathF.Max(MathF.Min(a, b), MathF.Min(MathF.Max(a, b), c))); }
public static float Min(float a, float b, float c, float d) { return(MathF.Min(a, MathF.Min(b, MathF.Min(c, d)))); }
public bool Intersects(Box2 box, out float distance, out Vector2 hitPos) { hitPos = Vector2.Zero; distance = 0; var tmin = 0.0f; // set to -FLT_MAX to get first hit on line var tmax = float.MaxValue; // set to max distance ray can travel (for segment) const float epsilon = 1.0E-07f; // X axis slab { if (MathF.Abs(_direction.X) < epsilon) { // ray is parallel to this slab, it will never hit unless ray is inside box if (_position.X < MathF.Min(box.Left, box.Right) || _position.X > MathF.Max(box.Left, box.Right)) { return(false); } } // calculate intersection t value of ray with near and far plane of slab var ood = 1.0f / _direction.X; var t1 = (MathF.Min(box.Left, box.Right) - _position.X) * ood; var t2 = (MathF.Max(box.Left, box.Right) - _position.X) * ood; // Make t1 be the intersection with near plane, t2 with far plane if (t1 > t2) { MathHelper.Swap(ref t1, ref t2); } // Compute the intersection of slab intersection intervals tmin = MathF.Max(t1, tmin); tmax = MathF.Min(t2, tmax); // Is this Min (SE) or Max(Textbook) // Exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return(false); } } // Y axis slab { if (MathF.Abs(_direction.Y) < epsilon) { // ray is parallel to this slab, it will never hit unless ray is inside box if (_position.Y < MathF.Min(box.Top, box.Bottom) || _position.Y > MathF.Max(box.Top, box.Bottom)) { return(false); } } // calculate intersection t value of ray with near and far plane of slab var ood = 1.0f / _direction.Y; var t1 = (MathF.Min(box.Top, box.Bottom) - _position.Y) * ood; var t2 = (MathF.Max(box.Top, box.Bottom) - _position.Y) * ood; // Make t1 be the intersection with near plane, t2 with far plane if (t1 > t2) { MathHelper.Swap(ref t1, ref t2); } // Compute the intersection of slab intersection intervals tmin = MathF.Max(t1, tmin); tmax = MathF.Min(t2, tmax); // Is this Min (SE) or Max(Textbook) // Exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return(false); } } // Ray intersects all slabs. Return point and intersection t value hitPos = _position + _direction * tmin; distance = tmin; return(true); }