Aetheric Drive

Added Aetheric Drive hardpoint and item behavior
Added Drive RPM UI to HUD
Fixed death not disabling continue option
Disabling global input when dialog is visible
Fixed loadout generator failure when zero price item present
Replaced fixed top speed with drag coefficients
This commit is contained in:
Reinier Vens 2021-04-14 03:29:14 +01:00
commit 11bfc739fe
65 changed files with 2312 additions and 320 deletions

View file

@ -12,6 +12,16 @@ public static class AetheriaMath
{
return source * exp(-lambda * dt);
}
public static float3 Decay(float3 source, float lambda, float dt)
{
return source * exp(-lambda * dt);
}
public static float3 Decay(float3 source, float3 lambda, float dt)
{
return source * exp(-lambda * dt);
}
public static float Damp(float a, float b, float lambda, float dt)
{

View file

@ -0,0 +1,121 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using MessagePack;
using Newtonsoft.Json;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), RuntimeInspectable]
public class AetherDriveData : BehaviorData
{
[Inspectable, JsonProperty("diameters"), Key(1)]
public float3 RotorDiameter;
[Inspectable, JsonProperty("masses"), Key(2)]
public float3 RotorMass;
[Inspectable, JsonProperty("rpm"), Key(3), RuntimeInspectable]
public PerformanceStat MaximumRpm;
[Inspectable, JsonProperty("couplingLambdas"), Key(4)]
public float3 CouplingLambda;
[Inspectable, JsonProperty("couplingEfficiency"), Key(5), RuntimeInspectable]
public PerformanceStat CouplingEfficiency;
[Inspectable, JsonProperty("torque"), Key(6), RuntimeInspectable]
public PerformanceStat Torque;
[Inspectable, JsonProperty("torqueProfile"), Key(7), RuntimeInspectable]
public BezierCurve TorqueProfile;
[Inspectable, JsonProperty("draw"), Key(8), RuntimeInspectable]
public PerformanceStat EnergyDraw;
[Inspectable, JsonProperty("passiveCoupling"), Key(9), RuntimeInspectable]
public PerformanceStat PassiveCoupling;
public override IBehavior CreateInstance(EquippedItem item)
{
return new AetherDrive(this, item);
}
}
public class AetherDrive : IBehavior
{
private AetherDriveData _data;
private float3 _axis;
public EquippedItem Item { get; }
public float3 Thrust { get; private set; }
public float3 Rpm { get; private set; }
public float MaximumRpm { get; private set; }
public BehaviorData Data => _data;
public AetherDriveData DriveData => _data;
public float3 Axis
{
get => _axis;
set => _axis = clamp(value, -1, 1);
}
public AetherDrive(AetherDriveData data, EquippedItem item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
{
var rotorSpeed = Rpm * _data.RotorDiameter / 100;
var forward = normalize(Item.Entity.Direction);
var right = forward.Rotate(ItemRotation.Clockwise);
var speed = float2(dot(Item.Entity.Velocity, forward), dot(Item.Entity.Velocity, right));
var couplingEfficiency = Item.Evaluate(_data.CouplingEfficiency);
var efficiency = float3(saturate(1 - speed / max(rotorSpeed.xy, 1) * sign(_axis.xy)) * couplingEfficiency, 1);
Thrust = (Rpm - AetheriaMath.Decay(Rpm, _data.CouplingLambda, dt)) * _data.RotorMass * efficiency;
var couplingLambda = _data.CouplingLambda * max(abs(_axis), Item.Evaluate(_data.PassiveCoupling));
var previousRpm = Rpm;
Rpm = AetheriaMath.Decay(Rpm, couplingLambda, dt);
var rpmLoss = previousRpm - Rpm;
var force = rpmLoss * _data.RotorMass * efficiency;
var heat = rpmLoss * _data.RotorMass * (1 - couplingEfficiency);
Item.AddHeat((heat.x + heat.y + heat.z)*Item.ItemManager.GameplaySettings.AetherHeatMultiplier);
Item.Entity.Velocity += forward * (_axis.x * force.x / Item.Entity.Mass);
Item.Entity.Velocity += right * (_axis.y * force.y / Item.Entity.Mass);
Item.Entity.Direction = mul(Item.Entity.Direction,
Unity.Mathematics.float2x2.Rotate(force.z * _axis.z * Item.ItemManager.GameplaySettings.AetherTorqueMultiplier / Item.Entity.Mass));
if(float.IsNaN(Item.Entity.Velocity.x))
Item.ItemManager.Log("FUCK FUCK FUCK FUCK");
MaximumRpm = Item.Evaluate(_data.MaximumRpm);
var torqueProfile = float3(
_data.TorqueProfile.Evaluate(Rpm.x / MaximumRpm),
_data.TorqueProfile.Evaluate(Rpm.y / MaximumRpm),
_data.TorqueProfile.Evaluate(Rpm.z / MaximumRpm));
var potentialTorque = Item.Evaluate(_data.Torque) * torqueProfile;
var potentialRpmDelta = potentialTorque / length(_data.RotorMass) * dt;
var actualRpmDelta = min(MaximumRpm - Rpm, potentialRpmDelta);
var torqueRatio = actualRpmDelta / potentialRpmDelta;
var draw = torqueRatio * Item.Evaluate(_data.EnergyDraw) / 3;
if (Item.Entity.TryConsumeEnergy((draw.x + draw.y + draw.z)*dt))
{
Rpm += actualRpmDelta;
return true;
}
return false;
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2022c838bbc64a0d86cfbd477e6a379c
timeCreated: 1618332827

View file

@ -22,11 +22,11 @@ public class AutoWeapon : InstantWeapon
{
}
public override bool Execute(float delta)
public override bool Execute(float dt)
{
if(_firing && _burstRemaining == 0 && _cooldown < 0)
Trigger();
return base.Execute(delta);
return base.Execute(dt);
}
}

View file

@ -15,7 +15,7 @@ using static Unity.Mathematics.noise;
public interface IBehavior
{
bool Execute(float delta);
bool Execute(float dt);
BehaviorData Data { get; }
}
@ -96,7 +96,7 @@ public abstract class PersistentBehaviorData
Union(9, typeof(WearData)),
Union(10, typeof(VelocityConversionData)),
Union(11, typeof(VelocityLimitData)),
// Union(13, typeof(PatrolControllerData)),
Union(12, typeof(AetherDriveData)),
// Union(14, typeof(TowingControllerData)),
Union(15, typeof(CooldownData)),
Union(16, typeof(HeatData)),

View file

@ -47,7 +47,7 @@ public class Capacitor : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Capacity = Item.Evaluate(_data.Capacity);
Efficiency = Item.Evaluate(_data.Efficiency);

View file

@ -112,14 +112,14 @@ public class ChargedWeapon : InstantWeapon, IEventBehavior
Velocity *= lerp(1, _data.ChargeFiringVelocityMultiplier, saturate(_charge));
}
public override bool Execute(float delta)
public override bool Execute(float dt)
{
if (_charging)
{
_charge += delta / ChargeTime;
_charge += dt / ChargeTime;
if (!_charged)
{
Item.AddHeat(ChargeHeat * (delta / ChargeTime));
Item.AddHeat(ChargeHeat * (dt / ChargeTime));
if(_charge > 1)
{
_charged = true;
@ -136,7 +136,7 @@ public class ChargedWeapon : InstantWeapon, IEventBehavior
Item.EquippableItem.Durability -= _data.FailureDamage;
}
}
return base.Execute(delta);
return base.Execute(dt);
}
public override void Activate()

View file

@ -32,7 +32,7 @@ public class Cockpit : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return true;
}

View file

@ -62,12 +62,12 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
_data = data;
}
public override bool Execute(float delta)
public override bool Execute(float dt)
{
base.Execute(delta);
base.Execute(dt);
if (_firing)
{
if (!Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.Energy) * delta))
if (!Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.Energy) * dt))
{
_firing = false;
OnStopFiring?.Invoke();
@ -77,7 +77,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
{
if (_reloading)
{
_reload -= delta / _data.ReloadTime;
_reload -= dt / _data.ReloadTime;
if (_reload < 0)
{
_reloading = false;
@ -86,7 +86,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
return false;
}
_ammoInterval -= delta / _data.AmmoInterval;
_ammoInterval -= dt / _data.AmmoInterval;
if (_ammoInterval < 0)
{
_ammoInterval = 1;
@ -115,10 +115,10 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
}
}
var dmg = Item.Wear * delta;
var dmg = Item.Wear * dt;
Item.EquippableItem.Durability -= dmg;
Item.Entity.ItemDamage.OnNext((Item, dmg));
Item.AddHeat(Item.Evaluate(_data.Heat) * delta);
Item.AddHeat(Item.Evaluate(_data.Heat) * dt);
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.Visibility);
}
return true;

