1 using Microsoft.Xna.Framework;
3 using System.Globalization;
19 private float? lastReceivedTargetForce;
25 private float targetForce;
32 private const float ForceToPowerExponent = 3f / 2f;
33 private const float PowerToForceExponent = 1.0f / ForceToPowerExponent;
35 private float maxForce;
37 private readonly
Attack propellerDamage;
39 private float damageTimer;
41 private bool hasPower;
43 private float prevVoltage;
45 private float controlLockTimer;
50 Serialize(500.0f,
IsPropertySaveable.Yes, description:
"The amount of force exerted on the submarine when the engine is operating at full power.")]
54 set => maxForce = Math.Max(0.0f, value);
58 description:
"The position of the propeller as an offset from the item's center (in pixels)."+
59 " Determines where the particles spawn and the position that causes characters to take damage from the engine if the PropellerDamage is defined.")]
76 set { force = MathHelper.Clamp(value, -100.0f, 100.0f); }
92 private const float TinkeringForceIncrease = 1.5f;
99 foreach (var subElement
in element.Elements())
101 switch (subElement.Name.ToString().ToLowerInvariant())
103 case "propellerdamage":
109 InitProjSpecific(element);
118 UpdateAnimation(deltaTime);
120 controlLockTimer -= deltaTime;
132 if (lastReceivedTargetForce.HasValue)
134 targetForce = lastReceivedTargetForce.Value;
137 if (Math.Abs(
Force) > 1.0f)
140 float currForce = force * MathF.Pow(voltageFactor, PowerToForceExponent);
143 float noise = Math.Abs(currForce) * MathHelper.Lerp(1.5f, 1f, condition);
144 UpdateAITargets(noise);
146 float forceMultiplier = 0.1f;
149 forceMultiplier *= MathHelper.Lerp(0.5f, 2.0f, (
float)Math.Sqrt(
User.
GetSkillLevel(
"helm") / 100));
151 currForce *=
item.
StatManager.GetAdjustedValueMultiplicative(ItemTalentStats.EngineMaxSpeed,
MaxForce) * forceMultiplier;
152 if (
item.GetComponent<
Repairable>() is { IsTinkering: true } repairable)
154 currForce *= 1f + repairable.TinkeringStrength * TinkeringForceIncrease;
157 currForce =
item.
StatManager.GetAdjustedValueMultiplicative(ItemTalentStats.EngineSpeed, currForce);
160 currForce *= MathHelper.Lerp(0.5f, 2.0f, condition);
162 Vector2 forceVector =
new Vector2(currForce, 0);
164 UpdatePropellerDamage(deltaTime);
166 float particleInterval = 1.0f / particlesPerSec;
167 particleTimer += deltaTime;
168 while (particleTimer > particleInterval)
170 Vector2 particleVel = -forceVector.ClampLength(5000.0f) / 5.0f;
172 particleVel * Rand.Range(0.8f, 1.1f),
174 particleTimer -= particleInterval;
207 private void UpdateAITargets(
float noise)
220 private void UpdatePropellerDamage(
float deltaTime)
224 damageTimer += deltaTime;
225 if (damageTimer < 0.5f) {
return; }
228 if (propellerDamage ==
null) {
return; }
230 float scaledDamageRange = propellerDamage.DamageRange *
item.
Scale;
233 float broadRange = Math.Max(scaledDamageRange * 2, 500);
234 foreach (Character character
in Character.CharacterList)
236 if (!character.Enabled || character.Removed) {
continue; }
237 if (Math.Abs(character.WorldPosition.X - propellerWorldPos.X) > broadRange) {
continue; }
238 if (Math.Abs(character.WorldPosition.Y - propellerWorldPos.Y) > broadRange) {
continue; }
240 foreach (Limb limb
in character.AnimController.Limbs)
242 if (limb.IsSevered || !limb.body.Enabled) {
continue; }
243 float distSqr = Vector2.DistanceSquared(limb.WorldPosition, propellerWorldPos);
244 if (distSqr > scaledDamageRange * scaledDamageRange) {
continue; }
245 character.LastDamageSource =
item;
246 propellerDamage.DoDamage(
null, character, propellerWorldPos, 1.0f,
true);
252 partial
void UpdateAnimation(
float deltaTime);
256 base.UpdateBroken(deltaTime, cam);
257 force = MathHelper.Lerp(force, 0.0f, 0.1f);
260 public override void FlipX(
bool relativeToSub)
265 public override void FlipY(
bool relativeToSub)
272 base.ReceiveSignal(signal, connection);
274 if (connection.
Name ==
"set_force")
276 if (
float.TryParse(signal.
value, NumberStyles.Float, CultureInfo.InvariantCulture, out
float tempForce))
278 controlLockTimer = 0.1f;
279 lastReceivedTargetForce = MathHelper.Clamp(tempForce, -100.0f, 100.0f);
285 public override XElement
Save(XElement parentElement)
291 XElement element = base.Save(parentElement);
Attacks are used to deal damage to characters, structures and items. They can be defined in the weapo...
float GetSkillLevel(string skillIdentifier)
static ParticleManager ParticleManager
ItemStatManager StatManager
override string Name
Note that this is not a LocalizedString instance, just the current name of the item as a string....
float ConditionPercentage
override XElement Save(XElement parentElement)
override void ReceiveSignal(Signal signal, Connection connection)
float CurrentBrokenVolume
override float GetCurrentPowerConsumption(Connection connection=null)
Power consumption of the engine. Only consume power when active and adjust consumption based on condi...
override void Update(float deltaTime, Camera cam)
override void GridResolved(Connection connection)
When grid is resolved update the previous voltage
override void UpdateBroken(float deltaTime, Camera cam)
Engine(Item item, ContentXElement element)
bool DisablePropellerDamage
override void FlipX(bool relativeToSub)
override void FlipY(bool relativeToSub)
const float MaxOverVoltageFactor
Maximum voltage factor when the device is being overvolted. I.e. how many times more effectively the ...
float powerConsumption
The maximum amount of power the item can draw from connected items
float currPowerConsumption
The amount of power currently consumed by the item. Negative values mean that the item is providing p...
void UpdateOnActiveEffects(float deltaTime)
void ApplyForce(Vector2 force)
Interface for entities that the clients can send events to the server
Interface for entities that the server can send events to the clients