Action Bar (WIP)

Refactor item instance to use DatabaseLink
Labels now pop up when aiming at loot
Yeeted HUD trigger group UI into the abyss
Created rebindable action bar (missing: assigning actions)
Created Consumable Items
Refactored behaviors to work on consumable items
Implemented Velocity Conversion Behavior
This commit is contained in:
Reinier Vens 2021-04-18 05:13:20 +01:00
commit 4489b18452
217 changed files with 5105 additions and 5703 deletions

View file

@ -28,6 +28,16 @@ public static class AetheriaMath
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static float2 Damp(float2 a, float2 b, float lambda, float dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
public static float3 Damp(float3 a, float3 b, float lambda, float dt)
{
return lerp(a, b, 1 - exp(-lambda * dt));
}
//first-order intercept using absolute target position
public static float3 FirstOrderIntercept
(

View file

@ -14,7 +14,7 @@ public class Minion : Agent
Ship.VisibleHostiles.ObserveAdd().Where(_ => Ship.Target.Value == null).Subscribe(add => Ship.Target.Value = add.Value);
var combatState = new CombatState(this);
_rootState.AddTransition(combatState,
_rootState.AddTransition(combatState,
() => Ship.Target.Value != null, null, true, _rootState);
combatState.AddTransition(_rootState,

View file

@ -37,23 +37,26 @@ public class AetherDriveData : BehaviorData
[Inspectable, JsonProperty("passiveCoupling"), Key(9), RuntimeInspectable]
public PerformanceStat PassiveCoupling;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new AetherDrive(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new AetherDrive(this, item);
}
}
public class AetherDrive : IBehavior
public class AetherDrive : Behavior
{
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
@ -62,54 +65,58 @@ public class AetherDrive : IBehavior
set => _axis = clamp(value, -1, 1);
}
public AetherDrive(AetherDriveData data, EquippedItem item)
public AetherDrive(AetherDriveData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public AetherDrive(AetherDriveData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
public override bool Execute(float dt)
{
var rotorSpeed = Rpm * _data.RotorDiameter / 100;
var forward = normalize(Item.Entity.Direction);
var forward = normalize(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 speed = float2(dot(Entity.Velocity, forward), dot(Entity.Velocity, right));
var couplingEfficiency = 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 couplingLambda = _data.CouplingLambda * max(abs(_axis), 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);
AddHeat((heat.x + heat.y + heat.z)*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));
Entity.Velocity += forward * (_axis.x * force.x / Entity.Mass);
Entity.Velocity += right * (_axis.y * force.y / Entity.Mass);
Entity.Direction = mul(Entity.Direction,
Unity.Mathematics.float2x2.Rotate(force.z * _axis.z * ItemManager.GameplaySettings.AetherTorqueMultiplier / Entity.Mass));
if(float.IsNaN(Item.Entity.Velocity.x))
Item.ItemManager.Log("FUCK FUCK FUCK FUCK");
if(float.IsNaN(Entity.Velocity.x))
ItemManager.Log("FUCK FUCK FUCK FUCK");
MaximumRpm = Item.Evaluate(_data.MaximumRpm);
MaximumRpm = 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 potentialTorque = 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;
var draw = torqueRatio * Evaluate(_data.EnergyDraw) / 3;
if (Item.Entity.TryConsumeEnergy((draw.x + draw.y + draw.z)*dt))
if (Entity.TryConsumeEnergy((draw.x + draw.y + draw.z)*dt))
{
Rpm += actualRpmDelta;
return true;

View file

@ -9,7 +9,7 @@ using static Unity.Mathematics.math;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
public class AutoWeaponData : InstantWeaponData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new AutoWeapon(this, item);
}
@ -18,9 +18,8 @@ public class AutoWeaponData : InstantWeaponData
public class AutoWeapon : InstantWeapon
{
public AutoWeapon(InstantWeaponData data, EquippedItem item) : base(data, item)
{
}
public AutoWeapon(InstantWeaponData data, EquippedItem item) : base(data, item) { }
public AutoWeapon(InstantWeaponData data, ConsumableItemEffect item) : base(data, item) { }
public override bool Execute(float dt)
{

View file

@ -13,28 +13,94 @@ using Unity.Mathematics;
using static Unity.Mathematics.math;
using static Unity.Mathematics.noise;
public interface IBehavior
public abstract class Behavior
{
bool Execute(float dt);
BehaviorData Data { get; }
public BehaviorData Data { get; }
public EquippedItem Item { get; }
private ConsumableItemEffect Consumable { get; }
protected ItemManager ItemManager { get; }
protected Entity Entity => Item?.Entity ?? Consumable.Entity;
public float Temperature => Item?.Temperature ?? Consumable.Entity.MaxTemp;
public float3 Direction
{
get
{
if(Item != null)
{
var hardpoint = Entity.Hardpoints[Item.Position.x, Item.Position.y];
if (hardpoint != null && Entity.HardpointTransforms.ContainsKey(hardpoint))
{
return normalize(Entity.HardpointTransforms[hardpoint].direction);
}
else
{
var itemDirection = Entity.Direction.Rotate(Item.EquippableItem.Rotation);
return float3(itemDirection.x, 0, itemDirection.y);
}
}
return float3(Entity.Direction.x, 0, Entity.Direction.y);
}
}
protected Behavior(BehaviorData data, EquippedItem item)
{
Data = data;
Item = item;
ItemManager = Item.ItemManager;
}
protected Behavior(BehaviorData data, ConsumableItemEffect consumable)
{
Data = data;
Consumable = consumable;
ItemManager = consumable.Entity.ItemManager;
}
public float Evaluate(PerformanceStat stat) => Item?.Evaluate(stat) ?? Consumable.Evaluate(stat);
protected void AddHeat(float heat) => Item?.AddHeat(heat); // TODO: Heat for Consumables
protected void CauseDamage(float damage)
{
if (Item != null)
{
Item.EquippableItem.Durability -= damage;
Entity.ItemDamage.OnNext((Item, damage));
}
else
{
Consumable.Entity.Hull.Durability -= damage;
Consumable.Entity.HullDamage.OnNext(damage);
}
}
protected void CauseWearDamage(float multiplier)
{
if (Item != null)
{
CauseDamage(Item.Wear * multiplier);
}
}
public virtual bool Execute(float dt)
{
return true;
}
}
public interface IActivatedBehavior : IBehavior
public interface IActivatedBehavior
{
void Activate();
void Deactivate();
}
public interface IAnalogBehavior : IBehavior
public interface IAnalogBehavior
{
float Axis { get; set; }
}
public interface IDisposableBehavior
{
void Dispose();
}
public interface IEventBehavior
{
void ResetEvents();
@ -128,12 +194,11 @@ public abstract class BehaviorData
[Inspectable, JsonProperty("group"), Key(0)]
public int Group;
public abstract IBehavior CreateInstance(EquippedItem item);
public abstract Behavior CreateInstance(EquippedItem item);
public abstract Behavior CreateInstance(ConsumableItemEffect consumable);
public override string ToString()
{
var className = base.ToString();
var dataIndex = className.IndexOf("data", StringComparison.InvariantCultureIgnoreCase);
return dataIndex>0 ? className.Substring(0,dataIndex).SplitCamelCase() : className;
return base.ToString().FormatTypeName();
}
}

View file

@ -17,20 +17,21 @@ public class CapacitorData : BehaviorData
[Inspectable, JsonProperty("efficiency"), Key(2), RuntimeInspectable]
public PerformanceStat Efficiency = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Capacitor(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Capacitor(this, item);
}
}
public class Capacitor : IBehavior
public class Capacitor : Behavior
{
private CapacitorData _data;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public float Charge { get; private set; }
public float Capacity { get; private set; }
public float Efficiency { get; private set; } = 1;
@ -38,19 +39,23 @@ public class Capacitor : IBehavior
public void AddCharge(float charge)
{
Charge = clamp(Charge + charge, 0, Capacity);
Item.AddHeat(abs(charge) * (1-Efficiency));
AddHeat(abs(charge) * (1-Efficiency));
}
public Capacitor(CapacitorData data, EquippedItem item)
public Capacitor(CapacitorData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public Capacitor(CapacitorData data, ConsumableItemEffect item) : base(data, item)
{
Capacity = Item.Evaluate(_data.Capacity);
Efficiency = Item.Evaluate(_data.Efficiency);
_data = data;
}
public override bool Execute(float dt)
{
Capacity = Evaluate(_data.Capacity);
Efficiency = Evaluate(_data.Efficiency);
return true;
}
}

View file

@ -45,13 +45,18 @@ public class ChargedWeaponData : InstantWeaponData
[Inspectable, JsonProperty("chargeHeatMul"), Key(32)]
public float ChargeFiringHeatMultiplier = 1;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new ChargedWeapon(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new ChargedWeapon(this, item);
}
}
public class ChargedWeapon : InstantWeapon, IEventBehavior
public class ChargedWeapon : InstantWeapon
{
private ChargedWeaponData _data;
private bool _charging;
@ -97,13 +102,18 @@ public class ChargedWeapon : InstantWeapon, IEventBehavior
{
_data = data;
}
public ChargedWeapon(ChargedWeaponData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
protected override void UpdateStats()
{
base.UpdateStats();
ChargeTime = Item.Evaluate(_data.ChargeTime);
ChargeEnergy = Item.Evaluate(_data.ChargeEnergy);
ChargeHeat = Item.Evaluate(_data.ChargeHeat);
ChargeTime = Evaluate(_data.ChargeTime);
ChargeEnergy = Evaluate(_data.ChargeEnergy);
ChargeHeat = Evaluate(_data.ChargeHeat);
Damage *= lerp(1, _data.ChargeFiringDamageMultiplier, saturate(_charge));
Heat *= lerp(1, _data.ChargeFiringHeatMultiplier, saturate(_charge));
Spread *= lerp(1, _data.ChargeFiringSpreadMultiplier, saturate(_charge));
@ -119,7 +129,7 @@ public class ChargedWeapon : InstantWeapon, IEventBehavior
_charge += dt / ChargeTime;
if (!_charged)
{
Item.AddHeat(ChargeHeat * (dt / ChargeTime));
AddHeat(ChargeHeat * (dt / ChargeTime));
if(_charge > 1)
{
_charged = true;
@ -133,7 +143,7 @@ public class ChargedWeapon : InstantWeapon, IEventBehavior
_coolingDown = true;
_charge = 0;
OnFailed?.Invoke();
Item.EquippableItem.Durability -= _data.FailureDamage;
CauseDamage(_data.FailureDamage);
}
}
return base.Execute(dt);

View file

@ -11,29 +11,27 @@ using static Unity.Mathematics.math;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
public class CockpitData : BehaviorData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Cockpit(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Cockpit(this, item);
}
}
public class Cockpit : IBehavior
public class Cockpit : Behavior
{
private CockpitData _data;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public Cockpit(CockpitData data, EquippedItem item)
public Cockpit(CockpitData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public Cockpit(CockpitData data, ConsumableItemEffect item) : base(data, item)
{
return true;
_data = data;
}
}

View file

@ -14,7 +14,12 @@ public class ConstantWeaponData : WeaponData
[InspectablePrefab, JsonProperty("ammoInterval"), Key(17)]
public float AmmoInterval = 1;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new ConstantWeapon(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new ConstantWeapon(this, item);
}
@ -62,12 +67,17 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
_data = data;
}
public ConstantWeapon(ConstantWeaponData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
public override bool Execute(float dt)
{
base.Execute(dt);
if (_firing)
{
if (!Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.Energy) * dt))
if (!Entity.TryConsumeEnergy(Evaluate(_data.Energy) * dt))
{
_firing = false;
OnStopFiring?.Invoke();
@ -93,7 +103,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
if (_data.MagazineSize > 1 && _ammo > 0) _ammo--;
else
{
var cargo = Item.Entity.FindItemInCargo(_data.AmmoType);
var cargo = Entity.FindItemInCargo(_data.AmmoType);
if (cargo != null)
{
var item = cargo.ItemsOfType[_data.AmmoType][0];
@ -115,11 +125,9 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
}
}
var dmg = Item.Wear * dt;
Item.EquippableItem.Durability -= dmg;
Item.Entity.ItemDamage.OnNext((Item, dmg));
Item.AddHeat(Item.Evaluate(_data.Heat) * dt);
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.Visibility);
CauseWearDamage(dt);
AddHeat(Evaluate(_data.Heat) * dt);
Entity.VisibilitySources[this] = Evaluate(_data.Visibility);
}
return true;
}

View file

@ -15,30 +15,36 @@ public class CooldownData : BehaviorData
[Inspectable, JsonProperty("cooldown"), Key(1), RuntimeInspectable]
public PerformanceStat Cooldown = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Cooldown(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Cooldown(this, item);
}
}
public class Cooldown : IBehavior, IAlwaysUpdatedBehavior, IProgressBehavior
public class Cooldown : Behavior, IAlwaysUpdatedBehavior, IProgressBehavior
{
private CooldownData _data;
public BehaviorData Data => _data;
private EquippedItem Item { get; }
private float _cooldown; // Normalized
public float Progress => saturate(_cooldown);
public Cooldown(CooldownData data, EquippedItem item)
public Cooldown(CooldownData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public Cooldown(CooldownData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
public override bool Execute(float dt)
{
if (_cooldown < 0)
{
@ -47,11 +53,10 @@ public class Cooldown : IBehavior, IAlwaysUpdatedBehavior, IProgressBehavior
}
return false;
}
public void Update(float delta)
{
_cooldown -= delta / Item.Evaluate(_data.Cooldown);
_cooldown -= delta / Evaluate(_data.Cooldown);
}
}

View file

@ -16,28 +16,33 @@ public class EnergyDrawData : BehaviorData
[Inspectable, JsonProperty("perSecond"), Key(2)]
public bool PerSecond;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new EnergyDraw(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new EnergyDraw(this, item);
}
}
public class EnergyDraw : IBehavior
public class EnergyDraw : Behavior
{
private EnergyDrawData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public EnergyDraw(EnergyDrawData data, EquippedItem item)
public EnergyDraw(EnergyDrawData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public EnergyDraw(EnergyDrawData data, ConsumableItemEffect item) : base(data, item)
{
return Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.EnergyDraw) * (_data.PerSecond ? dt : 1));
_data = data;
}
public override bool Execute(float dt)
{
return Entity.TryConsumeEnergy(Evaluate(_data.EnergyDraw) * (_data.PerSecond ? dt : 1));
}
}

View file

@ -16,29 +16,33 @@ public class HeatData : BehaviorData
[Inspectable, JsonProperty("perSecond"), Key(2)]
public bool PerSecond;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Heat(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Heat(this, item);
}
}
public class Heat : IBehavior
public class Heat : Behavior
{
private HeatData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public Heat(HeatData data, EquippedItem item)
public Heat(HeatData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Heat(HeatData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
Item.AddHeat(Item.Evaluate(_data.Heat) * (_data.PerSecond ? dt : 1));
AddHeat(Evaluate(_data.Heat) * (_data.PerSecond ? dt : 1));
return true;
}

View file

@ -11,28 +11,27 @@ using static Unity.Mathematics.math;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
public class HeatStorageData : BehaviorData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new HeatStorage(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new HeatStorage(this, item);
}
}
public class HeatStorage : IBehavior
public class HeatStorage : Behavior
{
private HeatStorageData _data;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public HeatStorage(HeatStorageData data, EquippedItem item)
public HeatStorage(HeatStorageData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public HeatStorage(HeatStorageData data, ConsumableItemEffect item) : base(data, item)
{
return true;
_data = data;
}
}

View file

@ -21,7 +21,12 @@ public class InstantWeaponData : WeaponData
[InspectablePrefab, JsonProperty("ammoInterval"), Key(20)]
public bool SingleAmmoBurst;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new InstantWeapon(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new InstantWeapon(this, item);
}
@ -77,11 +82,17 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
_ammo = data.MagazineSize;
}
public InstantWeapon(InstantWeaponData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
_ammo = data.MagazineSize;
}
protected void Trigger()
{
// If 1 ammo is consumed per burst, perform ammo and energy consumption here
// UseAmmo returns false when triggering reload; cancel firing if that is the case
if(_data.SingleAmmoBurst && (!Item.Entity.TryConsumeEnergy(Energy) || !UseAmmo())) return;
if(_data.SingleAmmoBurst && (!Entity.TryConsumeEnergy(Energy) || !UseAmmo())) return;
_burstRemaining = (int) BurstCount;
_burstInterval = BurstTime / _burstRemaining;
@ -93,9 +104,9 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
protected override void UpdateStats()
{
base.UpdateStats();
BurstCount = Item.Evaluate(_data.Count);
BurstTime = Item.Evaluate(_data.BurstTime);
Cooldown = Item.Evaluate(_data.Cooldown);
BurstCount = Evaluate(_data.Count);
BurstTime = Evaluate(_data.BurstTime);
Cooldown = Evaluate(_data.Cooldown);
Damage /= (int) BurstCount;
Heat /= (int) BurstCount;
@ -115,7 +126,7 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
var hasAmmo = true;
if (_data.AmmoType != Guid.Empty)
{
var cargo = Item.Entity.FindItemInCargo(_data.AmmoType);
var cargo = Entity.FindItemInCargo(_data.AmmoType);
if (cargo != null)
{
var item = cargo.ItemsOfType[_data.AmmoType][0];
@ -160,7 +171,7 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
{
// If multiple ammo is consumed per burst, perform ammo and energy consumption here
// UseAmmo returns false when triggering reload; cancel firing if that is the case
if (!_data.SingleAmmoBurst && (!Item.Entity.TryConsumeEnergy(Energy) || !UseAmmo()))
if (!_data.SingleAmmoBurst && (!Entity.TryConsumeEnergy(Energy) || !UseAmmo()))
{
_burstRemaining = 0;
return false;
@ -169,10 +180,9 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
_burstRemaining--;
_burstTimer -= _burstInterval;
OnFire?.Invoke();
Item.EquippableItem.Durability -= Item.Wear;
Item.Entity.ItemDamage.OnNext((Item, Item.Wear));
Item.AddHeat(Heat);
Item.Entity.VisibilitySources[this] = Visibility;
CauseWearDamage(1);
AddHeat(Heat);
Entity.VisibilitySources[this] = Visibility;
}
return true;
}

View file

@ -13,29 +13,34 @@ public class ItemUsageData : BehaviorData
[InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("item"), Key(1), RuntimeInspectable]
public Guid Item;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new ItemUsage(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new ItemUsage(this, item);
}
}
public class ItemUsage : IBehavior
public class ItemUsage : Behavior
{
private ItemUsageData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public ItemUsage(ItemUsageData data, EquippedItem item)
public ItemUsage(ItemUsageData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public ItemUsage(ItemUsageData data, ConsumableItemEffect item) : base(data, item)
{
var cargo = Item.Entity.FindItemInCargo(_data.Item);
_data = data;
}
public override bool Execute(float dt)
{
var cargo = Entity.FindItemInCargo(_data.Item);
if (cargo == null) return false;
var item = cargo.ItemsOfType[_data.Item][0];

View file

@ -27,7 +27,7 @@ public class LauncherData : LockWeaponData
[Inspectable, JsonProperty("missileSpeed"), Key(31), RuntimeInspectable]
public PerformanceStat MissileVelocity = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new LockWeapon(this, item);
}
@ -54,7 +54,7 @@ public class GuidedWeaponData : InstantWeaponData
[Inspectable, JsonProperty("missileSpeed"), Key(26), RuntimeInspectable]
public PerformanceStat MissileVelocity = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new InstantWeapon(this, item);
}

View file

@ -24,7 +24,11 @@ public class LockWeaponData : InstantWeaponData
[Inspectable, JsonProperty("decay"), Key(25)]
public PerformanceStat Decay = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new LockWeapon(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new LockWeapon(this, item);
}
@ -49,7 +53,7 @@ public class LockWeapon : InstantWeapon
public override float Progress => saturate(_cooldown > 0 ? _cooldown : _lock);
public override bool CanFire => base.CanFire && _lock > .99f && Item.Entity.TargetRange > MinRange && Item.Entity.TargetRange < Range;
public override bool CanFire => base.CanFire && _lock > .99f && Entity.TargetRange > MinRange && Entity.TargetRange < Range;
public float Lock
{
@ -60,28 +64,32 @@ public class LockWeapon : InstantWeapon
{
_data = data;
}
public LockWeapon(LockWeaponData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
public override bool Execute(float dt)
{
if (_target != Item.Entity.Target.Value)
if (_target != Entity.Target.Value)
{
_lock = 0;
_target = Item.Entity.Target.Value;
_target = Entity.Target.Value;
}
if (Item.Entity.Target.Value != null && Item.Entity.Target.Value.IsHostileTo(Item.Entity))
if (Entity.Target.Value != null && Entity.Target.Value.IsHostileTo(Entity))
{
LockSpeed = Item.Evaluate(_data.LockSpeed);
SensorImpact = Item.Evaluate(_data.SensorImpact);
LockAngle = Item.Evaluate(_data.LockAngle);
DirectionImpact = Item.Evaluate(_data.DirectionImpact);
Decay = Item.Evaluate(_data.Decay);
LockSpeed = Evaluate(_data.LockSpeed);
SensorImpact = Evaluate(_data.SensorImpact);
LockAngle = Evaluate(_data.LockAngle);
DirectionImpact = Evaluate(_data.DirectionImpact);
Decay = Evaluate(_data.Decay);
var degrees = acos(dot(normalize(Item.Entity.Target.Value.Position - Item.Entity.Position), normalize(Item.Entity.LookDirection))) * 57.2958f;
var degrees = acos(dot(normalize(Entity.Target.Value.Position - Entity.Position), normalize(Entity.LookDirection))) * 57.2958f;
if (degrees < LockAngle)
{
var lerp = 1 - unlerp(0, 90, degrees);
_lock = saturate(_lock + pow(lerp, DirectionImpact) * dt * LockSpeed * pow(Item.Entity.EntityInfoGathered[Item.Entity.Target.Value], SensorImpact));
_lock = saturate(_lock + pow(lerp, DirectionImpact) * dt * LockSpeed * pow(Entity.EntityInfoGathered[Entity.Target.Value], SensorImpact));
}
else _lock = saturate(_lock - dt * Decay);
}

View file

@ -24,45 +24,49 @@ public class MiningToolData : BehaviorData
[Inspectable, JsonProperty("range"), Key(4)]
public PerformanceStat Range = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new MiningTool(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new MiningTool(this, item);
}
}
public class MiningTool : IBehavior
public class MiningTool : Behavior
{
public Guid AsteroidBelt;
public int Asteroid;
private MiningToolData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public float Range { get; private set; }
public MiningTool(MiningToolData data, EquippedItem item)
public MiningTool(MiningToolData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public MiningTool(MiningToolData data, ConsumableItemEffect item) : base(data, item)
{
Range = Item.Evaluate(_data.Range);
var belt = Item.Entity.Zone.AsteroidBelts[AsteroidBelt];
_data = data;
}
public override bool Execute(float dt)
{
Range = Evaluate(_data.Range);
var belt = Entity.Zone.AsteroidBelts[AsteroidBelt];
if (AsteroidBelt != Guid.Empty &&
Item.Entity.Zone.AsteroidExists(AsteroidBelt, Asteroid) &&
length(Item.Entity.Position.xz - belt.Positions[Asteroid].xz) - belt.Scales[Asteroid] < Range)
Entity.Zone.AsteroidExists(AsteroidBelt, Asteroid) &&
length(Entity.Position.xz - belt.Positions[Asteroid].xz) - belt.Scales[Asteroid] < Range)
{
Item.Entity.Zone.MineAsteroid(
Item.Entity,
Entity.Zone.MineAsteroid(
Entity,
AsteroidBelt,
Asteroid,
Item.Evaluate(_data.DamagePerSecond) * dt,
Item.Evaluate(_data.Efficiency),
Item.Evaluate(_data.Penetration));
Evaluate(_data.DamagePerSecond) * dt,
Evaluate(_data.Efficiency),
Evaluate(_data.Penetration));
return true;
}

View file

@ -25,19 +25,24 @@ public class RadiatorData : BehaviorData
[Inspectable, JsonProperty("energyUsage"), Key(5), RuntimeInspectable]
public PerformanceStat EnergyUsage = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
[Inspectable, JsonProperty("thermalMass"), Key(6), RuntimeInspectable]
public PerformanceStat ThermalMass = new PerformanceStat();
public override Behavior CreateInstance(EquippedItem item)
{
return new Radiator(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Radiator(this, item);
}
}
public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavior
public class Radiator : Behavior, IAlwaysUpdatedBehavior, IInitializableBehavior
{
public EquippedItem Item { get; }
public float Temperature { get; private set; }
public BehaviorData Data => _data;
public float RadiatorTemperature { get; private set; }
public float Emissivity { get; private set; }
public float PumpedHeat { get; private set; }
public float WasteHeat { get; private set; }
@ -45,25 +50,28 @@ public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavio
private RadiatorData _data;
public Radiator(RadiatorData data, EquippedItem item)
public Radiator(RadiatorData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Radiator(RadiatorData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
PumpedHeat = Item.Evaluate(_data.PumpedHeat);
WasteHeat = Item.Evaluate(_data.WasteHeat);
EnergyUsage = Item.Evaluate(_data.EnergyUsage);
PumpedHeat = Evaluate(_data.PumpedHeat);
WasteHeat = Evaluate(_data.WasteHeat);
EnergyUsage = Evaluate(_data.EnergyUsage);
var itemTemperature = Item.Temperature;
var tempRatio = max(Temperature / itemTemperature, 1);
var itemTemperature = Temperature;
var tempRatio = max(RadiatorTemperature / itemTemperature, 1);
// Temperature ratio would cause more waste heat than pump capacity, stop executing
if (tempRatio > PumpedHeat / WasteHeat) return true;
if (!Item.Entity.TryConsumeEnergy(EnergyUsage * tempRatio * dt)) return false;
if (!Entity.TryConsumeEnergy(EnergyUsage * tempRatio * dt)) return false;
var pumpedHeat = PumpedHeat * max(itemTemperature - _data.TemperatureFloor, 0);
@ -72,22 +80,22 @@ public class Radiator : IBehavior, IAlwaysUpdatedBehavior, IInitializableBehavio
var wasteHeat = WasteHeat * tempRatio;
Item.AddHeat((wasteHeat - pumpedHeat) * dt);
Temperature += pumpedHeat / Item.ItemManager.GetThermalMass(Item.EquippableItem) * dt;
AddHeat((wasteHeat - pumpedHeat) * dt);
RadiatorTemperature += pumpedHeat / Evaluate(_data.ThermalMass) * dt;
return true;
}
public void Update(float delta)
{
Emissivity = Item.Evaluate(_data.Emissivity);
var rad = pow(Temperature, Item.ItemManager.GameplaySettings.HeatRadiationExponent) * Item.ItemManager.GameplaySettings.HeatRadiationMultiplier * Emissivity;
Temperature -= rad * delta;
Item.Entity.VisibilitySources[this] = rad;
Emissivity = Evaluate(_data.Emissivity);
var rad = pow(RadiatorTemperature, ItemManager.GameplaySettings.HeatRadiationExponent) * ItemManager.GameplaySettings.HeatRadiationMultiplier * Emissivity;
RadiatorTemperature -= rad * delta;
Entity.VisibilitySources[this] = rad;
}
public void Initialize()
{
Temperature = Item.Temperature;
RadiatorTemperature = Temperature;
}
}

View file

@ -2,6 +2,7 @@
* 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 System;
using System.Collections.Generic;
using System.Linq;
using MessagePack;
@ -25,45 +26,55 @@ public class ReactorData : BehaviorData
[Inspectable, JsonProperty("underload"), Key(4), RuntimeInspectable]
public PerformanceStat ThrottlingFactor = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Reactor(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Reactor(this, item);
}
}
public class Reactor : IBehavior, IOrderedBehavior
public class Reactor : Behavior, IOrderedBehavior, IDisposable
{
private ReactorData _data;
public Entity Entity { get; }
public EquippedItem Item { get; }
public ItemManager Context { get; }
public float Draw { get; private set; }
public float CurrentLoadRatio { get; private set; }
public int Order => 100;
public BehaviorData Data => _data;
private List<Capacitor> _capacitors;
public Reactor(ReactorData data, EquippedItem item)
private List<IDisposable> _subscriptions = new List<IDisposable>();
public Reactor(ReactorData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
_capacitors = Item.Entity.GetBehaviors<Capacitor>().ToList();
Item.Entity.Equipment.ObserveAdd().Subscribe(onAdd =>
FindCapacitors();
}
public Reactor(ReactorData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
FindCapacitors();
}
private void FindCapacitors()
{
_capacitors = Entity.GetBehaviors<Capacitor>().ToList();
_subscriptions.Add(Entity.Equipment.ObserveAdd().Subscribe(onAdd =>
{
var capacitor = onAdd.Value.GetBehavior<Capacitor>();
if (capacitor != null) _capacitors.Add(capacitor);
});
Item.Entity.Equipment.ObserveRemove().Subscribe(onRemove =>
}));
_subscriptions.Add(Entity.Equipment.ObserveRemove().Subscribe(onRemove =>
{
var capacitor = onRemove.Value.GetBehavior<Capacitor>();
if (capacitor != null) _capacitors.Remove(capacitor);
});
}));
}
public void ConsumeEnergy(float energy)
@ -71,10 +82,10 @@ public class Reactor : IBehavior, IOrderedBehavior
Draw += energy;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
var charge = Item.Evaluate(_data.Charge) * dt;
var efficiency = Item.Evaluate(_data.Efficiency);
var charge = Evaluate(_data.Charge) * dt;
var efficiency = Evaluate(_data.Efficiency);
// This behavior executes last, so any components drawing power have already done so
@ -88,7 +99,7 @@ public class Reactor : IBehavior, IOrderedBehavior
if (Draw > .01f)
{
CurrentLoadRatio = (Draw + charge) / max(charge, .01f);
var overloadEfficiency = Item.Evaluate(_data.OverloadEfficiency);
var overloadEfficiency = Evaluate(_data.OverloadEfficiency);
// Generate heat using overload efficiency, usually much less efficient!
heat += Draw / overloadEfficiency;
@ -121,7 +132,7 @@ public class Reactor : IBehavior, IOrderedBehavior
if (Draw < -.01f)
{
CurrentLoadRatio = (Draw + charge) / max(charge, .01f);
heat -= Draw / efficiency * (1 - 1 / Item.Evaluate(_data.ThrottlingFactor));
heat -= Draw / efficiency * (1 - 1 / Evaluate(_data.ThrottlingFactor));
Draw = 0;
}
else
@ -129,7 +140,13 @@ public class Reactor : IBehavior, IOrderedBehavior
CurrentLoadRatio = 1;
}
Item.AddHeat(heat);
AddHeat(heat);
return true;
}
public void Dispose()
{
foreach(var sub in _subscriptions)
sub.Dispose();
}
}

View file

@ -16,29 +16,34 @@ public class ReflectorData : BehaviorData
// [InspectableAnimationCurve, JsonProperty("visibility"), Key(1)]
// public float4[] VisibilityCurve;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Reflector(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Reflector(this, item);
}
}
public class Reflector : IBehavior
public class Reflector : Behavior
{
public EquippedItem Item { get; }
public BehaviorData Data => _data;
private ReflectorData _data;
public Reflector(ReflectorData data, EquippedItem item)
public Reflector(ReflectorData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public Reflector(ReflectorData data, ConsumableItemEffect item) : base(data, item)
{
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.CrossSection) * Item.Entity.Zone.GetLight(Item.Entity.Position.xz);
_data = data;
}
public override bool Execute(float dt)
{
Entity.VisibilitySources[this] = Evaluate(_data.CrossSection) * Entity.Zone.GetLight(Entity.Position.xz);
return true;
}

View file

@ -21,13 +21,18 @@ public class ResourceScannerData : BehaviorData
[Inspectable, JsonProperty("scanDuration"), Key(3), RuntimeInspectable]
public PerformanceStat ScanDuration = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new ResourceScanner(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new ResourceScanner(this, item);
}
}
public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
public class ResourceScanner : Behavior, IAlwaysUpdatedBehavior
{
public int Asteroid = -1;
@ -35,9 +40,6 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
private float _scanTime;
private Guid _scanTarget;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public float Range { get; private set; }
public float MinimumDensity { get; private set; }
public float ScanDuration { get; private set; }
@ -55,22 +57,26 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
}
}
public ResourceScanner(ResourceScannerData data, EquippedItem item)
public ResourceScanner(ResourceScannerData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public ResourceScanner(ResourceScannerData data, ConsumableItemEffect item) : base(data, item)
{
var planetData = Item.Entity.Zone.Planets[ScanTarget];
_data = data;
}
public override bool Execute(float dt)
{
var planetData = Entity.Zone.Planets[ScanTarget];
if (planetData != null)
{
if (planetData is AsteroidBeltData beltData)
{
if(Asteroid > -1 &&
Asteroid < beltData.Asteroids.Length &&
length(Item.Entity.Position.xz - Item.Entity.Zone.AsteroidBelts[ScanTarget].Positions[Asteroid].xz) < Range)
length(Entity.Position.xz - Entity.Zone.AsteroidBelts[ScanTarget].Positions[Asteroid].xz) < Range)
{
_scanTime += dt;
if (_scanTime > ScanDuration)
@ -84,7 +90,7 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
}
else
{
if(length(Item.Entity.Position.xz - Item.Entity.Zone.GetOrbitPosition(planetData.Orbit)) < Range)
if(length(Entity.Position.xz - Entity.Zone.GetOrbitPosition(planetData.Orbit)) < Range)
{
_scanTime += dt;
if (_scanTime > ScanDuration)
@ -101,8 +107,8 @@ public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior
public void Update(float delta)
{
Range = Item.Evaluate(_data.Range);
MinimumDensity = Item.Evaluate(_data.MinimumDensity);
ScanDuration = Item.Evaluate(_data.ScanDuration);
Range = Evaluate(_data.Range);
MinimumDensity = Evaluate(_data.MinimumDensity);
ScanDuration = Evaluate(_data.ScanDuration);
}
}

View file

@ -39,13 +39,18 @@ public class SensorData : BehaviorData
[Inspectable, JsonProperty("pingRadiusExponent"), Key(11)]
public float PingRadiusExponent = .5f;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Sensor(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Sensor(this, item);
}
}
public class Sensor : IBehavior, IEventBehavior
public class Sensor : Behavior, IEventBehavior
{
private SensorData _data;
private float _pingCooldown;
@ -54,10 +59,6 @@ public class Sensor : IBehavior, IEventBehavior
private float _pingRadius;
private HashSet<Entity> _pingedEntities = new HashSet<Entity>();
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public float Cooldown
{
get => saturate(_pingCooldown);
@ -81,9 +82,9 @@ public class Sensor : IBehavior, IEventBehavior
public void Ping()
{
if(_pingCooldown < 0 && Item.Entity.TryConsumeEnergy(Item.Evaluate(_data.PingEnergy)))
if(_pingCooldown < 0 && Entity.TryConsumeEnergy(Evaluate(_data.PingEnergy)))
{
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.PingVisibility);
Entity.VisibilitySources[this] = Evaluate(_data.PingVisibility);
_pinging = true;
_pingCooldown = 1;
_pingLerp = 0;
@ -93,18 +94,22 @@ public class Sensor : IBehavior, IEventBehavior
}
}
public Sensor(SensorData data, EquippedItem item)
public Sensor(SensorData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public Sensor(SensorData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
}
public override bool Execute(float dt)
{
if (_pinging)
{
_pingLerp += dt / _data.PingDuration;
_pingRadius = lerp(0, Item.Evaluate(_data.PingRange), pow(_pingLerp, _data.PingRadiusExponent));
_pingRadius = lerp(0, Evaluate(_data.PingRange), pow(_pingLerp, _data.PingRadiusExponent));
if (_pingLerp > 1)
{
_pinging = false;
@ -112,30 +117,27 @@ public class Sensor : IBehavior, IEventBehavior
}
}
_pingCooldown -= dt / Item.Evaluate(_data.PingCooldown);
_pingCooldown -= dt / Evaluate(_data.PingCooldown);
// TODO: Handle Active Detection / Visibility From Reflected Radiance
var hardpoint = Item.Entity.Hardpoints[Item.Position.x, Item.Position.y];
var forward = hardpoint != null && Item.Entity.HardpointTransforms.ContainsKey(hardpoint) ?
normalize(Item.Entity.HardpointTransforms[hardpoint].direction.xz) :
Item.Entity.Direction;
foreach (var entity in Item.Entity.Zone.Entities)
var forward = Direction.xz;
foreach (var entity in Entity.Zone.Entities)
{
if (entity == Item.Entity) continue;
if (entity == Entity) continue;
var diff = entity.Position.xz - Item.Entity.Position.xz;
var diff = entity.Position.xz - Entity.Position.xz;
var angle = acos(dot(forward, normalize(diff)));
var dist = length(diff);
float previous, next;
Item.Entity.EntityInfoGathered.TryGetValue(entity, out previous);
Entity.EntityInfoGathered.TryGetValue(entity, out previous);
if (!_pingedEntities.Contains(entity) && dist < _pingRadius)
{
_pingedEntities.Add(entity);
next = saturate(
previous +
entity.Visibility *
Item.Evaluate(_data.Sensitivity) *
Item.Evaluate(_data.PingBoost) *
Evaluate(_data.Sensitivity) *
Evaluate(_data.PingBoost) *
dist);
}
else
@ -143,13 +145,13 @@ public class Sensor : IBehavior, IEventBehavior
next = saturate(
previous +
entity.Visibility *
Item.Evaluate(_data.Sensitivity) *
Evaluate(_data.Sensitivity) *
_data.SensitivityCurve.Evaluate(angle / PI) *
dt / dist);
}
next *= 1 - Item.ItemManager.GameplaySettings.TargetInfoDecay * dt;
next *= 1 - ItemManager.GameplaySettings.TargetInfoDecay * dt;
//Context.Log($"{entity.Name} visibility {(int)(previous * 100)}% -> {(int)(next * 100)}%");
Item.Entity.EntityInfoGathered[entity] = next;
Entity.EntityInfoGathered[entity] = next;
}
return true;
}

View file

@ -16,44 +16,48 @@ public class ShieldData : BehaviorData
[Inspectable, JsonProperty("energy"), Key(2), RuntimeInspectable]
public PerformanceStat EnergyUsage = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Shield(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Shield(this, item);
}
}
public class Shield : IBehavior
public class Shield : Behavior
{
public EquippedItem Item { get; }
public float Efficiency { get; private set; }
public float EnergyUsage { get; private set; }
public BehaviorData Data => _data;
private ShieldData _data;
public Shield(ShieldData data, EquippedItem item)
public Shield(ShieldData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Shield(ShieldData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
Efficiency = Item.Evaluate(_data.Efficiency);
EnergyUsage = Item.Evaluate(_data.EnergyUsage);
Efficiency = Evaluate(_data.Efficiency);
EnergyUsage = Evaluate(_data.EnergyUsage);
return true;
}
public bool CanTakeHit(DamageType type, float damage)
{
return Item.Entity.CanConsumeEnergy(damage * EnergyUsage);
return Entity.CanConsumeEnergy(damage * EnergyUsage);
}
public void TakeHit(DamageType type, float damage)
{
Item.Entity.TryConsumeEnergy(damage * EnergyUsage);
Item.AddHeat(damage / Efficiency);
Entity.TryConsumeEnergy(damage * EnergyUsage);
AddHeat(damage / Efficiency);
}
}

View file

@ -22,19 +22,21 @@ public class StatModifierData : BehaviorData
[InspectableType(typeof(BehaviorData)), JsonProperty("requireBehavior"), Key(4)]
public Type RequireBehavior;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new StatModifier(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect consumable)
{
return new StatModifier(this, consumable);
}
}
[Order(-4)]
public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavior
public class StatModifier : Behavior, IInitializableBehavior, IDisposable
{
private StatModifierData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
private PerformanceStat[] _stats;
@ -43,10 +45,14 @@ public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavi
private static Type[] StatObjects => _statObjects = _statObjects ?? typeof(BehaviorData).GetAllChildClasses()
.Concat(typeof(EquippableItemData).GetAllChildClasses()).ToArray();
public StatModifier(StatModifierData data, EquippedItem item)
public StatModifier(StatModifierData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public StatModifier(StatModifierData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public void Initialize()
@ -59,17 +65,17 @@ public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavi
if (statField != null)
{
if (typeof(EquippableItemData).IsAssignableFrom(targetType))
_stats = Item.Entity.Equipment
_stats = Entity.Equipment
.Select(hp => hp.EquippableItem)
.Where(gear => _data.RequireBehavior == null || Item.ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.Where(gear => Item.ItemManager.GetData(gear).GetType() == targetType)
.Select(gear => statField.GetValue(Item.ItemManager.GetData(gear)) as PerformanceStat)
.Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.Where(gear => ItemManager.GetData(gear).GetType() == targetType)
.Select(gear => statField.GetValue(ItemManager.GetData(gear)) as PerformanceStat)
.ToArray();
else
_stats = Item.Entity.Equipment
_stats = Entity.Equipment
.Select(hp => hp.EquippableItem)
.Where(gear => _data.RequireBehavior == null || Item.ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.SelectMany(gear => Item.ItemManager.GetData(gear).Behaviors)
.Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.SelectMany(gear => ItemManager.GetData(gear).Behaviors)
.Where(behaviorData => behaviorData.GetType() == targetType)
.Select(behaviorData => statField.GetValue(behaviorData) as PerformanceStat)
.ToArray();
@ -77,19 +83,19 @@ public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavi
}
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
foreach (var stat in _stats)
(_data.Type == StatModifierType.Constant
? stat.GetConstantModifiers(Item.Entity)
: stat.GetScaleModifiers(Item.Entity))[this] = Item.Evaluate(_data.Modifier);
? stat.GetConstantModifiers(Entity)
: stat.GetScaleModifiers(Entity))[this] = Evaluate(_data.Modifier);
return true;
}
public void Dispose()
{
foreach (var stat in _stats)
(_data.Type == StatModifierType.Constant ? stat.GetConstantModifiers(Item.Entity) : stat.GetScaleModifiers(Item.Entity)).Remove(this);
(_data.Type == StatModifierType.Constant ? stat.GetConstantModifiers(Entity) : stat.GetScaleModifiers(Entity)).Remove(this);
}
}

View file

@ -10,29 +10,32 @@ using Newtonsoft.Json;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-25)]
public class SwitchData : BehaviorData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Switch(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Switch(this, item);
}
}
public class Switch : IBehavior
public class Switch : Behavior
{
private SwitchData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public bool Activated { get; set; }
public Switch(SwitchData data, EquippedItem item)
public Switch(SwitchData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Switch(SwitchData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
return Activated;
}

View file

@ -19,31 +19,36 @@ public class ThermotoggleData : BehaviorData
[Inspectable, JsonProperty("adjustable"), Key(3)]
public bool Adjustable;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Thermotoggle(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Thermotoggle(this, item);
}
}
public class Thermotoggle : IBehavior
public class Thermotoggle : Behavior
{
public float TargetTemperature;
private ThermotoggleData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
public ThermotoggleData ThermotoggleData => _data;
public Thermotoggle(ThermotoggleData data, EquippedItem item)
public Thermotoggle(ThermotoggleData data, EquippedItem item) : base(data, item)
{
_data = data;
TargetTemperature = data.TargetTemperature;
}
public Thermotoggle(ThermotoggleData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
TargetTemperature = data.TargetTemperature;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
return Item.Temperature < TargetTemperature ^ _data.HighPass;
return Temperature < TargetTemperature ^ _data.HighPass;
}
}

View file

@ -25,16 +25,19 @@ public class ThrusterData : BehaviorData
[InspectablePrefab, JsonProperty("Particles"), Key(5)]
public string ParticlesPrefab;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Thruster(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Thruster(this, item);
}
}
public class Thruster : IAnalogBehavior
public class Thruster : Behavior, IAnalogBehavior
{
public EquippedItem Item { get; }
public float Thrust { get; private set; }
public float Torque { get; }
@ -44,37 +47,41 @@ public class Thruster : IAnalogBehavior
set => _input = saturate(value);
}
public BehaviorData Data => _data;
private ThrusterData _data;
private float _input;
public Thruster(ThrusterData data, EquippedItem item)
public Thruster(ThrusterData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
var hullData = Item.ItemManager.GetData(Item.Entity.Hull) as HullData;
var hullData = ItemManager.GetData(Entity.Hull) as HullData;
var hullCenter = hullData.Shape.CenterOfMass;
var itemData = Item.ItemManager.GetData(item.EquippableItem);
var itemData = ItemManager.GetData(item.EquippableItem);
var itemCenter = hullData.Shape.Inset(itemData.Shape, item.Position, item.EquippableItem.Rotation).CenterOfMass;
var toCenter = hullCenter - itemCenter;
Torque = -dot(normalize(toCenter), float2(1, 0).Rotate(item.EquippableItem.Rotation));
Thrust = Item.Evaluate(_data.Thrust);
Thrust = Evaluate(_data.Thrust);
}
public bool Execute(float dt)
public Thruster(ThrusterData data, ConsumableItemEffect item) : base(data, item)
{
if(_input > .01f && Item.Entity.TryConsumeEnergy(_input * Item.Evaluate(_data.EnergyUsage)))
_data = data;
Torque = 0;
Thrust = Evaluate(_data.Thrust);
}
public override bool Execute(float dt)
{
if(_input > .01f && Entity.TryConsumeEnergy(_input * Evaluate(_data.EnergyUsage)))
{
Thrust = Item.Evaluate(_data.Thrust);
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 * 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;
Thrust = Evaluate(_data.Thrust);
Entity.Velocity -= Direction.xz * _input * Thrust / Entity.Mass * dt;
Entity.Direction = mul(Entity.Direction,
Unity.Mathematics.float2x2.Rotate(_input * Torque * Thrust * ItemManager.GameplaySettings.TorqueMultiplier / Entity.Mass * dt));
AddHeat(_input * Evaluate(_data.Heat) * dt);
var vis = _input * Evaluate(_data.Visibility);
if (!Entity.VisibilitySources.ContainsKey(this) || vis > Entity.VisibilitySources[this])
Entity.VisibilitySources[this] = vis;
return true;
}
return false;

View file

@ -10,29 +10,24 @@ using Newtonsoft.Json;
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-20)]
public class TriggerData : BehaviorData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Trigger(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Trigger(this, item);
}
}
public class Trigger : IBehavior, IActivatedBehavior
public class Trigger : Behavior, IActivatedBehavior
{
private TriggerData _data;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public bool _pulled;
public Trigger(TriggerData data, EquippedItem item)
{
_data = data;
Item = item;
}
public Trigger(TriggerData data, EquippedItem item) : base(data, item) { }
public Trigger(TriggerData data, ConsumableItemEffect item) : base(data, item) { }
public bool Execute(float dt)
public override bool Execute(float dt)
{
if (_pulled)
{

View file

@ -14,84 +14,74 @@ using float3 = Unity.Mathematics.float3;
[MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
public class TurretControllerData : BehaviorData
{
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new TurretController(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new TurretController(this, item);
}
}
public class TurretController : IBehavior
public class TurretController : Behavior, IInitializableBehavior
{
private TurretControllerData _data;
private List<Weapon> _weapons = new List<Weapon>();
private float _shotSpeed;
private bool _predictShots;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public TurretController(TurretControllerData data, EquippedItem item)
public TurretController(TurretControllerData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
var weapons = Item.Entity.Equipment.Where(e => e.Behaviors.Any(b => b.Data is WeaponData));
foreach (var weapon in weapons)
{
CheckWeapon(weapon);
}
Item.Entity.Equipment.ObserveAdd().Subscribe(add => CheckWeapon(add.Value));
Item.Entity.Equipment.ObserveRemove().Subscribe(remove =>
{
foreach (var b in remove.Value.Behaviors)
if (b is Weapon weapon)
_weapons.Remove(weapon);
});
}
private void CheckWeapon(EquippedItem item)
public TurretController(TurretControllerData data, ConsumableItemEffect item) : base(data, item)
{
foreach (var b in item.Behaviors)
if (b is Weapon weapon)
_data = data;
}
public void Initialize()
{
foreach (var weapon in Entity.GetBehaviors<Weapon>())
{
_weapons.Add(weapon);
var vel = weapon.Evaluate(weapon.WeaponData.Velocity);
if (vel > .1f)
{
_weapons.Add(weapon);
var vel = weapon.Item.Evaluate(weapon.WeaponData.Velocity);
if (vel > .1f)
{
_predictShots = true;
_shotSpeed = vel;
}
_predictShots = true;
_shotSpeed = vel;
}
}
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
if (Item.Entity.Target.Value != null)
if (Entity.Target.Value != null)
{
var diff = Item.Entity.Target.Value.Position - Item.Entity.Position;
var diff = Entity.Target.Value.Position - Entity.Position;
if (_predictShots)
{
var targetHullData = Item.Entity.ItemManager.GetData(Item.Entity.Target.Value.Hull) as HullData;
var targetVelocity = float3(Item.Entity.Target.Value.Velocity.x, 0, Item.Entity.Target.Value.Velocity.y);
var targetHullData = Entity.ItemManager.GetData(Entity.Target.Value.Hull) as HullData;
var targetVelocity = float3(Entity.Target.Value.Velocity.x, 0, Entity.Target.Value.Velocity.y);
var predictedPosition = AetheriaMath.FirstOrderIntercept(
Item.Entity.Position, float3.zero, _shotSpeed,
Item.Entity.Target.Value.Position, targetVelocity
Entity.Position, float3.zero, _shotSpeed,
Entity.Target.Value.Position, targetVelocity
);
predictedPosition.y = Item.Entity.Zone.GetHeight(predictedPosition.xz) + targetHullData.GridOffset;
Item.Entity.LookDirection = normalize(predictedPosition - Item.Entity.Position);
predictedPosition.y = Entity.Zone.GetHeight(predictedPosition.xz) + targetHullData.GridOffset;
Entity.LookDirection = normalize(predictedPosition - Entity.Position);
}
else
Item.Entity.LookDirection = normalize(diff);
Entity.LookDirection = normalize(diff);
var dist = length(diff);
foreach (var x in _weapons)
{
var data = x.Data as WeaponData;
var fire = dot(
Item.Entity.HardpointTransforms[Item.Entity.Hardpoints[x.Item.Position.x, x.Item.Position.y]].direction,
Item.Entity.LookDirection) > .99f;
if (x.Item.Evaluate(data.Range) > dist && fire)
x.Direction,
Entity.LookDirection) > .99f;
if (x.Evaluate(data.Range) > dist && fire)
{
x.Activate();
}
@ -106,7 +96,7 @@ public class TurretController : IBehavior
if (x.Firing)
x.Deactivate();
}
Item.Entity.Target.Value = Item.Entity.VisibleHostiles.FirstOrDefault(e => e is Ship);
Entity.Target.Value = Entity.VisibleHostiles.FirstOrDefault(e => e is Ship);
}
return true;
}

View file

@ -10,31 +10,35 @@ using static Unity.Mathematics.math;
[MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
public class VelocityConversionData : BehaviorData
{
[Inspectable, JsonProperty("traction"), Key(1), RuntimeInspectable]
public PerformanceStat Traction = new PerformanceStat();
[Inspectable, JsonProperty("lambda"), Key(1), RuntimeInspectable]
public PerformanceStat Lambda = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new VelocityConversion(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new VelocityConversion(this, item);
}
}
public class VelocityConversion : IBehavior
public class VelocityConversion : Behavior
{
public EquippedItem Item { get; }
public BehaviorData Data => _data;
private VelocityConversionData _data;
public VelocityConversion(VelocityConversionData data, EquippedItem item)
public VelocityConversion(VelocityConversionData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public VelocityConversion(VelocityConversionData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
Entity.Velocity = AetheriaMath.Damp(Entity.Velocity, Entity.Direction * length(Entity.Velocity), Evaluate(_data.Lambda), dt);
return true;
}
}

View file

@ -13,35 +13,40 @@ public class VelocityLimitData : BehaviorData
[Inspectable, JsonProperty("topSpeed"), Key(1), RuntimeInspectable]
public PerformanceStat TopSpeed = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new VelocityLimit(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new VelocityLimit(this, item);
}
}
[Order(100)]
public class VelocityLimit : IBehavior
public class VelocityLimit : Behavior
{
public EquippedItem Item { get; }
public float Limit { get; private set; }
public BehaviorData Data => _data;
private VelocityLimitData _data;
public VelocityLimit(VelocityLimitData data, EquippedItem item)
public VelocityLimit(VelocityLimitData data, EquippedItem item) : base(data, item)
{
_data = data;
Item = item;
Limit = Item.Evaluate(_data.TopSpeed);
Limit = Evaluate(_data.TopSpeed);
}
public bool Execute(float dt)
public VelocityLimit(VelocityLimitData data, ConsumableItemEffect item) : base(data, item)
{
Limit = Item.Evaluate(_data.TopSpeed);
if (length(Item.Entity.Velocity) > Limit)
Item.Entity.Velocity = normalize(Item.Entity.Velocity) * Limit;
_data = data;
Limit = Evaluate(_data.TopSpeed);
}
public override bool Execute(float dt)
{
Limit = Evaluate(_data.TopSpeed);
if (length(Entity.Velocity) > Limit)
Entity.Velocity = normalize(Entity.Velocity) * Limit;
return true;
}
}

View file

@ -16,31 +16,32 @@ public class VisibilityData : BehaviorData
[Inspectable, JsonProperty("visibilityDecay"), Key(2)]
public PerformanceStat VisibilityDecay = new PerformanceStat();
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Visibility(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Visibility(this, item);
}
}
public class Visibility : IBehavior
public class Visibility : Behavior
{
private VisibilityData _data;
private EquippedItem Item { get; }
public BehaviorData Data => _data;
private float _cooldown; // Normalized
public Visibility(VisibilityData data, EquippedItem item)
public Visibility(VisibilityData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Visibility(VisibilityData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
Item.Entity.VisibilitySources[this] = Item.Evaluate(_data.Visibility);
Entity.VisibilitySources[this] = Evaluate(_data.Visibility);
return true;
}
}

View file

@ -67,17 +67,14 @@ public abstract class WeaponData : BehaviorData
public PerformanceStat Velocity = new PerformanceStat();
}
public abstract class Weapon : IActivatedBehavior
public abstract class Weapon : Behavior, IActivatedBehavior
{
private WeaponData _data;
public EquippedItem Item { get; }
public abstract float DamagePerSecond { get; }
public abstract float RangeDamagePerSecond(float range);
public abstract int Ammo { get; }
public WeaponData WeaponData => _data;
public BehaviorData Data => _data;
public float Damage { get; protected set; }
public float Penetration { get; protected set; }
@ -96,29 +93,32 @@ public abstract class Weapon : IActivatedBehavior
{
get => _firing;
}
public Weapon(WeaponData data, EquippedItem item)
public Weapon(WeaponData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Weapon(WeaponData data, ConsumableItemEffect item) : base(data, item)
{
Item = item;
_data = data;
}
protected virtual void UpdateStats()
{
Damage = Item.Evaluate(_data.Damage);
Penetration = Item.Evaluate(_data.Penetration);
DamageSpread = Item.Evaluate(_data.DamageSpread);
MinRange = Item.Evaluate(_data.MinRange);
Range = Item.Evaluate(_data.Range);
Energy = Item.Evaluate(_data.Energy);
Heat = Item.Evaluate(_data.Heat);
Visibility = Item.Evaluate(_data.Visibility);
Spread = Item.Evaluate(_data.Spread);
Velocity = Item.Evaluate(_data.Velocity);
Damage = Evaluate(_data.Damage);
Penetration = Evaluate(_data.Penetration);
DamageSpread = Evaluate(_data.DamageSpread);
MinRange = Evaluate(_data.MinRange);
Range = Evaluate(_data.Range);
Energy = Evaluate(_data.Energy);
Heat = Evaluate(_data.Heat);
Visibility = Evaluate(_data.Visibility);
Spread = Evaluate(_data.Spread);
Velocity = Evaluate(_data.Velocity);
}
public virtual bool Execute(float dt)
public override bool Execute(float dt)
{
UpdateStats();
return true;

View file

@ -14,39 +14,32 @@ public class WearData : BehaviorData
[InspectableTemperature, JsonProperty("perSecond"), Key(1)]
public bool PerSecond = true;
public override IBehavior CreateInstance(EquippedItem item)
public override Behavior CreateInstance(EquippedItem item)
{
return new Wear(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Wear(this, item);
}
}
public class Wear : IBehavior
public class Wear : Behavior
{
private WearData _data;
public EquippedItem Item { get; }
public BehaviorData Data => _data;
public Wear(WearData data, EquippedItem item)
public Wear(WearData data, EquippedItem item) : base(data, item)
{
_data = data;
}
public Wear(WearData data, ConsumableItemEffect item) : base(data, item)
{
_data = data;
Item = item;
}
public bool Execute(float dt)
public override bool Execute(float dt)
{
if (_data.PerSecond)
{
var dmg = Item.Wear * dt;
Item.EquippableItem.Durability -= dmg;
Item.Entity.ItemDamage.OnNext((Item, dmg));
}
else
{
Item.EquippableItem.Durability -= Item.Wear;
Item.Entity.ItemDamage.OnNext((Item, Item.Wear));
}
CauseWearDamage(_data.PerSecond ? dt : 1);
return true;
}
}

View file

@ -103,7 +103,7 @@ public static class ReflectionExtensions
public static string FormatTypeName(this string typeName)
{
return (typeName.EndsWith("Data")
return (typeName.EndsWith("Data", StringComparison.InvariantCultureIgnoreCase)
? typeName.Substring(0, typeName.Length - 4)
: typeName).SplitCamelCase();
}

View file

@ -15,6 +15,7 @@ public abstract class Entity
public Zone Zone;
public Faction Faction;
public EquippableItem Hull;
public EquippedItem EquippedHull;
public float3 Position;
public float2 Direction = float2(0,1);
@ -62,6 +63,9 @@ public abstract class Entity
private List<Capacitor> _capacitors = new List<Capacitor>();
private List<Reactor> _reactors = new List<Reactor>();
private List<Radiator> _heatsinks = new List<Radiator>();
private List<ConsumableItemEffect> _activeConsumables = new List<ConsumableItemEffect>();
protected bool _active;
private bool _heatsinksEnabled = true;
@ -208,6 +212,34 @@ public abstract class Entity
EntityInfoGathered.ObserveRemove().Subscribe(remove => VisibleEntities.Remove(remove.Key));
}
public void ActivateConsumable(ConsumableItem item)
{
_activeConsumables.Add(new ConsumableItemEffect(item, this));
}
public ConsumableItemEffect FindActiveConsumable(ConsumableItemData data)
{
return _activeConsumables.FirstOrDefault(ac => ac.Data.ID == data.ID);
}
public bool CanActivateConsumable(ConsumableItemData data)
{
return data.Stackable || FindActiveConsumable(data) == null;
}
public bool TryActivateConsumable(ConsumableItemData data)
{
if (!CanActivateConsumable(data)) return false;
var bay = FindItemInCargo(data.ID);
if (bay == null) return false;
var item = (ConsumableItem) bay.ItemsOfType[data.ID].First();
ActivateConsumable(item);
bay.Remove(item);
return true;
}
public bool IsHostileTo(Entity other)
{
if (Faction == null)
@ -221,7 +253,8 @@ public abstract class Entity
private void MapEntity()
{
var hullData = ItemManager.GetData(Hull) as HullData;
Equipment.Add(new EquippedItem(ItemManager, Hull, int2.zero, this));
EquippedHull = new EquippedItem(ItemManager, Hull, int2.zero, this);
Equipment.Add(EquippedHull);
Mass = hullData.Mass;
Temperature = new float[hullData.Shape.Width, hullData.Shape.Height];
NewTemperature = new float[hullData.Shape.Width, hullData.Shape.Height];
@ -257,7 +290,8 @@ public abstract class Entity
public void GenerateTriggerGroups()
{
foreach (var group in Weapons
.GroupBy(w => w.Item.EquippableItem.Data)
.GroupBy(w => w.Item.EquippableItem.Data.LinkID)
.OrderBy(wg=>wg.Average(w=>w.Range))
.Select((weapons, index) => (weapons, index)))
{
TriggerGroups[group.index].weapons = group.weapons.ToList();
@ -695,7 +729,7 @@ public abstract class Entity
Parent = null;
}
public T GetBehavior<T>() where T : class, IBehavior
public T GetBehavior<T>() where T : Behavior
{
foreach (var equippedItem in Equipment)
if(equippedItem.Behaviors != null)
@ -705,7 +739,7 @@ public abstract class Entity
return null;
}
public IEnumerable<T> GetBehaviors<T>() where T : class, IBehavior
public IEnumerable<T> GetBehaviors<T>() where T : Behavior
{
foreach (var equippedItem in Equipment)
if(equippedItem.Behaviors != null)
@ -779,12 +813,13 @@ public abstract class Entity
{
if(Cockpit != null)
{
if (Cockpit.Item.Temperature > ItemManager.GameplaySettings.HeatstrokeTemperature)
var cockpitTemp = Cockpit.Temperature;
if (cockpitTemp > ItemManager.GameplaySettings.HeatstrokeTemperature)
{
var previous = Heatstroke;
Heatstroke = saturate(
Heatstroke +
pow(Cockpit.Item.Temperature - ItemManager.GameplaySettings.HeatstrokeTemperature, ItemManager.GameplaySettings.HeatstrokeExponent) *
pow(cockpitTemp - ItemManager.GameplaySettings.HeatstrokeTemperature, ItemManager.GameplaySettings.HeatstrokeExponent) *
ItemManager.GameplaySettings.HeatstrokeMultiplier * delta);
if(previous < ItemManager.GameplaySettings.SevereHeatstrokeRiskThreshold && Heatstroke > ItemManager.GameplaySettings.SevereHeatstrokeRiskThreshold)
HeatstrokeRisk.OnNext(Unit.Default);
@ -798,12 +833,13 @@ public abstract class Entity
{
Heatstroke = saturate(Heatstroke - ItemManager.GameplaySettings.HeatstrokeRecoverySpeed * delta);
}
if (Cockpit.Item.Temperature < ItemManager.GameplaySettings.HypothermiaTemperature)
if (cockpitTemp < ItemManager.GameplaySettings.HypothermiaTemperature)
{
var previous = Hypothermia;
Hypothermia = saturate(
Hypothermia +
pow(ItemManager.GameplaySettings.HypothermiaTemperature - Cockpit.Item.Temperature, ItemManager.GameplaySettings.HypothermiaExponent) *
pow(ItemManager.GameplaySettings.HypothermiaTemperature - cockpitTemp, ItemManager.GameplaySettings.HypothermiaExponent) *
ItemManager.GameplaySettings.HypothermiaMultiplier * delta);
if(previous < ItemManager.GameplaySettings.SevereHeatstrokeRiskThreshold && Heatstroke > ItemManager.GameplaySettings.SevereHeatstrokeRiskThreshold)
HypothermiaRisk.OnNext(Unit.Default);
@ -818,7 +854,13 @@ public abstract class Entity
Hypothermia = saturate(Hypothermia - ItemManager.GameplaySettings.HypothermiaRecoverySpeed * delta);
}
}
for (var i = 0; i < _activeConsumables.Count; i++)
{
_activeConsumables[i].Update(delta);
if(_activeConsumables[i].RemainingDuration < 0) _activeConsumables.RemoveAt(i--);
}
foreach (var equippedItem in _orderedEquipment)
{
equippedItem.Update(delta);
@ -935,17 +977,64 @@ public abstract class Entity
}
}
public class ConsumableItemEffect
{
public float RemainingDuration { get; private set; }
public Entity Entity { get; }
public ConsumableItem Item { get; }
public ConsumableItemData Data { get; }
public Behavior[] Behaviors { get; }
public ConsumableItemEffect(ConsumableItem item, Entity entity)
{
Item = item;
Entity = entity;
Data = (ConsumableItemData) item.Data.Value;
RemainingDuration = Data.Duration;
Behaviors = Data.StatModifiers
.Select(bd => bd.CreateInstance(this))
.ToArray();
}
public void Update(float delta)
{
foreach (var behavior in Behaviors)
if(behavior is IAlwaysUpdatedBehavior alwaysUpdatedBehavior) alwaysUpdatedBehavior.Update(delta);
foreach (var behavior in Behaviors)
{
if (!behavior.Execute(delta))
break;
}
RemainingDuration -= delta;
}
public float Evaluate(PerformanceStat stat)
{
var effectiveness = Data.Effectiveness.Evaluate((Data.Duration - RemainingDuration) / Data.Duration);
var quality = pow(Item.Quality, stat.QualityExponent);
var result = lerp(stat.Min, stat.Max, effectiveness * quality);
if (float.IsNaN(result))
return stat.Min;
return result;
}
}
public class EquippedItem
{
public int SortPosition;
public EquippableItem EquippableItem;
public int2 Position;
public Dictionary<int, BehaviorGroup> BehaviorGroups;
private bool _thermalOnline;
private bool _durabilityOnline;
public IBehavior[] Behaviors { get; }
public Behavior[] Behaviors { get; }
public Dictionary<int, BehaviorGroup> BehaviorGroups { get; }
public float Conductivity { get; }
public float ThermalPerformance { get; private set; }
public float ThermalExponent { get; }
@ -1077,7 +1166,7 @@ public class EquippedItem
}
}
public T GetBehavior<T>() where T : class, IBehavior
public T GetBehavior<T>() where T : Behavior
{
foreach (var behavior in Behaviors)
if (behavior is T b)
@ -1125,7 +1214,7 @@ public class EquippedCargoBay : EquippedItem
// Check whether the given item will fit when its origin is placed at the given coordinate
public bool ItemFits(ItemInstance item, int2 cargoCoord)
{
var itemData = ItemManager.GetData(item);
var itemData = item.Data.Value;
// Check every cell of the item's shape
foreach (var i in itemData.Shape.Coordinates)
{
@ -1249,9 +1338,9 @@ public class EquippedCargoBay : EquippedItem
}
Cargo[item] = cargoCoord;
if(!ItemsOfType.ContainsKey(item.Data))
ItemsOfType[item.Data] = new List<ItemInstance>();
ItemsOfType[item.Data].Add(item);
if(!ItemsOfType.ContainsKey(item.Data.LinkID))
ItemsOfType[item.Data.LinkID] = new List<ItemInstance>();
ItemsOfType[item.Data.LinkID].Add(item);
}
else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data == item.Data)
{
@ -1293,9 +1382,9 @@ public class EquippedCargoBay : EquippedItem
}
Cargo[item] = cargoCoord;
if(!ItemsOfType.ContainsKey(item.Data))
ItemsOfType[item.Data] = new List<ItemInstance>();
ItemsOfType[item.Data].Add(item);
if(!ItemsOfType.ContainsKey(item.Data.LinkID))
ItemsOfType[item.Data.LinkID] = new List<ItemInstance>();
ItemsOfType[item.Data.LinkID].Add(item);
Mass += ItemManager.GetMass(item);
ThermalMass += ItemManager.GetThermalMass(item);
@ -1318,9 +1407,9 @@ public class EquippedCargoBay : EquippedItem
Occupancy[v.x, v.y] = null;
Cargo.Remove(item);
ItemsOfType[item.Data].Remove(item);
if (!ItemsOfType[item.Data].Any())
ItemsOfType.Remove(item.Data);
ItemsOfType[item.Data.LinkID].Remove(item);
if (!ItemsOfType[item.Data.LinkID].Any())
ItemsOfType.Remove(item.Data.LinkID);
Mass -= ItemManager.GetMass(item);
ThermalMass -= ItemManager.GetThermalMass(item);
@ -1347,9 +1436,9 @@ public class EquippedCargoBay : EquippedItem
Occupancy[v.x, v.y] = null;
Cargo.Remove(item);
ItemsOfType[item.Data].Remove(item);
if (!ItemsOfType[item.Data].Any())
ItemsOfType.Remove(item.Data);
ItemsOfType[item.Data.LinkID].Remove(item);
if (!ItemsOfType[item.Data.LinkID].Any())
ItemsOfType.Remove(item.Data.LinkID);
Mass -= ItemManager.GetMass(item);
ThermalMass -= ItemManager.GetThermalMass(item);
@ -1408,9 +1497,9 @@ public class EquippedDockingBay : EquippedCargoBay
public class BehaviorGroup
{
public IBehavior[] Behaviors;
public Behavior[] Behaviors;
public T GetBehavior<T>() where T : class, IBehavior
public T GetBehavior<T>() where T : Behavior
{
foreach (var b in Behaviors)
{
@ -1421,7 +1510,7 @@ public class BehaviorGroup
return null;
}
public T GetExposed<T>() where T : class, IBehavior, IInteractiveBehavior
public T GetExposed<T>() where T : Behavior, IInteractiveBehavior
{
foreach (var b in Behaviors)
{

View file

@ -230,7 +230,7 @@ public abstract class EntityPack
{
foreach (var (_, item) in t)
{
var itemData = itemManager.GetData(item);
var itemData = item.Data.Value;
if (item is SimpleCommodity s)
_price += itemData.Price * s.Quantity;
else
@ -242,7 +242,7 @@ public abstract class EntityPack
{
foreach (var (_, item) in t)
{
var itemData = itemManager.GetData(item);
var itemData = item.Data.Value;
if (item is SimpleCommodity s)
_price += itemData.Price * s.Quantity;
else

View file

@ -284,8 +284,8 @@ public class SimpleCommodityData : ItemData
[MessagePackObject, JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<CraftedItemData>))]
public abstract class CraftedItemData : ItemData
{
[Inspectable, JsonProperty("ingredientQualityWeight"), Key(9)]
public float IngredientQualityWeight = .5f;
// [Inspectable, JsonProperty("ingredientQualityWeight"), Key(9)]
// public float IngredientQualityWeight = .5f;
}
[RethinkTable("Items"), Inspectable, MessagePackObject]
@ -298,7 +298,26 @@ public class CompoundCommodityData : CraftedItemData
public CompoundCommodityCategory Category;
}
[JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<EquippableItemData>))]
[RethinkTable("Items"), Inspectable, MessagePackObject]
public class ConsumableItemData : CraftedItemData
{
[Inspectable, JsonProperty("behaviors"), Key(10)]
public List<StatModifierData> StatModifiers = new List<StatModifierData>();
[Inspectable, JsonProperty("stackable"), Key(11)]
public bool Stackable;
[Inspectable, JsonProperty("duration"), Key(12)]
public float Duration;
[InspectableTexture, JsonProperty("icon"), Key(13)]
public string Icon;
[Inspectable, JsonProperty("effectiveness"), Key(14)]
public BezierCurve Effectiveness;
}
[JsonObject(MemberSerialization.OptIn)]
public abstract class EquippableItemData : CraftedItemData
{
[InspectableTexture, JsonProperty("schematic"), Key(10)]
@ -331,6 +350,9 @@ public abstract class EquippableItemData : CraftedItemData
[Inspectable, JsonProperty("sfx"), Key(19)]
public string SoundEffectTrigger;
[InspectableTexture, JsonProperty("actionIcon"), Key(20)]
public string ActionBarIcon;
[IgnoreMember]
public abstract HardpointType HardpointType { get; }
@ -372,7 +394,7 @@ public abstract class EquippableItemData : CraftedItemData
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class GearData : EquippableItemData
{
[Inspectable, JsonProperty("hardpointType"), Key(20)]
[Inspectable, JsonProperty("hardpointType"), Key(21)]
public HardpointType Hardpoint;
[IgnoreMember] public override HardpointType HardpointType => Hardpoint;
@ -381,7 +403,7 @@ public class GearData : EquippableItemData
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class CargoBayData : EquippableItemData
{
[Inspectable, JsonProperty("interiorShape"), Key(20)]
[Inspectable, JsonProperty("interiorShape"), Key(21)]
public Shape InteriorShape;
[IgnoreMember] public override HardpointType HardpointType => HardpointType.Tool;
}
@ -389,48 +411,48 @@ public class CargoBayData : EquippableItemData
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class DockingBayData : CargoBayData
{
[Inspectable, JsonProperty("maxSize"), Key(21)]
[Inspectable, JsonProperty("maxSize"), Key(22)]
public int2 MaxSize;
}
[RethinkTable("Items"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class WeaponItemData : GearData
{
[Inspectable, JsonProperty("range"), Key(21)]
[Inspectable, JsonProperty("range"), Key(22)]
public WeaponRange WeaponRange;
[Inspectable, JsonProperty("caliber"), Key(22)]
[Inspectable, JsonProperty("caliber"), Key(23)]
public WeaponCaliber WeaponCaliber;
[Inspectable, JsonProperty("weaponType"), Key(23)]
[Inspectable, JsonProperty("weaponType"), Key(24)]
public WeaponType WeaponType;
[Inspectable, JsonProperty("fireTypes"), Key(24)]
[Inspectable, JsonProperty("fireTypes"), Key(25)]
public WeaponFireType WeaponFireTypes;
[Inspectable, JsonProperty("modifiers"), Key(25)]
[Inspectable, JsonProperty("modifiers"), Key(26)]
public WeaponModifiers WeaponModifiers;
}
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class HullData : EquippableItemData
{
[Inspectable, JsonProperty("hardpoints"), Key(20)]
[Inspectable, JsonProperty("hardpoints"), Key(21)]
public List<HardpointData> Hardpoints = new List<HardpointData>();
[InspectablePrefab, JsonProperty("prefab"), Key(21)]
[InspectablePrefab, JsonProperty("prefab"), Key(22)]
public string Prefab;
[Inspectable, JsonProperty("hullType"), Key(22)]
[Inspectable, JsonProperty("hullType"), Key(23)]
public HullType HullType;
[Inspectable, JsonProperty("gridOffset"), Key(23)]
[Inspectable, JsonProperty("gridOffset"), Key(24)]
public float GridOffset;
[Inspectable, JsonProperty("armor"), Key(24)]
[Inspectable, JsonProperty("armor"), Key(25)]
public float Armor;
[Inspectable, JsonProperty("drag"), Key(25)]
[Inspectable, JsonProperty("drag"), Key(26)]
public float Drag;
[IgnoreMember]
@ -511,29 +533,29 @@ public class PerformanceStat
// [JsonProperty("ingredient"), Key(5)] public Guid? Ingredient;
[IgnoreMember] private Dictionary<Entity,Dictionary<IBehavior,float>> _scaleModifiers;
[IgnoreMember] private Dictionary<Entity,Dictionary<IBehavior,float>> _constantModifiers;
[IgnoreMember] private Dictionary<Entity,Dictionary<Behavior,float>> _scaleModifiers;
[IgnoreMember] private Dictionary<Entity,Dictionary<Behavior,float>> _constantModifiers;
[IgnoreMember]
private Dictionary<Entity, Dictionary<IBehavior, float>> ScaleModifiers =>
_scaleModifiers = _scaleModifiers ?? new Dictionary<Entity, Dictionary<IBehavior, float>>();
private Dictionary<Entity, Dictionary<Behavior, float>> ScaleModifiers =>
_scaleModifiers = _scaleModifiers ?? new Dictionary<Entity, Dictionary<Behavior, float>>();
[IgnoreMember]
private Dictionary<Entity, Dictionary<IBehavior, float>> ConstantModifiers =>
_constantModifiers = _constantModifiers ?? new Dictionary<Entity, Dictionary<IBehavior, float>>();
private Dictionary<Entity, Dictionary<Behavior, float>> ConstantModifiers =>
_constantModifiers = _constantModifiers ?? new Dictionary<Entity, Dictionary<Behavior, float>>();
public Dictionary<IBehavior, float> GetScaleModifiers(Entity entity)
public Dictionary<Behavior, float> GetScaleModifiers(Entity entity)
{
if(!ScaleModifiers.ContainsKey(entity))
ScaleModifiers[entity] = new Dictionary<IBehavior, float>();
ScaleModifiers[entity] = new Dictionary<Behavior, float>();
return ScaleModifiers[entity];
}
public Dictionary<IBehavior, float> GetConstantModifiers(Entity entity)
public Dictionary<Behavior, float> GetConstantModifiers(Entity entity)
{
if(!ConstantModifiers.ContainsKey(entity))
ConstantModifiers[entity] = new Dictionary<IBehavior, float>();
ConstantModifiers[entity] = new Dictionary<Behavior, float>();
return ConstantModifiers[entity];
}

View file

@ -18,16 +18,18 @@ using static Unity.Mathematics.math;
[Union(0, typeof(SimpleCommodity)),
Union(1, typeof(CompoundCommodity)),
Union(2, typeof(EquippableItem)),
Union(3, typeof(ConsumableItem)),
JsonObject(MemberSerialization.OptIn),
JsonConverter(typeof(JsonKnownTypesConverter<ItemInstance>))]
public abstract class ItemInstance
{
[JsonProperty("data"), Key(0)] public Guid Data;
[JsonProperty("data"), Key(0)] public DatabaseLink<ItemData> Data;
[JsonProperty("rotation"), Key(1)] public ItemRotation Rotation;
}
[Union(0, typeof(CompoundCommodity)),
Union(1, typeof(EquippableItem)),
Union(2, typeof(ConsumableItem)),
JsonObject(MemberSerialization.OptIn),
JsonConverter(typeof(JsonKnownTypesConverter<CraftedItemInstance>))]
public abstract class CraftedItemInstance : ItemInstance
@ -57,4 +59,9 @@ public class EquippableItem : CraftedItemInstance
{
[JsonProperty("durability"), Key(7)] public float Durability;
[JsonProperty("override"), Key(8)] public bool OverrideShutdown;
}
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class ConsumableItem : CraftedItemInstance
{
}

View file

@ -107,52 +107,40 @@ public class ItemManager
// return Tier[itemData];
// }
public ItemData GetData(ItemInstance item)
{
return ItemData.Get<ItemData>(item.Data);
}
public SimpleCommodityData GetData(SimpleCommodity item)
{
return ItemData.Get<SimpleCommodityData>(item.Data);
return item.Data.Value as SimpleCommodityData;
}
public CraftedItemData GetData(CraftedItemInstance item)
{
return ItemData.Get<CraftedItemData>(item.Data);
return item.Data.Value as CraftedItemData;
}
public EquippableItemData GetData(EquippableItem equippableItem)
public EquippableItemData GetData(EquippableItem item)
{
return ItemData.Get<EquippableItemData>(equippableItem.Data);
return item.Data.Value as EquippableItemData;
}
public float GetMass(ItemInstance item)
{
var data = GetData(item);
switch (item)
return item switch
{
case CraftedItemInstance _:
return data.Mass;
case SimpleCommodity commodity:
return data.Mass * commodity.Quantity;
}
return 0;
CraftedItemInstance _ => item.Data.Value.Mass,
SimpleCommodity commodity => item.Data.Value.Mass * commodity.Quantity,
_ => 0
};
}
public float GetThermalMass(ItemInstance item)
{
var data = GetData(item);
switch (item)
var data = item.Data.Value;
return item switch
{
case CraftedItemInstance _:
return data.Mass * data.SpecificHeat;
case SimpleCommodity commodity:
return data.Mass * data.SpecificHeat * commodity.Quantity;
}
return 0;
CraftedItemInstance _ => data.Mass * data.SpecificHeat,
SimpleCommodity commodity => data.Mass * data.SpecificHeat * commodity.Quantity,
_ => 0
};
}
// Returns stat when not equipped
@ -184,7 +172,7 @@ public class ItemManager
{
var newItem = new SimpleCommodity
{
Data = item.ID,
Data = new DatabaseLink<ItemData>{LinkID = item.ID},
Quantity = count
};
//ItemData.Add(newItem);
@ -197,7 +185,7 @@ public class ItemManager
public ItemInstance Instantiate(ItemInstance item)
{
var data = GetData(item);
var data = item.Data.Value;
if(data is CraftedItemData c)
{
var i = CreateInstance(c);
@ -217,18 +205,15 @@ public class ItemManager
{
if (item is EquippableItemData equippableItemData)
{
var newGear = new EquippableItem
return new EquippableItem
{
Data = item.ID,
Quality = quality
Data = new DatabaseLink<ItemData> {LinkID = item.ID}, Quality = quality, Durability = equippableItemData.Durability
};
newGear.Durability = equippableItemData.Durability;
return newGear;
}
var newCommodity = new CompoundCommodity
{
Data = item.ID,
Data = new DatabaseLink<ItemData>{LinkID = item.ID},
Quality = quality
};
return newCommodity;

View file

@ -37,6 +37,9 @@ public class SavedGame
[Key(9)]
public int[] DiscoveredZones;
[Key(10)]
public SavedActionBarBinding[] ActionBarBindings;
public SavedGame() { }
@ -91,4 +94,32 @@ public class SavedZone
[Key(5)]
public ZonePack Contents;
}
[MessagePackObject,
Union(0, typeof(SavedActionBarConsumableBinding)),
Union(1, typeof(SavedActionBarGearBinding)),
Union(2, typeof(SavedActionBarWeaponGroupBinding))
]
public abstract class SavedActionBarBinding
{
}
[MessagePackObject]
public class SavedActionBarConsumableBinding : SavedActionBarBinding
{
[Key(0)] public DatabaseLink<ConsumableItemData> Target;
}
[MessagePackObject]
public class SavedActionBarGearBinding : SavedActionBarBinding
{
[Key(0)] public int EquipmentIndex;
[Key(1)] public int BehaviorIndex;
}
[MessagePackObject]
public class SavedActionBarWeaponGroupBinding : SavedActionBarBinding
{
[Key(0)] public int Group;
}