View file

@ -38,7 +38,7 @@ public class Cooldown : IBehavior, IAlwaysUpdatedBehavior, IProgressBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if (_cooldown < 0)
{

View file

@ -36,8 +36,8 @@ public class EnergyDraw : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.EnergyDraw) * (_data.PerSecond ? delta : 1));
return Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.EnergyDraw) * (_data.PerSecond ? dt : 1));
}
}

View file

@ -36,9 +36,9 @@ public class Heat : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Item.AddHeat(Item.Evaluate(_data.Heat) * (_data.PerSecond ? delta : 1));
Item.AddHeat(Item.Evaluate(_data.Heat) * (_data.PerSecond ? dt : 1));
return true;
}

View file

@ -31,7 +31,7 @@ public class HeatStorage : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return true;
}

View file

@ -136,12 +136,12 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
}
public override bool Execute(float delta)
public override bool Execute(float dt)
{
base.Execute(delta);
base.Execute(dt);
if (_coolingDown)
{
_cooldown -= delta / (_data.MagazineSize > 0 && _ammo == 0 ? _data.ReloadTime : Cooldown);
_cooldown -= dt / (_data.MagazineSize > 0 && _ammo == 0 ? _data.ReloadTime : Cooldown);
if (_cooldown < 0)
{
_coolingDown = false;
@ -155,7 +155,7 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
}
}
_burstTimer += delta;
_burstTimer += dt;
while (_burstRemaining > 0 && _burstTimer > 0)
{
// If multiple ammo is consumed per burst, perform ammo and energy consumption here

View file

@ -33,7 +33,7 @@ public class ItemUsage : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
var cargo = Item.Entity.FindItemInCargo(_data.Item);
if (cargo == null) return false;

View file

@ -61,7 +61,7 @@ public class LockWeapon : InstantWeapon
_data = data;
}
public override bool Execute(float delta)
public override bool Execute(float dt)
{
if (_target != Item.Entity.Target.Value)
{
@ -81,12 +81,12 @@ public class LockWeapon : InstantWeapon
if (degrees < LockAngle)
{
var lerp = 1 - unlerp(0, 90, degrees);
_lock = saturate(_lock + pow(lerp, DirectionImpact) * delta * LockSpeed * pow(Item.Entity.EntityInfoGathered[Item.Entity.Target.Value], SensorImpact));
_lock = saturate(_lock + pow(lerp, DirectionImpact) * dt * LockSpeed * pow(Item.Entity.EntityInfoGathered[Item.Entity.Target.Value], SensorImpact));
}
else _lock = saturate(_lock - delta * Decay);
else _lock = saturate(_lock - dt * Decay);
}
return base.Execute(delta);
return base.Execute(dt);
}
}

