2020-12-22 03:13:43 +00:00
|
|
|
/* 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/. */
|
|
|
|
|
|
2020-04-09 10:33:16 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
2020-04-29 23:36:00 +01:00
|
|
|
using JsonKnownTypes;
|
|
|
|
|
using MessagePack;
|
|
|
|
|
using Newtonsoft.Json;
|
2020-12-10 23:20:38 +00:00
|
|
|
using UniRx;
|
2020-04-09 10:33:16 +01:00
|
|
|
using Unity.Mathematics;
|
|
|
|
|
using static Unity.Mathematics.math;
|
2020-12-10 23:20:38 +00:00
|
|
|
using int2 = Unity.Mathematics.int2;
|
2020-04-09 10:33:16 +01:00
|
|
|
|
2020-04-29 23:36:00 +01:00
|
|
|
[MessagePackObject,
|
2020-05-04 00:07:36 +01:00
|
|
|
Union(0, typeof(Ship)),
|
|
|
|
|
Union(1, typeof(OrbitalEntity)),
|
2020-04-29 23:36:00 +01:00
|
|
|
JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<Entity>))]
|
2020-12-10 23:20:38 +00:00
|
|
|
public abstract class Entity
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
public Zone Zone;
|
2021-02-11 03:14:20 +00:00
|
|
|
public MegaCorporation Faction;
|
2020-12-10 23:20:38 +00:00
|
|
|
public EquippableItem Hull;
|
2020-06-01 03:11:04 +01:00
|
|
|
|
2021-01-06 14:56:39 +00:00
|
|
|
public float3 Position;
|
2020-06-01 03:11:04 +01:00
|
|
|
public float2 Direction = float2(0,1);
|
|
|
|
|
public float2 Velocity;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public float[,] Temperature;
|
2021-01-17 23:26:53 +00:00
|
|
|
public float[,] NewTemperature;
|
2021-01-17 02:45:52 +00:00
|
|
|
public bool2[,] HullConductivity;
|
2020-12-27 22:18:22 +00:00
|
|
|
public float[,] ThermalMass;
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-19 02:37:13 +00:00
|
|
|
public readonly ReactiveCollection<EquippedItem> Equipment = new ReactiveCollection<EquippedItem>();
|
|
|
|
|
public readonly ReactiveCollection<EquippedCargoBay> CargoBays = new ReactiveCollection<EquippedCargoBay>();
|
|
|
|
|
public readonly ReactiveCollection<EquippedDockingBay> DockingBays = new ReactiveCollection<EquippedDockingBay>();
|
2021-02-26 19:01:47 +00:00
|
|
|
public readonly ReactiveCollection<Entity> VisibleEntities = new ReactiveCollection<Entity>();
|
|
|
|
|
public readonly ReactiveCollection<Entity> VisibleHostiles = new ReactiveCollection<Entity>();
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
public Entity Parent;
|
|
|
|
|
public List<Entity> Children = new List<Entity>();
|
2021-01-10 03:59:47 +00:00
|
|
|
public ReactiveProperty<Entity> Target = new ReactiveProperty<Entity>((Entity)null);
|
2021-01-05 02:56:17 +00:00
|
|
|
|
|
|
|
|
public float3 LookDirection;
|
2020-06-01 03:11:04 +01:00
|
|
|
|
|
|
|
|
public string Name;
|
|
|
|
|
|
|
|
|
|
public int Population;
|
|
|
|
|
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
2020-05-06 04:56:36 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public readonly Dictionary<string, float> Messages = new Dictionary<string, float>();
|
|
|
|
|
public readonly Dictionary<object, float> VisibilitySources = new Dictionary<object, float>();
|
2021-02-26 19:01:47 +00:00
|
|
|
public readonly ReactiveDictionary<Entity, float> EntityInfoGathered = new ReactiveDictionary<Entity, float>();
|
2021-01-08 12:44:10 +00:00
|
|
|
public readonly Dictionary<HardpointData, (float3 position, float3 direction)> HardpointTransforms =
|
2021-01-15 20:07:39 +00:00
|
|
|
new Dictionary<HardpointData, (float3 position, float3 direction)>();
|
2020-06-02 07:01:03 +01:00
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public readonly (List<Weapon> weapons, List<EquippedItem> items)[] TriggerGroups;
|
2020-12-31 19:53:16 +00:00
|
|
|
|
|
|
|
|
public List<IPopulationAssignment> PopulationAssignments = new List<IPopulationAssignment>();
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2020-12-12 03:42:58 +00:00
|
|
|
public EquippedItem[,] GearOccupancy;
|
|
|
|
|
public HardpointData[,] Hardpoints;
|
2021-01-08 12:44:10 +00:00
|
|
|
public float[,] Armor;
|
2021-02-01 08:13:14 +00:00
|
|
|
public float[,] MaxArmor;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
private EquippedItem[] _orderedEquipment;
|
2021-02-11 03:14:20 +00:00
|
|
|
private List<Weapon> _weapons = new List<Weapon>();
|
2021-03-02 23:02:19 +00:00
|
|
|
private List<Capacitor> _capacitors = new List<Capacitor>();
|
|
|
|
|
private List<Reactor> _reactors = new List<Reactor>();
|
2021-03-04 03:58:46 +00:00
|
|
|
private List<Radiator> _heatsinks = new List<Radiator>();
|
2021-01-05 02:56:17 +00:00
|
|
|
protected bool _active;
|
2021-03-04 03:58:46 +00:00
|
|
|
|
|
|
|
|
private bool _heatsinksEnabled = true;
|
|
|
|
|
|
|
|
|
|
public bool HeatsinksEnabled
|
|
|
|
|
{
|
|
|
|
|
get => _heatsinksEnabled;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value == _heatsinksEnabled) return;
|
|
|
|
|
_heatsinksEnabled = value;
|
|
|
|
|
foreach (var heatsink in _heatsinks)
|
|
|
|
|
heatsink.Item.Enabled = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Active
|
|
|
|
|
{
|
|
|
|
|
get => _active;
|
|
|
|
|
}
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2021-02-11 03:14:20 +00:00
|
|
|
public IEnumerable<Weapon> Weapons
|
|
|
|
|
{
|
|
|
|
|
get => _weapons;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public float TargetRange { get; private set; }
|
2021-01-27 00:05:30 +00:00
|
|
|
public float MaxTemp { get; private set; }
|
|
|
|
|
public float MinTemp { get; private set; }
|
2021-02-26 19:01:47 +00:00
|
|
|
public bool ShieldEnabled // TODO: MAKE SHIELDS
|
|
|
|
|
{
|
|
|
|
|
get => true;
|
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
public ItemManager ItemManager { get; }
|
|
|
|
|
public int AssignedPopulation => PopulationAssignments.Sum(pa => pa.AssignedPopulation);
|
|
|
|
|
public float Mass { get; private set; }
|
|
|
|
|
public float Visibility => VisibilitySources.Values.Sum();
|
|
|
|
|
|
2021-01-08 12:44:10 +00:00
|
|
|
public Subject<(int2 pos, float damage)> ArmorDamage = new Subject<(int2, float)>();
|
|
|
|
|
public Subject<(EquippedItem item, float damage)> ItemDamage = new Subject<(EquippedItem, float)>();
|
2021-03-03 01:53:23 +00:00
|
|
|
public Subject<EquippedItem> ItemOffline = new Subject<EquippedItem>();
|
|
|
|
|
public Subject<EquippedItem> ItemOnline = new Subject<EquippedItem>();
|
2021-01-08 12:44:10 +00:00
|
|
|
public Subject<float> HullDamage = new Subject<float>();
|
2021-02-26 19:01:47 +00:00
|
|
|
public Subject<Entity> Docked = new Subject<Entity>();
|
2021-01-10 03:59:47 +00:00
|
|
|
|
|
|
|
|
public UniRx.IObservable<EquippedItem> ItemDestroyed;
|
|
|
|
|
public UniRx.IObservable<int2> HullArmorDepleted;
|
|
|
|
|
public UniRx.IObservable<HardpointData> HardpointArmorDepleted;
|
2021-02-26 19:01:47 +00:00
|
|
|
public UniRx.IObservable<Weapon> WeaponDestroyed;
|
2021-01-08 12:44:10 +00:00
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
private List<IDisposable> _subscriptions = new List<IDisposable>();
|
|
|
|
|
|
|
|
|
|
public virtual void Activate()
|
2020-07-03 01:33:42 +01:00
|
|
|
{
|
2021-02-26 19:01:47 +00:00
|
|
|
_active = true;
|
|
|
|
|
foreach (var item in Equipment)
|
|
|
|
|
foreach (var behavior in item.Behaviors)
|
2020-07-03 01:33:42 +01:00
|
|
|
{
|
2021-02-26 19:01:47 +00:00
|
|
|
if(behavior is IInitializableBehavior initializableBehavior)
|
|
|
|
|
initializableBehavior.Initialize();
|
2020-07-03 01:33:42 +01:00
|
|
|
}
|
2021-02-26 19:01:47 +00:00
|
|
|
//foreach(var entity in Zone.Entities) EntityInfoGathered.Add(entity, 0);
|
|
|
|
|
_subscriptions.Add(Zone.Entities.ObserveRemove().Subscribe(remove =>
|
|
|
|
|
{
|
|
|
|
|
if (Target.Value == remove.Value) Target.Value = null;
|
|
|
|
|
EntityInfoGathered.Remove(remove.Value);
|
|
|
|
|
VisibleEntities.Remove(remove.Value);
|
|
|
|
|
VisibleHostiles.Remove(remove.Value);
|
|
|
|
|
}));
|
|
|
|
|
_subscriptions.Add(VisibleEntities.ObserveRemove().Subscribe(remove =>
|
|
|
|
|
{
|
|
|
|
|
if (Target.Value == remove.Value) Target.Value = null;
|
|
|
|
|
}));
|
|
|
|
|
GenerateTriggerGroups();
|
2020-07-03 01:33:42 +01:00
|
|
|
}
|
2020-05-25 03:05:30 +01:00
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public virtual void Deactivate()
|
|
|
|
|
{
|
|
|
|
|
foreach(var s in _subscriptions) s.Dispose();
|
|
|
|
|
_subscriptions.Clear();
|
|
|
|
|
_active = false;
|
|
|
|
|
EntityInfoGathered.Clear();
|
|
|
|
|
VisibleEntities.Clear();
|
|
|
|
|
VisibleHostiles.Clear();
|
|
|
|
|
}
|
2021-01-05 02:56:17 +00:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public Entity(ItemManager itemManager, Zone zone, EquippableItem hull)
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
ItemManager = itemManager;
|
2020-05-07 03:53:54 +01:00
|
|
|
Zone = zone;
|
2020-04-23 03:31:17 +01:00
|
|
|
Hull = hull;
|
2020-12-19 02:37:13 +00:00
|
|
|
Name = hull.Name;
|
2021-01-08 12:44:10 +00:00
|
|
|
MapEntity();
|
2021-02-26 19:01:47 +00:00
|
|
|
TriggerGroups = new (List<Weapon> triggers, List<EquippedItem> items)[itemManager.GameplaySettings.TriggerGroupCount];
|
2020-12-31 19:53:16 +00:00
|
|
|
for(int i=0; i<itemManager.GameplaySettings.TriggerGroupCount; i++)
|
2021-02-26 19:01:47 +00:00
|
|
|
TriggerGroups[i] = (new List<Weapon>(), new List<EquippedItem>());
|
2021-01-10 03:59:47 +00:00
|
|
|
|
|
|
|
|
ItemDestroyed = ItemDamage.Where(x => x.item.EquippableItem.Durability < .01f).Select(x=>x.item);
|
2021-02-26 19:01:47 +00:00
|
|
|
WeaponDestroyed = ItemDestroyed.Select(x => x.Behaviors.FirstOrDefault(b => b is Weapon) as Weapon).Where(x => x != null);
|
2021-01-10 03:59:47 +00:00
|
|
|
HullArmorDepleted = ArmorDamage.Where(x => Armor[x.pos.x, x.pos.y] < .01f).Select(x => x.pos);
|
2021-02-26 19:01:47 +00:00
|
|
|
|
|
|
|
|
EntityInfoGathered.ObserveReplace().Subscribe(replace =>
|
|
|
|
|
{
|
|
|
|
|
if (replace.OldValue < ItemManager.GameplaySettings.TargetDetectionInfoThreshold &&
|
|
|
|
|
replace.NewValue > ItemManager.GameplaySettings.TargetDetectionInfoThreshold)
|
|
|
|
|
{
|
|
|
|
|
VisibleEntities.Add(replace.Key);
|
|
|
|
|
if(IsHostileTo(replace.Key))
|
|
|
|
|
VisibleHostiles.Add(replace.Key);
|
|
|
|
|
}
|
|
|
|
|
if (replace.OldValue > ItemManager.GameplaySettings.TargetDetectionInfoThreshold &&
|
|
|
|
|
replace.NewValue < ItemManager.GameplaySettings.TargetDetectionInfoThreshold)
|
|
|
|
|
{
|
|
|
|
|
VisibleEntities.Remove(replace.Key);
|
|
|
|
|
if(IsHostileTo(replace.Key))
|
2021-02-27 20:53:36 +00:00
|
|
|
VisibleHostiles.Remove(replace.Key);
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
EntityInfoGathered.ObserveRemove().Subscribe(remove => VisibleEntities.Remove(remove.Key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsHostileTo(Entity other)
|
|
|
|
|
{
|
|
|
|
|
if (Faction == null)
|
|
|
|
|
{
|
|
|
|
|
return other.Faction != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Faction.PlayerHostile && other.Faction == null;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-08 12:44:10 +00:00
|
|
|
private void MapEntity()
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
2020-12-31 19:53:16 +00:00
|
|
|
Equipment.Add(new EquippedItem(ItemManager, Hull, int2.zero, this));
|
2020-12-22 03:13:43 +00:00
|
|
|
Mass = hullData.Mass;
|
2020-12-27 22:18:22 +00:00
|
|
|
Temperature = new float[hullData.Shape.Width, hullData.Shape.Height];
|
2021-01-17 23:26:53 +00:00
|
|
|
NewTemperature = new float[hullData.Shape.Width, hullData.Shape.Height];
|
2021-01-17 02:45:52 +00:00
|
|
|
HullConductivity = new bool2[hullData.Shape.Width,hullData.Shape.Height];
|
2020-12-27 22:18:22 +00:00
|
|
|
ThermalMass = new float[hullData.Shape.Width, hullData.Shape.Height];
|
2021-01-08 12:44:10 +00:00
|
|
|
Armor = new float[hullData.Shape.Width, hullData.Shape.Height];
|
2021-02-01 08:13:14 +00:00
|
|
|
MaxArmor = new float[hullData.Shape.Width, hullData.Shape.Height];
|
2020-12-12 03:42:58 +00:00
|
|
|
Hardpoints = new HardpointData[hullData.Shape.Width, hullData.Shape.Height];
|
2020-12-10 23:20:38 +00:00
|
|
|
foreach (var hardpoint in hullData.Hardpoints)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
foreach (var hardpointCoord in hardpoint.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
var hullCoord = hardpoint.Position + hardpointCoord;
|
2020-12-12 03:42:58 +00:00
|
|
|
Hardpoints[hullCoord.x, hullCoord.y] = hardpoint;
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
2020-07-03 01:33:42 +01:00
|
|
|
}
|
2021-02-01 08:13:14 +00:00
|
|
|
var cellCount = hullData.Shape.Coordinates.Length;
|
|
|
|
|
foreach (var v in hullData.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
Armor[v.x, v.y] = hullData.Armor;
|
|
|
|
|
MaxArmor[v.x, v.y] = hullData.Armor;
|
|
|
|
|
if (Hardpoints[v.x, v.y] != null)
|
|
|
|
|
{
|
|
|
|
|
Armor[v.x, v.y] += Hardpoints[v.x, v.y].Armor;
|
|
|
|
|
MaxArmor[v.x, v.y] += Hardpoints[v.x, v.y].Armor;
|
|
|
|
|
}
|
|
|
|
|
Temperature[v.x, v.y] = 280;
|
|
|
|
|
ThermalMass[v.x, v.y] = hullData.Mass * hullData.SpecificHeat / cellCount;
|
|
|
|
|
}
|
|
|
|
|
GearOccupancy = new EquippedItem[hullData.Shape.Width, hullData.Shape.Height];
|
2020-05-06 04:56:36 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public void GenerateTriggerGroups()
|
|
|
|
|
{
|
|
|
|
|
foreach (var group in Weapons
|
|
|
|
|
.GroupBy(w => w.Item.EquippableItem.Data)
|
|
|
|
|
.Select((weapons, index) => (weapons, index)))
|
|
|
|
|
{
|
|
|
|
|
TriggerGroups[group.index].weapons = group.weapons.ToList();
|
|
|
|
|
TriggerGroups[group.index].items = group.weapons.Select(w=>w.Item).ToList();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-01 08:13:14 +00:00
|
|
|
public void AddHeat(int2 position, float heat, bool ignoreThermalMass = false)
|
2020-05-06 04:56:36 +01:00
|
|
|
{
|
2021-02-01 08:13:14 +00:00
|
|
|
if (ignoreThermalMass)
|
|
|
|
|
Temperature[position.x, position.y] += heat;
|
|
|
|
|
else
|
|
|
|
|
Temperature[position.x, position.y] += heat / ThermalMass[position.x, position.y];
|
2020-12-31 19:53:16 +00:00
|
|
|
}
|
2020-06-11 02:55:11 +01:00
|
|
|
|
2020-12-31 19:53:16 +00:00
|
|
|
public int CountItemsInCargo(Guid itemDataID)
|
|
|
|
|
{
|
|
|
|
|
int sum = 0;
|
|
|
|
|
foreach (var x in CargoBays)
|
2020-07-03 01:33:42 +01:00
|
|
|
{
|
2020-12-31 19:53:16 +00:00
|
|
|
if (x.ItemsOfType.ContainsKey(itemDataID))
|
|
|
|
|
{
|
|
|
|
|
foreach (var i in x.ItemsOfType[itemDataID]) sum += i is SimpleCommodity simpleCommodity ? simpleCommodity.Quantity : 1;
|
|
|
|
|
}
|
2020-07-03 01:33:42 +01:00
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-31 19:53:16 +00:00
|
|
|
return sum;
|
2020-12-27 22:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public EquippedCargoBay FindItemInCargo(Guid itemDataID)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
return CargoBays.FirstOrDefault(c => c.ItemsOfType.ContainsKey(itemDataID));
|
2020-06-10 02:45:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Attempts to move a given number of items of the given type to the target Entity
|
|
|
|
|
// Returns the number of items successfully transferred
|
|
|
|
|
public int TryTransferItems(Entity target, Guid itemDataID, int quantity)
|
2020-06-10 02:45:10 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
int quantityTransferred = 0;
|
|
|
|
|
while (quantityTransferred < quantity)
|
|
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
EquippedCargoBay originInventory = CargoBays.FirstOrDefault(c => c.ItemsOfType.ContainsKey(itemDataID));
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
if (originInventory == null) break;
|
|
|
|
|
|
|
|
|
|
var itemInstance = originInventory.ItemsOfType[itemDataID][0];
|
|
|
|
|
|
|
|
|
|
if (itemInstance is SimpleCommodity simpleCommodity)
|
|
|
|
|
{
|
|
|
|
|
var targetQuantity = min(simpleCommodity.Quantity, quantity - quantityTransferred);
|
2020-12-19 02:37:13 +00:00
|
|
|
if (!target.CargoBays.Any(c => originInventory.TryTransferItem(c, simpleCommodity, targetQuantity)))
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
quantityTransferred += targetQuantity - simpleCommodity.Quantity;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quantityTransferred += targetQuantity;
|
|
|
|
|
}
|
|
|
|
|
else if (itemInstance is CraftedItemInstance craftedItemInstance)
|
|
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
if (!target.CargoBays.Any(c => originInventory.TryTransferItem(c, craftedItemInstance)))
|
2020-12-10 23:20:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
quantityTransferred++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-10 02:45:10 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
return quantityTransferred;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-04 03:58:46 +00:00
|
|
|
public EquippableItem TryUnequip(EquippedItem item)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2021-03-04 03:58:46 +00:00
|
|
|
// Don't allow unequipping when the entity is active
|
|
|
|
|
if (_active) return null;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
if (item.EquippableItem == null)
|
|
|
|
|
{
|
|
|
|
|
ItemManager.Log("Attempted to remove equipped item with no equippable item on it! This should be impossible!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
if (item is EquippedCargoBay cargoBay)
|
|
|
|
|
{
|
|
|
|
|
if(cargoBay.Cargo.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
ItemManager.Log("Attempted to remove cargo bay that is not empty! Please check first before doing this!");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-19 02:37:13 +00:00
|
|
|
CargoBays.Remove(cargoBay);
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-19 02:37:13 +00:00
|
|
|
Equipment.Remove(item);
|
2020-12-27 22:18:22 +00:00
|
|
|
_orderedEquipment = Equipment.OrderBy(x => x.SortPosition).ToArray();
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-20 03:04:52 +00:00
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = ItemManager.GetData(item.EquippableItem);
|
2020-12-20 03:04:52 +00:00
|
|
|
foreach (var i in hullData.Shape.Coordinates)
|
2021-01-17 02:45:52 +00:00
|
|
|
if (GearOccupancy[i.x, i.y] == item)
|
2020-12-27 22:18:22 +00:00
|
|
|
{
|
|
|
|
|
ThermalMass[i.x, i.y] -= ItemManager.GetThermalMass(item.EquippableItem) / itemData.Shape.Coordinates.Length;
|
2021-01-17 02:45:52 +00:00
|
|
|
GearOccupancy[i.x, i.y] = null;
|
2020-12-27 22:18:22 +00:00
|
|
|
}
|
2020-12-22 03:13:43 +00:00
|
|
|
Mass -= itemData.Mass;
|
2021-02-11 03:14:20 +00:00
|
|
|
foreach (var b in item.Behaviors)
|
2021-03-02 23:02:19 +00:00
|
|
|
{
|
2021-02-11 03:14:20 +00:00
|
|
|
if (b is Weapon weapon)
|
2021-03-02 23:02:19 +00:00
|
|
|
_weapons.Remove(weapon);
|
|
|
|
|
if(b is Capacitor capacitor)
|
|
|
|
|
_capacitors.Remove(capacitor);
|
|
|
|
|
if(b is Reactor reactor)
|
|
|
|
|
_reactors.Remove(reactor);
|
2021-03-04 03:58:46 +00:00
|
|
|
if(b is Radiator heatsink)
|
|
|
|
|
_heatsinks.Remove(heatsink);
|
2021-03-02 23:02:19 +00:00
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
return item.EquippableItem;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Check whether the given item will fit when its origin is placed at the given coordinate
|
|
|
|
|
private bool ItemFits(EquippableItemData itemData, HullData hullData, EquippableItem item, int2 hullCoord)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-20 03:04:52 +00:00
|
|
|
// If the given coordinate isn't even in the ship it obviously won't fit
|
|
|
|
|
if (!hullData.Shape[hullCoord]) return false;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Items without specific hardpoints on the ship can be freely rotated and placed anywhere
|
2021-01-17 02:45:52 +00:00
|
|
|
if (itemData.HardpointType == HardpointType.Tool)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
// Check every cell of the item's shape
|
|
|
|
|
foreach (var i in itemData.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
// If there is any gear already occupying that space, it won't fit
|
2021-01-05 02:56:17 +00:00
|
|
|
// If there's a hardpoint there, it won't fit
|
2020-12-10 23:20:38 +00:00
|
|
|
// Thermal items have their own layer and do not collide with gear
|
|
|
|
|
var itemCoord = hullCoord + itemData.Shape.Rotate(i, item.Rotation);
|
2021-01-17 02:45:52 +00:00
|
|
|
if (!hullData.InteriorCells[itemCoord] ||
|
|
|
|
|
itemData.HardpointType == HardpointType.Tool && Hardpoints[itemCoord.x, itemCoord.y] != null ||
|
|
|
|
|
GearOccupancy[itemCoord.x, itemCoord.y] != null)
|
|
|
|
|
return false;
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-12-12 03:42:58 +00:00
|
|
|
var hardpoint = Hardpoints[hullCoord.x, hullCoord.y];
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
// If there's no hardpoint there, it won't fit
|
|
|
|
|
if (hardpoint == null) return false;
|
|
|
|
|
|
|
|
|
|
// If the hardpoint type doesn't match the item, it won't fit
|
|
|
|
|
if (hardpoint.Type != itemData.HardpointType) return false;
|
|
|
|
|
|
2020-12-20 03:04:52 +00:00
|
|
|
// Items placed in hardpoints are automatically aligned to hardpoint rotation
|
|
|
|
|
item.Rotation = hardpoint.Rotation;
|
|
|
|
|
|
|
|
|
|
// Inset the shapes of both item and hardpoint
|
|
|
|
|
var itemShapeInset = hullData.Shape.Inset(itemData.Shape, hullCoord, item.Rotation);
|
|
|
|
|
var hardpointShapeInset = hullData.Shape.Inset(hardpoint.Shape, hardpoint.Position);
|
|
|
|
|
|
2021-01-08 12:44:10 +00:00
|
|
|
// Check every cell of the hardpoint shape
|
|
|
|
|
foreach(var v in hardpointShapeInset.Coordinates)
|
|
|
|
|
if (GearOccupancy[v.x, v.y] != null)
|
|
|
|
|
return false;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Check every cell of the item's shape
|
2020-12-20 03:04:52 +00:00
|
|
|
foreach (var i in itemShapeInset.Coordinates)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
// If the hardpoint does not have a matching cell, it wont fit
|
2020-12-20 03:04:52 +00:00
|
|
|
if (!hardpointShapeInset[i]) return false;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
// If there is any gear already occupying that space, it won't fit
|
2020-12-20 03:04:52 +00:00
|
|
|
if (GearOccupancy[i.x, i.y] != null) return false;
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Check whether the given item will fit when its origin is placed at the given coordinate on the hull
|
|
|
|
|
public bool ItemFits(EquippableItem item, int2 hullCoord)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2021-03-04 03:58:46 +00:00
|
|
|
// Don't allow equipping while deployed
|
|
|
|
|
if (_active) return false;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = ItemManager.GetData(item);
|
|
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
|
|
|
|
return ItemFits(itemData, hullData, item, hullCoord);
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public bool TryFindSpace(EquippableItem item, out int2 hullCoord)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2021-03-04 03:58:46 +00:00
|
|
|
// Don't allow equipping while deployed
|
|
|
|
|
if (_active)
|
|
|
|
|
{
|
|
|
|
|
hullCoord = int2.zero;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = ItemManager.GetData(item);
|
|
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
2020-05-11 01:17:10 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Tools and thermal equipment can be installed anywhere on the ship
|
|
|
|
|
// Search the whole ship for somewhere the item will fit
|
2021-01-17 02:45:52 +00:00
|
|
|
if (itemData.HardpointType == HardpointType.Tool)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
foreach (var hullCoord2 in hullData.InteriorCells.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
if (ItemFits(itemData, hullData, item, hullCoord2))
|
|
|
|
|
{
|
|
|
|
|
hullCoord = hullCoord2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-06 04:56:36 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Everything else has to be equipped onto a hardpoint of the same type
|
|
|
|
|
// Search the ship for an empty hardpoint that matches the type and shape of the item
|
|
|
|
|
else
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
foreach (var hardpoint in hullData.Hardpoints)
|
|
|
|
|
{
|
|
|
|
|
if(hardpoint.Type == itemData.HardpointType)
|
|
|
|
|
{
|
|
|
|
|
foreach (var hardpointCoord in hardpoint.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
var hullCoord2 = hardpoint.Position + hardpointCoord;
|
|
|
|
|
if (ItemFits(itemData, hullData, item, hullCoord2))
|
|
|
|
|
{
|
|
|
|
|
hullCoord = hullCoord2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
2020-04-28 01:50:50 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
hullCoord = int2.zero;
|
|
|
|
|
return false;
|
2020-04-28 01:50:50 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Try to equip the given item anywhere it will fit, returns true when the item was successfully equipped
|
|
|
|
|
public bool TryEquip(EquippableItem item) => TryFindSpace(item, out var hullCoord) && TryEquip(item, hullCoord);
|
|
|
|
|
|
|
|
|
|
// Try to equip the given item to the given location
|
|
|
|
|
public bool TryEquip(EquippableItem item, int2 hullCoord)
|
2020-06-02 07:01:03 +01:00
|
|
|
{
|
2021-03-04 03:58:46 +00:00
|
|
|
// Don't allow equipping while deployed
|
|
|
|
|
if (_active) return false;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = ItemManager.GetData(item);
|
|
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
|
|
|
|
|
|
|
|
|
if (!ItemFits(itemData, hullData, item, hullCoord)) return false;
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2021-01-06 14:56:39 +00:00
|
|
|
EquippedItem equippedItem;
|
2021-01-17 02:45:52 +00:00
|
|
|
if (itemData.HardpointType == HardpointType.Tool)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
if(itemData is CargoBayData)
|
|
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
if (itemData is DockingBayData)
|
|
|
|
|
{
|
2020-12-27 22:18:22 +00:00
|
|
|
equippedItem = new EquippedDockingBay(ItemManager, item, hullCoord, this, $"{Name} Docking Bay {DockingBays.Count + 1}");
|
2020-12-19 02:37:13 +00:00
|
|
|
DockingBays.Add((EquippedDockingBay) equippedItem);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-12-27 22:18:22 +00:00
|
|
|
equippedItem = new EquippedCargoBay(ItemManager, item, hullCoord, this, $"{Name} Cargo Bay {CargoBays.Count + 1}");
|
2020-12-19 02:37:13 +00:00
|
|
|
CargoBays.Add((EquippedCargoBay) equippedItem);
|
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-12-27 22:18:22 +00:00
|
|
|
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this);
|
2020-12-19 02:37:13 +00:00
|
|
|
Equipment.Add(equippedItem);
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-06-02 07:01:03 +01:00
|
|
|
else
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2021-01-06 14:56:39 +00:00
|
|
|
equippedItem = new EquippedItem(ItemManager, item, hullCoord, this);
|
2020-12-19 02:37:13 +00:00
|
|
|
Equipment.Add(equippedItem);
|
2021-01-06 14:56:39 +00:00
|
|
|
}
|
2021-03-03 01:53:23 +00:00
|
|
|
|
|
|
|
|
foreach (var b in equippedItem.Behaviors)
|
|
|
|
|
{
|
|
|
|
|
if (b is Weapon weapon)
|
|
|
|
|
_weapons.Add(weapon);
|
|
|
|
|
if(b is Capacitor capacitor)
|
|
|
|
|
_capacitors.Add(capacitor);
|
|
|
|
|
if(b is Reactor reactor)
|
|
|
|
|
_reactors.Add(reactor);
|
2021-03-04 03:58:46 +00:00
|
|
|
if(b is Radiator heatsink)
|
|
|
|
|
_heatsinks.Add(heatsink);
|
2021-03-03 01:53:23 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-04 03:58:46 +00:00
|
|
|
equippedItem.OnOnline += () => ItemOnline.OnNext(equippedItem);
|
|
|
|
|
equippedItem.OnOffline += () => ItemOffline.OnNext(equippedItem);
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2021-01-06 14:56:39 +00:00
|
|
|
foreach (var i in itemData.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
var occupiedCoord = hullCoord + itemData.Shape.Rotate(i, item.Rotation);
|
|
|
|
|
// TODO: Track thermal mass of cargo bay contents as reactive property
|
|
|
|
|
ThermalMass[occupiedCoord.x, occupiedCoord.y] += ItemManager.GetThermalMass(item) / itemData.Shape.Coordinates.Length;
|
2021-01-17 02:45:52 +00:00
|
|
|
GearOccupancy[occupiedCoord.x, occupiedCoord.y] = equippedItem;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
2021-01-06 14:56:39 +00:00
|
|
|
|
|
|
|
|
Mass += itemData.Mass;
|
|
|
|
|
_orderedEquipment = Equipment.OrderBy(x => x.SortPosition).ToArray();
|
|
|
|
|
return true;
|
2020-12-19 02:37:13 +00:00
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-19 02:37:13 +00:00
|
|
|
public EquippedDockingBay TryDock(Ship ship)
|
|
|
|
|
{
|
|
|
|
|
var bay = DockingBays.FirstOrDefault(x => x.DockedShip == null);
|
|
|
|
|
if (bay != null)
|
|
|
|
|
{
|
|
|
|
|
bay.DockedShip = ship;
|
|
|
|
|
ship.SetParent(this);
|
|
|
|
|
Zone.Entities.Remove(ship);
|
2021-02-26 19:01:47 +00:00
|
|
|
Deactivate();
|
|
|
|
|
ship.Docked.OnNext(this);
|
2020-12-19 02:37:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryUndock(Ship ship)
|
|
|
|
|
{
|
|
|
|
|
var bay = DockingBays.FirstOrDefault(x => x.DockedShip == ship);
|
|
|
|
|
if (bay == null)
|
|
|
|
|
{
|
|
|
|
|
ItemManager.Log($"Ship {ship.Name} attempted to undock from {Name}, but it was not docked!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bay.Cargo.Any())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bay.DockedShip = null;
|
|
|
|
|
ship.RemoveParent();
|
|
|
|
|
Zone.Entities.Add(ship);
|
2021-02-26 19:01:47 +00:00
|
|
|
ship.Activate();
|
2020-12-19 02:37:13 +00:00
|
|
|
|
|
|
|
|
return true;
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-02 23:02:19 +00:00
|
|
|
public bool TryConsumeEnergy(float energy)
|
|
|
|
|
{
|
|
|
|
|
if (energy < .01f) return true;
|
|
|
|
|
int chargedCapacitors;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
chargedCapacitors = _capacitors.Count(capacitor => capacitor.Charge > .01f);
|
|
|
|
|
var chargeToRemove = energy;
|
|
|
|
|
foreach (var cap in _capacitors)
|
|
|
|
|
{
|
|
|
|
|
if(cap.Charge > 0.01f)
|
|
|
|
|
{
|
|
|
|
|
var chargeRemoved = min(chargeToRemove / chargedCapacitors, cap.Charge);
|
|
|
|
|
cap.AddCharge(-chargeRemoved);
|
|
|
|
|
energy -= chargeRemoved;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (chargedCapacitors > 0 && energy > .01f);
|
|
|
|
|
|
|
|
|
|
if (energy < .01f) return true;
|
|
|
|
|
|
|
|
|
|
int onlineReactors = _reactors.Count(reactor=>reactor.Item.Online);
|
|
|
|
|
foreach (var reactor in _reactors)
|
|
|
|
|
{
|
|
|
|
|
if (reactor.Item.Online)
|
|
|
|
|
{
|
|
|
|
|
reactor.ConsumeEnergy(energy / onlineReactors);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return onlineReactors > 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
private void AddChild(Entity entity)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
|
|
|
|
Mass += entity.Mass;
|
2020-12-10 23:20:38 +00:00
|
|
|
Children.Add(entity);
|
2020-06-05 04:16:33 +01:00
|
|
|
}
|
2020-06-02 07:01:03 +01:00
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
private void RemoveChild(Entity entity)
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
|
|
|
|
Mass -= entity.Mass;
|
2020-12-10 23:20:38 +00:00
|
|
|
Children.Remove(entity);
|
2020-06-02 07:01:03 +01:00
|
|
|
}
|
2020-12-01 00:16:11 +00:00
|
|
|
|
|
|
|
|
public void SetParent(Entity parent)
|
|
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
Parent = parent;
|
2020-12-01 00:16:11 +00:00
|
|
|
parent.AddChild(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RemoveParent()
|
|
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
if (Parent == null)
|
2020-12-01 00:16:11 +00:00
|
|
|
return;
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
Parent.RemoveChild(this);
|
|
|
|
|
Parent = null;
|
2020-12-01 00:16:11 +00:00
|
|
|
}
|
2020-06-02 07:01:03 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public T GetBehavior<T>() where T : class, IBehavior
|
2020-06-02 07:01:03 +01:00
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
foreach (var equippedItem in Equipment)
|
2020-12-27 22:18:22 +00:00
|
|
|
if(equippedItem.Behaviors != null)
|
|
|
|
|
foreach (var behavior in equippedItem.Behaviors)
|
|
|
|
|
if (behavior is T b)
|
|
|
|
|
return b;
|
2020-12-10 23:20:38 +00:00
|
|
|
return null;
|
|
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public IEnumerable<T> GetBehaviors<T>() where T : class, IBehavior
|
|
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
foreach (var equippedItem in Equipment)
|
2020-12-27 22:18:22 +00:00
|
|
|
if(equippedItem.Behaviors != null)
|
|
|
|
|
foreach (var behavior in equippedItem.Behaviors)
|
|
|
|
|
if (behavior is T b)
|
|
|
|
|
yield return b;
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public IEnumerable<T> GetBehaviorData<T>() where T : BehaviorData
|
|
|
|
|
{
|
2020-12-19 02:37:13 +00:00
|
|
|
foreach (var equippedItem in Equipment)
|
2020-12-10 23:20:38 +00:00
|
|
|
foreach (var behavior in equippedItem.Behaviors)
|
|
|
|
|
if (behavior.Data is T b)
|
|
|
|
|
yield return b;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-25 05:53:36 +00:00
|
|
|
// public IEnumerable<(T t, Switch s)> GetSwitch<T>() where T : class, IBehavior
|
|
|
|
|
// {
|
|
|
|
|
// foreach (var equippedItem in Equipment)
|
|
|
|
|
// foreach (var group in equippedItem.BehaviorGroups.Values)
|
|
|
|
|
// foreach(var behavior in group.Behaviors)
|
|
|
|
|
// if (behavior is T t)
|
|
|
|
|
// {
|
|
|
|
|
// var s = group.GetExposed<Switch>();
|
|
|
|
|
// if (s != null) yield return (t, s);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// public IEnumerable<(T behavior, Trigger trigger)> GetTrigger<T>() where T : class, IBehavior
|
|
|
|
|
// {
|
|
|
|
|
// foreach (var equippedItem in Equipment)
|
|
|
|
|
// foreach (var group in equippedItem.BehaviorGroups.Values)
|
|
|
|
|
// foreach(var behavior in group.Behaviors)
|
|
|
|
|
// if (behavior is T t)
|
|
|
|
|
// {
|
|
|
|
|
// var s = group.GetExposed<Trigger>();
|
|
|
|
|
// if (s != null) yield return (t, s);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// public IEnumerable<(T behavior, Axis axis)> GetAxis<T>() where T : class, IBehavior
|
|
|
|
|
// {
|
|
|
|
|
// foreach (var equippedItem in Equipment)
|
|
|
|
|
// foreach (var group in equippedItem.BehaviorGroups.Values)
|
|
|
|
|
// foreach(var behavior in group.Behaviors)
|
|
|
|
|
// if (behavior is T t)
|
|
|
|
|
// {
|
|
|
|
|
// var s = group.GetExposed<Axis>();
|
|
|
|
|
// if (s != null) yield return (t, s);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
public virtual void Update(float delta)
|
|
|
|
|
{
|
2020-12-27 22:18:22 +00:00
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
|
|
|
|
TargetRange = Target.Value == null ? -1 : length(Position - Target.Value.Position);
|
2021-01-25 05:53:36 +00:00
|
|
|
|
|
|
|
|
foreach (var v in VisibilitySources.Keys.ToArray())
|
|
|
|
|
{
|
|
|
|
|
VisibilitySources[v] *= max(1 - ItemManager.GameplaySettings.VisibilityDecay * delta, 0);
|
|
|
|
|
|
|
|
|
|
if (VisibilitySources[v] < 0.01f) VisibilitySources.Remove(v);
|
|
|
|
|
}
|
2021-02-26 19:01:47 +00:00
|
|
|
|
|
|
|
|
UpdateTemperature(delta);
|
|
|
|
|
|
|
|
|
|
if (_active)
|
|
|
|
|
{
|
|
|
|
|
foreach (var equippedItem in _orderedEquipment)
|
|
|
|
|
{
|
|
|
|
|
equippedItem.Update(delta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var message in Messages.Keys.ToArray())
|
|
|
|
|
{
|
|
|
|
|
Messages[message] = Messages[message] - delta;
|
|
|
|
|
if (Messages[message] < 0)
|
|
|
|
|
Messages.Remove(message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach(var child in Children)
|
|
|
|
|
child.Update(delta);
|
|
|
|
|
|
|
|
|
|
if (Parent != null)
|
|
|
|
|
{
|
|
|
|
|
Position = Parent.Position;
|
|
|
|
|
Velocity = Parent.Velocity;
|
|
|
|
|
}
|
|
|
|
|
else Position.y = Zone.GetHeight(Position.xz) + hullData.GridOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateTemperature(float delta)
|
|
|
|
|
{
|
|
|
|
|
var hullData = ItemManager.GetData(Hull) as HullData;
|
2021-01-25 05:53:36 +00:00
|
|
|
|
2021-01-27 00:05:30 +00:00
|
|
|
MaxTemp = Single.MinValue;
|
|
|
|
|
MinTemp = Single.MaxValue;
|
|
|
|
|
|
2021-01-17 23:26:53 +00:00
|
|
|
//float[,] newTemp = new float[hullData.Shape.Width,hullData.Shape.Height];
|
2020-12-27 22:18:22 +00:00
|
|
|
var radiation = 0f;
|
|
|
|
|
foreach (var v in hullData.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
var temp = Temperature[v.x, v.y];
|
2021-01-27 00:05:30 +00:00
|
|
|
var totalTemp = temp / ItemManager.GameplaySettings.HeatConductionMultiplier;
|
|
|
|
|
var totalConductivity = 1f / ItemManager.GameplaySettings.HeatConductionMultiplier;
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
if (hullData.Shape[int2(v.x - 1, v.y)])
|
2021-01-27 00:05:30 +00:00
|
|
|
{
|
|
|
|
|
var conductivity = (GearOccupancy[v.x, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(GearOccupancy[v.x - 1, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(HullConductivity[v.x - 1, v.y].x ? hullData.Conductivity : 1 / hullData.Conductivity) *
|
|
|
|
|
(ThermalMass[v.x - 1, v.y] / ThermalMass[v.x, v.y]);
|
|
|
|
|
totalConductivity += conductivity;
|
|
|
|
|
totalTemp += Temperature[v.x - 1, v.y] * conductivity;
|
|
|
|
|
}
|
2021-01-17 02:45:52 +00:00
|
|
|
|
|
|
|
|
if (hullData.Shape[int2(v.x + 1, v.y)])
|
2021-01-27 00:05:30 +00:00
|
|
|
{
|
|
|
|
|
var conductivity = (GearOccupancy[v.x, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(GearOccupancy[v.x + 1, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(HullConductivity[v.x, v.y].x ? hullData.Conductivity : 1 / hullData.Conductivity) *
|
|
|
|
|
(ThermalMass[v.x + 1, v.y] / ThermalMass[v.x, v.y]);
|
|
|
|
|
totalConductivity += conductivity;
|
|
|
|
|
totalTemp += Temperature[v.x + 1, v.y] * conductivity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
if (hullData.Shape[int2(v.x, v.y - 1)])
|
2021-01-27 00:05:30 +00:00
|
|
|
{
|
|
|
|
|
var conductivity = (GearOccupancy[v.x, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(GearOccupancy[v.x, v.y - 1]?.Conductivity ?? 1) *
|
|
|
|
|
(HullConductivity[v.x, v.y - 1].y ? hullData.Conductivity : 1 / hullData.Conductivity) *
|
|
|
|
|
(ThermalMass[v.x, v.y - 1] / ThermalMass[v.x, v.y]);
|
|
|
|
|
totalConductivity += conductivity;
|
|
|
|
|
totalTemp += Temperature[v.x, v.y - 1] * conductivity;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2021-01-27 00:05:30 +00:00
|
|
|
if (hullData.Shape[int2(v.x, v.y + 1)])
|
|
|
|
|
{
|
|
|
|
|
var conductivity = (GearOccupancy[v.x, v.y]?.Conductivity ?? 1) *
|
|
|
|
|
(GearOccupancy[v.x, v.y + 1]?.Conductivity ?? 1) *
|
|
|
|
|
(HullConductivity[v.x, v.y].y ? hullData.Conductivity : 1 / hullData.Conductivity) *
|
|
|
|
|
(ThermalMass[v.x, v.y + 1] / ThermalMass[v.x, v.y]);
|
|
|
|
|
totalConductivity += conductivity;
|
|
|
|
|
totalTemp += Temperature[v.x, v.y + 1] * conductivity;
|
|
|
|
|
}
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2021-01-27 00:05:30 +00:00
|
|
|
NewTemperature[v.x, v.y] = totalTemp / totalConductivity;
|
|
|
|
|
|
|
|
|
|
var r = 0f;
|
2020-12-27 22:18:22 +00:00
|
|
|
// For all cells on the border of the entity, radiate some heat into space, increasing the visibility of the ship
|
2021-01-17 02:45:52 +00:00
|
|
|
if (Parent==null && !hullData.InteriorCells[v])
|
2020-12-27 22:18:22 +00:00
|
|
|
{
|
2021-03-01 01:53:56 +00:00
|
|
|
var rad = pow(NewTemperature[v.x, v.y], ItemManager.GameplaySettings.HeatRadiationExponent) *
|
|
|
|
|
ItemManager.GameplaySettings.HeatRadiationMultiplier;
|
|
|
|
|
NewTemperature[v.x, v.y] -= rad * delta;
|
|
|
|
|
r += rad;
|
2020-12-27 22:18:22 +00:00
|
|
|
}
|
2021-01-27 00:05:30 +00:00
|
|
|
|
|
|
|
|
radiation += r;
|
2021-01-17 02:45:52 +00:00
|
|
|
|
2021-01-31 03:52:32 +00:00
|
|
|
if(float.IsNaN(NewTemperature[v.x, v.y]) || NewTemperature[v.x, v.y] < 0)
|
2021-01-17 02:45:52 +00:00
|
|
|
ItemManager.Log("HOUSTON, WE HAVE A PROBLEM!");
|
2021-01-27 00:05:30 +00:00
|
|
|
|
|
|
|
|
if (NewTemperature[v.x, v.y] < MinTemp)
|
|
|
|
|
MinTemp = NewTemperature[v.x, v.y];
|
|
|
|
|
|
|
|
|
|
if (NewTemperature[v.x, v.y] > MaxTemp)
|
|
|
|
|
MaxTemp = NewTemperature[v.x, v.y];
|
2020-12-27 22:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VisibilitySources[this] = radiation;
|
2021-01-17 23:26:53 +00:00
|
|
|
var swap = Temperature;
|
|
|
|
|
Temperature = NewTemperature;
|
|
|
|
|
NewTemperature = swap;
|
2020-06-02 07:01:03 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public void SetMessage(string message)
|
2020-04-28 01:50:50 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
Messages[message] = ItemManager.GameplaySettings.MessageDuration;
|
2020-06-02 07:01:03 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class EquippedItem
|
|
|
|
|
{
|
2021-01-17 02:45:52 +00:00
|
|
|
public EquippableItem EquippableItem;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
public int2 Position;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
public IBehavior[] Behaviors;
|
|
|
|
|
|
2021-01-25 05:53:36 +00:00
|
|
|
public Dictionary<int, BehaviorGroup> BehaviorGroups;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
2021-03-04 03:58:46 +00:00
|
|
|
public bool Enabled = true;
|
|
|
|
|
|
|
|
|
|
public event Action OnOffline;
|
|
|
|
|
public event Action OnOnline;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
public float Conductivity { get; }
|
|
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
public Shape InsetShape { get; }
|
|
|
|
|
|
|
|
|
|
public int SortPosition;
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public bool Online
|
|
|
|
|
{
|
|
|
|
|
get => _online;
|
|
|
|
|
}
|
2021-01-10 03:59:47 +00:00
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
public float Temperature
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
float sum = 0;
|
|
|
|
|
foreach (var x in InsetShape.Coordinates) sum += _entity.Temperature[x.x, x.y];
|
|
|
|
|
return sum/InsetShape.Coordinates.Length;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-04 03:58:46 +00:00
|
|
|
|
|
|
|
|
public Entity Entity
|
|
|
|
|
{
|
|
|
|
|
get => _entity;
|
|
|
|
|
}
|
2020-12-27 22:18:22 +00:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
protected readonly ItemManager _itemManager;
|
|
|
|
|
private readonly EquippableItemData _data;
|
2020-12-27 22:18:22 +00:00
|
|
|
private Entity _entity;
|
2021-02-26 19:01:47 +00:00
|
|
|
private bool _online;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity)
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
_itemManager = itemManager;
|
|
|
|
|
_data = _itemManager.GetData(item);
|
2020-12-27 22:18:22 +00:00
|
|
|
_entity = entity;
|
2020-12-10 23:20:38 +00:00
|
|
|
EquippableItem = item;
|
|
|
|
|
Position = position;
|
2021-01-17 02:45:52 +00:00
|
|
|
Conductivity = _data.Conductivity;
|
2020-12-27 22:18:22 +00:00
|
|
|
var hullData = itemManager.GetData(entity.Hull);
|
|
|
|
|
InsetShape = hullData.Shape.Inset(_data.Shape, position, item.Rotation);
|
2020-12-31 19:53:16 +00:00
|
|
|
|
|
|
|
|
Behaviors = _data.Behaviors
|
|
|
|
|
.Select(bd => bd.CreateInstance(itemManager, entity, this))
|
|
|
|
|
.ToArray();
|
2021-01-25 05:53:36 +00:00
|
|
|
|
2020-12-31 19:53:16 +00:00
|
|
|
BehaviorGroups = Behaviors
|
|
|
|
|
.GroupBy(b => b.Data.Group)
|
2021-01-25 05:53:36 +00:00
|
|
|
.OrderBy(g => g.Key)
|
|
|
|
|
.ToDictionary(g => g.Key, g => new BehaviorGroup
|
|
|
|
|
{
|
2020-12-31 19:53:16 +00:00
|
|
|
Behaviors = g.ToArray(),
|
2021-01-25 05:53:36 +00:00
|
|
|
// Switch = (Switch) g.FirstOrDefault(b => b is Switch),
|
|
|
|
|
// Trigger = (Trigger) g.FirstOrDefault(b => b is Trigger)
|
|
|
|
|
});
|
2020-12-31 19:53:16 +00:00
|
|
|
|
|
|
|
|
foreach (var behavior in Behaviors)
|
|
|
|
|
{
|
|
|
|
|
if (behavior is IOrderedBehavior orderedBehavior)
|
|
|
|
|
SortPosition = orderedBehavior.Order;
|
|
|
|
|
if(behavior is IPopulationAssignment populationAssignment)
|
|
|
|
|
entity.PopulationAssignments.Add(populationAssignment);
|
|
|
|
|
}
|
2020-12-27 22:18:22 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-01 08:13:14 +00:00
|
|
|
public void AddHeat(float heat, bool ignoreThermalMass = false)
|
2020-12-27 22:18:22 +00:00
|
|
|
{
|
|
|
|
|
foreach(var hullCoord in InsetShape.Coordinates)
|
2021-02-01 08:13:14 +00:00
|
|
|
_entity.AddHeat(hullCoord, heat / InsetShape.Coordinates.Length, ignoreThermalMass);
|
2020-04-09 10:33:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public void Update(float delta)
|
2020-05-11 01:17:10 +01:00
|
|
|
{
|
2021-02-26 19:01:47 +00:00
|
|
|
foreach (var behavior in Behaviors)
|
2021-01-17 02:45:52 +00:00
|
|
|
if(behavior is IAlwaysUpdatedBehavior alwaysUpdatedBehavior) alwaysUpdatedBehavior.Update(delta);
|
2021-01-10 03:59:47 +00:00
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
var previouslyOnline = _online;
|
|
|
|
|
_online = EquippableItem.Durability > .01f && Temperature > _data.MinimumTemperature && Temperature < _data.MaximumTemperature;
|
|
|
|
|
|
2021-03-04 03:58:46 +00:00
|
|
|
if (!previouslyOnline && _online) OnOnline?.Invoke();
|
|
|
|
|
if (previouslyOnline && !_online) OnOffline?.Invoke();
|
2021-02-26 19:01:47 +00:00
|
|
|
|
2021-03-04 03:58:46 +00:00
|
|
|
if (Enabled && _online)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
2021-01-25 05:53:36 +00:00
|
|
|
foreach (var group in BehaviorGroups.Values)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
2021-01-10 03:59:47 +00:00
|
|
|
foreach (var behavior in group.Behaviors)
|
|
|
|
|
{
|
|
|
|
|
if (!behavior.Execute(delta))
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-03-02 23:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T GetBehavior<T>() where T : class, IBehavior
|
|
|
|
|
{
|
|
|
|
|
foreach (var behavior in Behaviors)
|
|
|
|
|
if (behavior is T b)
|
|
|
|
|
return b;
|
|
|
|
|
return null;
|
2020-05-11 01:17:10 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
2020-05-11 01:17:10 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public class EquippedCargoBay : EquippedItem
|
|
|
|
|
{
|
|
|
|
|
public readonly ReactiveDictionary<ItemInstance, int2> Cargo = new ReactiveDictionary<ItemInstance, int2>();
|
|
|
|
|
|
|
|
|
|
public readonly ItemInstance[,] Occupancy;
|
|
|
|
|
|
|
|
|
|
public readonly Dictionary<Guid, List<ItemInstance>> ItemsOfType = new Dictionary<Guid, List<ItemInstance>>();
|
2020-12-14 02:56:35 +00:00
|
|
|
|
|
|
|
|
public readonly CargoBayData Data;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
public float Mass { get; private set; }
|
|
|
|
|
public float ThermalMass { get; private set; }
|
2020-12-19 02:37:13 +00:00
|
|
|
public string Name { get; }
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-27 22:18:22 +00:00
|
|
|
public EquippedCargoBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity)
|
2020-05-11 01:17:10 +01:00
|
|
|
{
|
2020-12-14 02:56:35 +00:00
|
|
|
Data = _itemManager.GetData(EquippableItem) as CargoBayData;
|
2020-12-19 02:37:13 +00:00
|
|
|
Name = name;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-14 02:56:35 +00:00
|
|
|
Mass = Data.Mass;
|
|
|
|
|
ThermalMass = Data.Mass * Data.SpecificHeat;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
2020-12-14 02:56:35 +00:00
|
|
|
Occupancy = new ItemInstance[Data.InteriorShape.Width,Data.InteriorShape.Height];
|
2020-05-11 01:17:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Check whether the given item will fit when its origin is placed at the given coordinate
|
2020-12-20 03:04:52 +00:00
|
|
|
public bool ItemFits(ItemInstance item, int2 cargoCoord)
|
2020-05-28 04:50:40 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = _itemManager.GetData(item);
|
|
|
|
|
// Check every cell of the item's shape
|
|
|
|
|
foreach (var i in itemData.Shape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
// If there is an item already occupying that space, it won't fit
|
|
|
|
|
var itemCargoCoord = cargoCoord + itemData.Shape.Rotate(i, item.Rotation);
|
2020-12-20 03:04:52 +00:00
|
|
|
if (!Data.InteriorShape[itemCargoCoord] || (Occupancy[itemCargoCoord.x, itemCargoCoord.y] != null && Occupancy[itemCargoCoord.x, itemCargoCoord.y] != item)) return false;
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2020-05-28 04:50:40 +01:00
|
|
|
}
|
2021-03-04 03:58:46 +00:00
|
|
|
|
|
|
|
|
public bool TryFindSpace(ItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
if (item is SimpleCommodity simpleCommodity)
|
|
|
|
|
return TryFindSpace(simpleCommodity, out _);
|
|
|
|
|
if (item is CraftedItemInstance craftedItem)
|
|
|
|
|
return TryFindSpace(craftedItem, out _);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-28 04:50:40 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Tries to find a place to put the given items in the inventory
|
|
|
|
|
// Will attempt to fill existing item stacks first
|
|
|
|
|
// Returns true only when ALL of the items have places to go
|
|
|
|
|
public bool TryFindSpace(SimpleCommodity item, out List<int2> positions)
|
2020-05-28 04:50:40 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
positions = new List<int2>();
|
|
|
|
|
var itemData = _itemManager.GetData(item);
|
|
|
|
|
var remainingQuantity = item.Quantity;
|
|
|
|
|
|
|
|
|
|
// For simple commodities, search for existing item stacks to add to
|
|
|
|
|
foreach (var cargoItem in Cargo.Keys)
|
|
|
|
|
{
|
|
|
|
|
if (item.Data != cargoItem.Data) continue;
|
|
|
|
|
|
|
|
|
|
var cargoCommodity = (SimpleCommodity) cargoItem;
|
|
|
|
|
if (cargoCommodity.Quantity >= itemData.MaxStack) continue;
|
|
|
|
|
|
|
|
|
|
// Subtract remaining space in existing stack from remaining quantity
|
|
|
|
|
remainingQuantity -= min(itemData.MaxStack - cargoCommodity.Quantity, remainingQuantity);
|
|
|
|
|
positions.Add(Cargo[cargoItem]);
|
|
|
|
|
|
|
|
|
|
// If we've moved all of the items into existing stacks, no need to search for empty space!
|
|
|
|
|
if (remainingQuantity == 0) return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search all the space in the cargo bay for an empty space where the item fits
|
2020-12-14 02:56:35 +00:00
|
|
|
foreach (var cargoCoord in Data.InteriorShape.Coordinates)
|
2020-12-10 23:20:38 +00:00
|
|
|
{
|
|
|
|
|
if (ItemFits(item, cargoCoord))
|
|
|
|
|
{
|
|
|
|
|
positions.Add(cargoCoord);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2020-05-28 04:50:40 +01:00
|
|
|
}
|
2021-03-04 03:58:46 +00:00
|
|
|
|
|
|
|
|
// Searches the cargo bay for a position where the item will fit, returns true when found
|
|
|
|
|
public bool TryFindSpace(CraftedItemInstance item, out int2 position)
|
|
|
|
|
{
|
|
|
|
|
// Search all the space in the cargo bay for an empty space where the item fits
|
|
|
|
|
foreach (var cargoCoord in Data.InteriorShape.Coordinates)
|
|
|
|
|
{
|
|
|
|
|
if (ItemFits(item, cargoCoord))
|
|
|
|
|
{
|
|
|
|
|
position = cargoCoord;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
position = int2.zero;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-01-27 16:14:41 +00:00
|
|
|
|
|
|
|
|
public bool TryStore(ItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
if (item is SimpleCommodity simpleCommodity)
|
|
|
|
|
return TryStore(simpleCommodity);
|
|
|
|
|
if (item is CraftedItemInstance craftedItem)
|
|
|
|
|
return TryStore(craftedItem);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-28 04:50:40 +01:00
|
|
|
|
2020-12-20 03:04:52 +00:00
|
|
|
public bool TryStore(ItemInstance item, int2 cargoCoord)
|
|
|
|
|
{
|
|
|
|
|
if (item is SimpleCommodity simpleCommodity)
|
|
|
|
|
return TryStore(simpleCommodity, cargoCoord);
|
|
|
|
|
if (item is CraftedItemInstance craftedItem)
|
|
|
|
|
return TryStore(craftedItem, cargoCoord);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Attempts to store all of the given item anywhere in the inventory
|
|
|
|
|
// Will attempt to fill existing item stacks first
|
|
|
|
|
// Returns true only when ALL of the items are successfully stored
|
|
|
|
|
public bool TryStore(SimpleCommodity item)
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
TryFindSpace(item, out var positions);
|
|
|
|
|
foreach (var position in positions)
|
2020-05-26 01:12:06 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
if (TryStore(item, position)) return true;
|
2020-05-26 01:12:06 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
return false;
|
2020-04-09 10:33:16 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Try to store the given commodity at the given position
|
|
|
|
|
// If there's a stack at the given position it will be added to
|
|
|
|
|
// Returns true only when ALL of the items are successfully stored
|
|
|
|
|
public bool TryStore(SimpleCommodity item, int2 cargoCoord)
|
2020-04-09 10:33:16 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = _itemManager.GetData(item);
|
|
|
|
|
if (ItemFits(item, cargoCoord))
|
2020-06-05 04:16:33 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
foreach (var p in itemData.Shape.Coordinates)
|
2020-06-12 01:57:15 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var pos = cargoCoord + itemData.Shape.Rotate(p, item.Rotation);
|
|
|
|
|
Occupancy[pos.x, pos.y] = item;
|
|
|
|
|
}
|
|
|
|
|
Cargo[item] = cargoCoord;
|
2020-06-05 04:16:33 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
if(!ItemsOfType.ContainsKey(item.Data))
|
|
|
|
|
ItemsOfType[item.Data] = new List<ItemInstance>();
|
|
|
|
|
ItemsOfType[item.Data].Add(item);
|
|
|
|
|
}
|
|
|
|
|
else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data == item.Data)
|
|
|
|
|
{
|
|
|
|
|
if (cargoCommodity.Quantity + item.Quantity <= itemData.MaxStack)
|
|
|
|
|
{
|
|
|
|
|
cargoCommodity.Quantity += item.Quantity;
|
2020-06-12 01:57:15 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
else
|
2020-06-12 01:57:15 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var quantityTransferred = itemData.MaxStack - cargoCommodity.Quantity;
|
|
|
|
|
item.Quantity -= quantityTransferred;
|
|
|
|
|
cargoCommodity.Quantity = itemData.MaxStack;
|
|
|
|
|
|
|
|
|
|
Mass += itemData.Mass * quantityTransferred;
|
|
|
|
|
ThermalMass += itemData.Mass * itemData.SpecificHeat * quantityTransferred;
|
|
|
|
|
return false;
|
2020-06-12 01:57:15 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
}
|
|
|
|
|
else return false;
|
|
|
|
|
|
|
|
|
|
Mass += _itemManager.GetMass(item);
|
|
|
|
|
ThermalMass += _itemManager.GetThermalMass(item);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-06-12 01:57:15 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
// Try to store the given item anywhere it will fit, returns true when the item was successfully stored
|
|
|
|
|
public bool TryStore(CraftedItemInstance item) => TryFindSpace(item, out var position) && TryStore(item, position);
|
|
|
|
|
|
|
|
|
|
// Try to store the given item at the given position, returns true when the item was successfully stored
|
|
|
|
|
public bool TryStore(CraftedItemInstance item, int2 cargoCoord)
|
|
|
|
|
{
|
|
|
|
|
if (!ItemFits(item, cargoCoord)) return false;
|
|
|
|
|
|
|
|
|
|
var itemData = _itemManager.GetData(item);
|
|
|
|
|
foreach (var p in itemData.Shape.Coordinates)
|
2020-05-04 00:07:36 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
var pos = cargoCoord + itemData.Shape.Rotate(p, item.Rotation);
|
|
|
|
|
Occupancy[pos.x, pos.y] = item;
|
2020-05-04 00:07:36 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
Cargo[item] = cargoCoord;
|
|
|
|
|
|
|
|
|
|
if(!ItemsOfType.ContainsKey(item.Data))
|
|
|
|
|
ItemsOfType[item.Data] = new List<ItemInstance>();
|
|
|
|
|
ItemsOfType[item.Data].Add(item);
|
|
|
|
|
|
|
|
|
|
Mass += _itemManager.GetMass(item);
|
|
|
|
|
ThermalMass += _itemManager.GetThermalMass(item);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-05-11 01:17:10 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public SimpleCommodity Remove(SimpleCommodity item, int quantity)
|
|
|
|
|
{
|
|
|
|
|
if (!Cargo.ContainsKey(item))
|
2020-06-06 03:21:03 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
_itemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!");
|
|
|
|
|
return null;
|
2020-06-06 03:21:03 +01:00
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
var itemData = _itemManager.GetData(item);
|
|
|
|
|
if(quantity >= item.Quantity)
|
2020-06-06 03:21:03 +01:00
|
|
|
{
|
2020-12-20 03:04:52 +00:00
|
|
|
foreach(var v in Data.InteriorShape.Coordinates)
|
|
|
|
|
if (Occupancy[v.x, v.y] == item)
|
|
|
|
|
Occupancy[v.x, v.y] = null;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
Cargo.Remove(item);
|
|
|
|
|
ItemsOfType[item.Data].Remove(item);
|
|
|
|
|
if (!ItemsOfType[item.Data].Any())
|
|
|
|
|
ItemsOfType.Remove(item.Data);
|
|
|
|
|
|
|
|
|
|
Mass -= _itemManager.GetMass(item);
|
|
|
|
|
ThermalMass -= _itemManager.GetThermalMass(item);
|
|
|
|
|
|
|
|
|
|
return item;
|
2020-06-06 03:21:03 +01:00
|
|
|
}
|
2020-04-29 23:36:00 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
item.Quantity -= quantity;
|
|
|
|
|
Mass -= itemData.Mass * quantity;
|
|
|
|
|
ThermalMass -= itemData.Mass * itemData.SpecificHeat * quantity;
|
|
|
|
|
return new SimpleCommodity{Data = item.Data, Quantity = quantity, Rotation = item.Rotation};
|
2020-05-29 23:06:35 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
public void Remove(CraftedItemInstance item)
|
2020-04-29 23:36:00 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
if (!Cargo.ContainsKey(item))
|
|
|
|
|
{
|
|
|
|
|
_itemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var itemData = _itemManager.GetData(item);
|
2020-12-20 03:04:52 +00:00
|
|
|
foreach(var v in Data.InteriorShape.Coordinates)
|
|
|
|
|
if (Occupancy[v.x, v.y] == item)
|
|
|
|
|
Occupancy[v.x, v.y] = null;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
Cargo.Remove(item);
|
|
|
|
|
ItemsOfType[item.Data].Remove(item);
|
|
|
|
|
if (!ItemsOfType[item.Data].Any())
|
|
|
|
|
ItemsOfType.Remove(item.Data);
|
|
|
|
|
|
|
|
|
|
Mass -= _itemManager.GetMass(item);
|
|
|
|
|
ThermalMass -= _itemManager.GetThermalMass(item);
|
2020-04-29 23:36:00 +01:00
|
|
|
}
|
2020-12-20 03:04:52 +00:00
|
|
|
|
|
|
|
|
public void Remove(ItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
if (item is SimpleCommodity simpleCommodity)
|
|
|
|
|
Remove(simpleCommodity, simpleCommodity.Quantity);
|
|
|
|
|
if (item is CraftedItemInstance craftedItem)
|
|
|
|
|
Remove(craftedItem);
|
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
|
|
|
public bool TryTransferItem(EquippedCargoBay target, SimpleCommodity item, int quantity)
|
2020-04-29 23:36:00 +01:00
|
|
|
{
|
2020-12-10 23:20:38 +00:00
|
|
|
if (!Cargo.ContainsKey(item))
|
|
|
|
|
{
|
|
|
|
|
_itemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-04-30 02:54:31 +01:00
|
|
|
|
2020-12-10 23:20:38 +00:00
|
|
|
var oldPos = Cargo[item];
|
|
|
|
|
var newItem = Remove(item, quantity);
|
|
|
|
|
|
|
|
|
|
if (target.TryStore(item)) return true;
|
|
|
|
|
|
|
|
|
|
// Failed to transfer full quantity, move the remaining items back to their old slot
|
|
|
|
|
TryStore(newItem, oldPos);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryTransferItem(EquippedCargoBay target, CraftedItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
if (!Cargo.ContainsKey(item))
|
|
|
|
|
{
|
|
|
|
|
_itemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!target.TryStore(item)) return false;
|
|
|
|
|
Remove(item);
|
|
|
|
|
return true;
|
2020-04-29 23:36:00 +01:00
|
|
|
}
|
2020-06-02 07:01:03 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-19 02:37:13 +00:00
|
|
|
public class EquippedDockingBay : EquippedCargoBay
|
|
|
|
|
{
|
|
|
|
|
public Ship DockedShip;
|
|
|
|
|
public int2 MaxSize => _data.MaxSize;
|
|
|
|
|
private DockingBayData _data;
|
2020-12-27 22:18:22 +00:00
|
|
|
public EquippedDockingBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity, name)
|
2020-12-19 02:37:13 +00:00
|
|
|
{
|
|
|
|
|
_data = _itemManager.GetData(EquippableItem) as DockingBayData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 04:16:33 +01:00
|
|
|
public class BehaviorGroup
|
2020-06-02 07:01:03 +01:00
|
|
|
{
|
2020-06-05 04:16:33 +01:00
|
|
|
public IBehavior[] Behaviors;
|
2021-01-25 05:53:36 +00:00
|
|
|
|
|
|
|
|
public T GetBehavior<T>() where T : class, IBehavior
|
|
|
|
|
{
|
|
|
|
|
foreach (var b in Behaviors)
|
|
|
|
|
{
|
|
|
|
|
if (!(b is T s)) continue;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T GetExposed<T>() where T : class, IBehavior, IInteractiveBehavior
|
|
|
|
|
{
|
|
|
|
|
foreach (var b in Behaviors)
|
|
|
|
|
{
|
|
|
|
|
if (!(b is T s) || !((IInteractiveBehavior)b).Exposed) continue;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 04:16:33 +01:00
|
|
|
//public IAnalogBehavior Axis;
|
2020-04-09 10:33:16 +01:00
|
|
|
}
|