View file

@ -48,7 +48,7 @@ public class MiningTool : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Range = Item.Evaluate(_data.Range);
var belt = Item.Entity.Zone.AsteroidBelts[AsteroidBelt];
@ -60,7 +60,7 @@ public class MiningTool : IBehavior
Item.Entity,
AsteroidBelt,
Asteroid,
Item.Evaluate(_data.DamagePerSecond) * delta,
Item.Evaluate(_data.DamagePerSecond) * dt,
Item.Evaluate(_data.Efficiency),
Item.Evaluate(_data.Penetration));
return true;

View file

@ -51,7 +51,7 @@ public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavio
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
PumpedHeat = Item.Evaluate(_data.PumpedHeat);
WasteHeat = Item.Evaluate(_data.WasteHeat);
@ -63,7 +63,7 @@ public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavio
// Temperature ratio would cause more waste heat than pump capacity, stop executing
if (tempRatio > PumpedHeat / WasteHeat) return true;
if (!Item.Entity.TryConsumeEnergy(EnergyUsage * tempRatio * delta)) return false;
if (!Item.Entity.TryConsumeEnergy(EnergyUsage * tempRatio * dt)) return false;
var pumpedHeat = PumpedHeat * max(itemTemperature - _data.TemperatureFloor, 0);
@ -72,8 +72,8 @@ public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavio
var wasteHeat = WasteHeat * tempRatio;
Item.AddHeat((wasteHeat - pumpedHeat) * delta);
Temperature += pumpedHeat / Item.ItemManager.GetThermalMass(Item.EquippableItem) * delta;
Item.AddHeat((wasteHeat - pumpedHeat) * dt);
Temperature += pumpedHeat / Item.ItemManager.GetThermalMass(Item.EquippableItem) * dt;
return true;
}

View file

@ -71,9 +71,9 @@ public class Reactor : IBehavior, IOrderedBehavior
Draw += energy;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
var charge = Item.Evaluate(_data.Charge) * delta;
var charge = Item.Evaluate(_data.Charge) * dt;
var efficiency = Item.Evaluate(_data.Efficiency);
// This behavior executes last, so any components drawing power have already done so

View file

@ -36,7 +36,7 @@ public class Reflector : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.CrossSection) * Item.Entity.Zone.GetLight(Item.Entity.Position.xz);

View file

@ -61,7 +61,7 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
var planetData = Item.Entity.Zone.Planets[ScanTarget];
if (planetData != null)
@ -72,7 +72,7 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
Asteroid < beltData.Asteroids.Length &&
length(Item.Entity.Position.xz - Item.Entity.Zone.AsteroidBelts[ScanTarget].Positions[Asteroid].xz) < Range)
{
_scanTime += delta;
_scanTime += dt;
if (_scanTime > ScanDuration)
{
// TODO: Implement Scanning!
@ -86,7 +86,7 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
{
if(length(Item.Entity.Position.xz - Item.Entity.Zone.GetOrbitPosition(planetData.Orbit)) < Range)
{
_scanTime += delta;
_scanTime += dt;
if (_scanTime > ScanDuration)
{
//Context.ItemData.Get<Corporation>(Entity.Corporation).PlanetSurveyFloor[ScanTarget] = MinimumDensity;

View file

@ -99,11 +99,11 @@ public class Sensor : IBehavior, IEventBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if (_pinging)
{
_pingLerp += delta / _data.PingDuration;
_pingLerp += dt / _data.PingDuration;
_pingRadius = lerp(0, Item.Evaluate(_data.PingRange), pow(_pingLerp, _data.PingRadiusExponent));
if (_pingLerp > 1)
{
@ -112,7 +112,7 @@ public class Sensor : IBehavior, IEventBehavior
}
}
_pingCooldown -= delta / Item.Evaluate(_data.PingCooldown);
_pingCooldown -= dt / Item.Evaluate(_data.PingCooldown);
// TODO: Handle Active Detection / Visibility From Reflected Radiance
var hardpoint = Item.Entity.Hardpoints[Item.Position.x, Item.Position.y];
@ -145,9 +145,9 @@ public class Sensor : IBehavior, IEventBehavior
entity.Visibility *
Item.Evaluate(_data.Sensitivity) *
_data.SensitivityCurve.Evaluate(angle / PI) *
delta / dist);
dt / dist);
}
next *= 1 - Item.ItemManager.GameplaySettings.TargetInfoDecay * delta;
next *= 1 - Item.ItemManager.GameplaySettings.TargetInfoDecay * dt;
//Context.Log($"{entity.Name} visibility {(int)(previous * 100)}% -> {(int)(next * 100)}%");
Item.Entity.EntityInfoGathered[entity] = next;
}

View file

@ -39,7 +39,7 @@ public class Shield : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Efficiency = Item.Evaluate(_data.Efficiency);
EnergyUsage = Item.Evaluate(_data.EnergyUsage);

View file

@ -77,7 +77,7 @@ public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavi
}
}
public bool Execute(float delta)
public bool Execute(float dt)
{
foreach (var stat in _stats)
(_data.Type == StatModifierType.Constant

View file

@ -32,7 +32,7 @@ public class Switch : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return Activated;
}

View file

@ -42,7 +42,7 @@ public class Thermotoggle : IBehavior
TargetTemperature = data.TargetTemperature;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return Item.Temperature < TargetTemperature ^ _data.HighPass;
}

View file

@ -63,15 +63,15 @@ public class Thruster : IAnalogBehavior
Thrust = Item.Evaluate(_data.Thrust);
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if(_input > .01f && Item.Entity.TryConsumeEnergy(_input * Item.Evaluate(_data.EnergyUsage)))
{
Thrust = Item.Evaluate(_data.Thrust);
Item.Entity.Velocity -= Item.Entity.Direction.Rotate(Item.EquippableItem.Rotation) * _input * Thrust / Item.Entity.Mass * delta;
Item.Entity.Velocity -= Item.Entity.Direction.Rotate(Item.EquippableItem.Rotation) * _input * Thrust / Item.Entity.Mass * dt;
Item.Entity.Direction = mul(Item.Entity.Direction,
Unity.Mathematics.float2x2.Rotate(_input * Torque * Thrust * Item.ItemManager.GameplaySettings.TorqueMultiplier / Item.Entity.Mass * delta));
Item.AddHeat(_input * Item.Evaluate(_data.Heat) * delta);
Unity.Mathematics.float2x2.Rotate(_input * Torque * Thrust * Item.ItemManager.GameplaySettings.TorqueMultiplier / Item.Entity.Mass * dt));
Item.AddHeat(_input * Item.Evaluate(_data.Heat) * dt);
var vis = _input * Item.Evaluate(_data.Visibility);
if (!Item.Entity.VisibilitySources.ContainsKey(this) || vis > Item.Entity.VisibilitySources[this])
Item.Entity.VisibilitySources[this] = vis;

View file

@ -32,7 +32,7 @@ public class Trigger : IBehavior, IActivatedBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if (_pulled)
{

View file

@ -65,7 +65,7 @@ public class TurretController : IBehavior
}
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if (Item.Entity.Target.Value != null)
{

View file

@ -33,7 +33,7 @@ public class VelocityConversion : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
return true;
}

View file

@ -37,7 +37,7 @@ public class VelocityLimit : IBehavior
Limit = Item.Evaluate(_data.TopSpeed);
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Limit = Item.Evaluate(_data.TopSpeed);
if (length(Item.Entity.Velocity) > Limit)

View file

@ -38,7 +38,7 @@ public class Visibility : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.Visibility);
return true;

View file

@ -118,7 +118,7 @@ public abstract class Weapon : IActivatedBehavior
Velocity = Item.Evaluate(_data.Velocity);
}
public virtual bool Execute(float delta)
public virtual bool Execute(float dt)
{
UpdateStats();
return true;

View file

@ -34,11 +34,11 @@ public class Wear : IBehavior
Item = item;
}
public bool Execute(float delta)
public bool Execute(float dt)
{
if (_data.PerSecond)
{
var dmg = Item.Wear * delta;
var dmg = Item.Wear * dt;
Item.EquippableItem.Durability -= dmg;
Item.Entity.ItemDamage.OnNext((Item, dmg));
}

View file

@ -41,7 +41,7 @@ public enum HardpointType
Tool,
Thermal,
Thruster,
WarpThruster,
WarpDrive,
Reactor,
Radiator,
Shield,
@ -49,7 +49,8 @@ public enum HardpointType
Energy,
Ballistic,
Launcher,
ControlModule
ControlModule,
AetherDrive
}
public enum WeaponType

View file

@ -430,6 +430,9 @@ public class HullData : EquippableItemData
[Inspectable, JsonProperty("armor"), Key(24)]
public float Armor;
[Inspectable, JsonProperty("drag"), Key(25)]
public float Drag;
[IgnoreMember]
public Shape InteriorCells
{

View file

@ -70,8 +70,9 @@ public class LoadoutGenerator
}
var cargo = entity.CargoBays.First();
var inventory = RandomItems<EquippableItemData>(16, 1,
data => !(data is HullData hull && hull.HullType != HullType.Ship) && !(data is CargoBayData))
IEnumerable<EquippableItemData> inventory = RandomItems<EquippableItemData>(16, 1,
data => !(data is HullData hull && hull.HullType != HullType.Ship) && !(data is CargoBayData));
inventory = inventory
.OrderByDescending(item=>item.Shape.Coordinates.Length);
foreach (var item in inventory)
{
@ -86,6 +87,7 @@ public class LoadoutGenerator
{
return ItemManager.ItemData.GetAll<HullData>()
.Where(item =>
item.Price > 0 &&
(hullFilter?.Invoke(item) ?? true) &&
item.HullType == type &&
(Faction == null || item.Manufacturer == Faction.ID || Faction.Allegiance.ContainsKey(item.Manufacturer)))
@ -101,9 +103,11 @@ public class LoadoutGenerator
public T[] RandomItems<T>(int count, float sizeExponent, Predicate<T> filter = null) where T : EquippableItemData
{
return ItemManager.ItemData.GetAll<T>()
.Where(item => Sector.ContainsFaction(item.Manufacturer) &&
(Faction == null || Faction.Allegiance.ContainsKey(item.Manufacturer)) &&
(filter?.Invoke(item) ?? true))
.Where(item =>
item.Price > 0 &&
Sector.ContainsFaction(item.Manufacturer) &&
(Faction == null || Faction.Allegiance.ContainsKey(item.Manufacturer)) &&
(filter?.Invoke(item) ?? true))
.WeightedRandomElements(ref Random, item =>
(Faction == null || item.Manufacturer == Faction.ID ? 1 : Faction.Allegiance[item.Manufacturer]) * // Prioritize items from allied manufacturers
pow(item.Shape.Coordinates.Length, sizeExponent) / // Prioritize larger items

View file

@ -6,7 +6,7 @@ using MessagePack;
public class PlayerSettings
{
[Key(0)] public string Name = "Anonymous";
[Key(1)] public SavedGame CurrentRun;
[Key(1)] public SavedGame SavedRun;
[Key(2)] public TemperatureUnit TemperatureUnit = TemperatureUnit.Celsius;
[Key(3)] public int SignificantDigits = 3;

View file

@ -176,6 +176,8 @@ public class GameplaySettings
public ExponentialLerp LockSpinSpeed;
public float TorqueFloor;
public float TorqueMultiplier;
public float AetherTorqueMultiplier;
public float AetherHeatMultiplier;
public float VisibilityDecay;
public float TargetInfoDecay;
public float TargetDetectionInfoThreshold;

View file

@ -35,6 +35,8 @@ public class Ship : Entity
private HashSet<Thruster> _leftThrusters;
private HashSet<Thruster> _clockwiseThrusters;
private HashSet<Thruster> _counterClockwiseThrusters;
private HashSet<EquippedItem> _aetherDriveItems;
private HashSet<AetherDrive> _aetherDrives;
private bool _exitingWormhole = false;
private bool _enteringWormhole = false;
@ -51,9 +53,9 @@ public class Ship : Entity
public float ClockwiseTorque { get; private set; }
public float CounterClockwiseTorque { get; private set; }
public float LeftStrafeTotalTorque { get; private set; }
private Thruster[] LeftStrafeTorqueThrusters;
private List<Thruster> LeftStrafeTorqueThrusters = new List<Thruster>();
public float RightStrafeTotalTorque { get; private set; }
private Thruster[] RightStrafeTorqueThrusters;
private List<Thruster> RightStrafeTorqueThrusters = new List<Thruster>();
public float TurnTime(float2 direction)
{
@ -89,91 +91,90 @@ public class Ship : Entity
public override void Activate()
{
base.Activate();
_aetherDrives = new HashSet<AetherDrive>(GetBehaviors<AetherDrive>());
_aetherDriveItems = new HashSet<EquippedItem>(_aetherDrives.Select(x => x.Item));
_allThrusters = GetBehaviors<Thruster>().ToArray();
_thrusterItems = new HashSet<EquippedItem>(_allThrusters.Select(x=>x.Item));
_forwardThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.Reversed));
RecalculateForwardThrust();
foreach (var thruster in _forwardThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateForwardThrust());
_reverseThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.None));
RecalculateReverseThrust();
foreach (var thruster in _reverseThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateReverseThrust());
_rightThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.CounterClockwise));
RecalculateRightStrafeThrust();
foreach (var thruster in _rightThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateRightStrafeThrust());
_leftThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Item.EquippableItem.Rotation == ItemRotation.Clockwise));
RecalculateLeftStrafeThrust();
foreach (var thruster in _leftThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateLeftStrafeThrust());
_counterClockwiseThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Torque < -ItemManager.GameplaySettings.TorqueFloor));
RecalculateCounterClockwiseTorque();
foreach (var thruster in _counterClockwiseThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateCounterClockwiseTorque());
_clockwiseThrusters = new HashSet<Thruster>(_allThrusters
.Where(x => x.Torque > ItemManager.GameplaySettings.TorqueFloor));
RecalculateClockwiseTorque();
foreach (var thruster in _clockwiseThrusters)
thruster.Item.Online.Skip(1).Subscribe(b => RecalculateClockwiseTorque());
}
public Ship(ItemManager itemManager, Zone zone, EquippableItem hull, EntitySettings settings) : base(itemManager, zone, hull, settings)
{
void CheckForThruster(EquippedItem item)
{
if (_thrusterItems.Contains(item))
{
foreach (var behavior in item.Behaviors)
{
if (behavior is Thruster thruster)
{
if (_forwardThrusters.Contains(thruster)) RecalculateForwardThrust();
if (_reverseThrusters.Contains(thruster)) RecalculateReverseThrust();
if (_rightThrusters.Contains(thruster)) RecalculateRightStrafeThrust();
if (_leftThrusters.Contains(thruster)) RecalculateLeftStrafeThrust();
if (_clockwiseThrusters.Contains(thruster)) RecalculateClockwiseTorque();
if (_counterClockwiseThrusters.Contains(thruster)) RecalculateCounterClockwiseTorque();
}
}
}
}
ItemDestroyed.Where(item=>_thrusterItems.Contains(item)).Subscribe(RemoveThruster);
ItemDestroyed.Where(item=>_aetherDriveItems.Contains(item)).Subscribe(RemoveAetherDrive);
}
ItemDamage.Select(x => x.item).Subscribe(CheckForThruster);
private void RemoveAetherDrive(EquippedItem item)
{
_aetherDriveItems.Remove(item);
_aetherDrives.Remove(item.GetBehavior<AetherDrive>());
}
private void RemoveThruster(EquippedItem item)
{
_thrusterItems.Remove(item);
var thruster = item.GetBehavior<Thruster>();
if (_forwardThrusters.Contains(thruster)) _forwardThrusters.Remove(thruster);
if (_reverseThrusters.Contains(thruster)) _reverseThrusters.Remove(thruster);
if (_rightThrusters.Contains(thruster)) _rightThrusters.Remove(thruster);
if (_leftThrusters.Contains(thruster)) _leftThrusters.Remove(thruster);
if (_clockwiseThrusters.Contains(thruster)) _clockwiseThrusters.Remove(thruster);
if (_counterClockwiseThrusters.Contains(thruster)) _counterClockwiseThrusters.Remove(thruster);
}
#region ThrustCalculation
private void RecalculateThrust()
{
RecalculateForwardThrust();
RecalculateReverseThrust();
RecalculateLeftStrafeThrust();
RecalculateRightStrafeThrust();
RecalculateClockwiseTorque();
RecalculateCounterClockwiseTorque();
}
private void RecalculateForwardThrust()
{
ForwardThrust = 0;
foreach (var thruster in _forwardThrusters)
{
if(thruster.Item.Active.Value)
if (thruster.Item.Active.Value)
ForwardThrust += thruster.Thrust;
}
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
ForwardThrust += drive.Thrust.x;
}
private void RecalculateReverseThrust()
{
ReverseThrust = 0;
foreach (var thruster in _reverseThrusters)
{
if(thruster.Item.Active.Value)
if (thruster.Item.Active.Value)
ReverseThrust += thruster.Thrust;
}
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
ReverseThrust += drive.Thrust.x;
}
private void RecalculateLeftStrafeThrust()
@ -188,9 +189,14 @@ public class Ship : Entity
LeftStrafeTotalTorque += thruster.Torque * thruster.Thrust;
}
}
LeftStrafeTorqueThrusters = _leftThrusters
.Where(x => abs(sign(x.Torque) - sign(LeftStrafeTotalTorque)) < .01f)
.ToArray();
LeftStrafeTorqueThrusters.Clear();
foreach(var thruster in _leftThrusters)
if (abs(sign(thruster.Torque) - sign(LeftStrafeTotalTorque)) < .01f)
LeftStrafeTorqueThrusters.Add(thruster);
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
LeftStrafeThrust += drive.Thrust.y;
}
private void RecalculateRightStrafeThrust()
@ -205,29 +211,38 @@ public class Ship : Entity
RightStrafeTotalTorque += thruster.Torque * thruster.Thrust;
}
}
RightStrafeTorqueThrusters = _rightThrusters
.Where(x => abs(sign(x.Torque) - sign(RightStrafeTotalTorque)) < .01f)
.ToArray();
RightStrafeTorqueThrusters.Clear();
foreach(var thruster in _rightThrusters)
if (abs(sign(thruster.Torque) - sign(RightStrafeTotalTorque)) < .01f)
RightStrafeTorqueThrusters.Add(thruster);
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
RightStrafeThrust += drive.Thrust.y;
}
private void RecalculateClockwiseTorque()
{
ClockwiseTorque = 0;
foreach (var thruster in _clockwiseThrusters)
{
if(thruster.Item.Active.Value)
if (thruster.Item.Active.Value)
ClockwiseTorque += thruster.Torque;
}
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
ClockwiseTorque += drive.Thrust.z;
}
private void RecalculateCounterClockwiseTorque()
{
CounterClockwiseTorque = 0;
foreach (var thruster in _counterClockwiseThrusters)
{
if(thruster.Item.Active.Value)
if (thruster.Item.Active.Value)
CounterClockwiseTorque -= thruster.Torque;
}
foreach (var drive in _aetherDrives)
if (drive.Item.Active.Value)
CounterClockwiseTorque += drive.Thrust.z;
}
#endregion
@ -236,8 +251,9 @@ public class Ship : Entity
{
if (_active && !_exitingWormhole && !_enteringWormhole)
{
RecalculateThrust();
foreach (var thruster in _allThrusters) thruster.Axis = 0;
var rightThrusterTorqueCompensation = abs(RightStrafeTotalTorque) / RightStrafeTorqueThrusters.Length;
var rightThrusterTorqueCompensation = abs(RightStrafeTotalTorque) / RightStrafeTorqueThrusters.Count;
foreach (var thruster in _rightThrusters)
{
var thrust = 0f;
@ -246,7 +262,7 @@ public class Ship : Entity
thrust -= MovementDirection.x * (rightThrusterTorqueCompensation / (abs(thruster.Torque) * thruster.Thrust));
thruster.Axis = thrust;
}
var leftThrusterTorqueCompensation = abs(LeftStrafeTotalTorque) / LeftStrafeTorqueThrusters.Length;
var leftThrusterTorqueCompensation = abs(LeftStrafeTotalTorque) / LeftStrafeTorqueThrusters.Count;
foreach (var thruster in _leftThrusters)
{
var thrust = 0f;
@ -269,7 +285,14 @@ public class Ship : Entity
foreach (var thruster in _clockwiseThrusters) thruster.Axis += deltaRot;
foreach (var thruster in _counterClockwiseThrusters) thruster.Axis += -deltaRot;
foreach (var drive in _aetherDrives)
drive.Axis = float3(MovementDirection.y, MovementDirection.x, deltaRot);
}
var velocityMagnitude = length(Velocity);
if(velocityMagnitude > .01f)
Velocity = normalize(Velocity) * AetheriaMath.Decay(velocityMagnitude, HullData.Drag, delta);
Position.xz += Velocity * delta;