Equipment Data Simplification
Removed blueprint system for crafting (and excised anything depending on that) Implemented smootherstep and used it for wormhole animation Quality dependent durability and heat exponents are now global instead of item specific Database list view now groups equipment by manufacturer Thrusters can now consume energy Weapons can have reloads even when they don't have ammo
This commit is contained in:
parent
017335e09d
commit
47189c8a7e
49 changed files with 6943 additions and 1548 deletions
|
|
@ -189,4 +189,10 @@ public static class AetheriaMath
|
|||
x = saturate(x);
|
||||
return x * x * (3 - 2 * x);
|
||||
}
|
||||
|
||||
public static float Smootherstep(float x)
|
||||
{
|
||||
x = saturate(x);
|
||||
return x * x * x * (x * (x * 6 - 15) + 10);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ public interface IPopulationAssignment
|
|||
}
|
||||
|
||||
[MessagePackObject,
|
||||
Union(0, typeof(FactoryPersistence)),
|
||||
JsonObject(MemberSerialization.OptIn),
|
||||
JsonConverter(typeof(JsonKnownTypesConverter<PersistentBehaviorData>))]
|
||||
public abstract class PersistentBehaviorData
|
||||
|
|
@ -97,7 +96,6 @@ public abstract class PersistentBehaviorData
|
|||
Union(9, typeof(WearData)),
|
||||
Union(10, typeof(VelocityConversionData)),
|
||||
Union(11, typeof(VelocityLimitData)),
|
||||
Union(12, typeof(FactoryData)),
|
||||
// Union(13, typeof(PatrolControllerData)),
|
||||
// Union(14, typeof(TowingControllerData)),
|
||||
Union(15, typeof(CooldownData)),
|
||||
|
|
|
|||
|
|
@ -1,287 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class FactoryData : BehaviorData
|
||||
{
|
||||
[InspectableField, JsonProperty("toolingTime"), Key(1)]
|
||||
public PerformanceStat ToolingTime = new PerformanceStat();
|
||||
|
||||
[InspectableField, JsonProperty("automation"), Key(2)]
|
||||
public int AutomationPoints;
|
||||
|
||||
[InspectableField, JsonProperty("automationQuality"), Key(3)]
|
||||
public float AutomationQuality = .5f;
|
||||
|
||||
[InspectableDatabaseLink(typeof(PersonalityAttribute)), JsonProperty("productionProfile"), Key(4)]
|
||||
public Dictionary<Guid, float> ProductionProfile = new Dictionary<Guid, float>();
|
||||
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new Factory(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class Factory : IBehavior//, IPersistentBehavior, IPopulationAssignment
|
||||
{
|
||||
public float ProductionQuality;
|
||||
public double RetoolingTime;
|
||||
public string ItemName;
|
||||
public Guid ItemUnderConstruction;
|
||||
public bool Active;
|
||||
public int AssignedPopulation { get; set; }
|
||||
|
||||
public Entity Entity { get; }
|
||||
public EquippedItem Item { get; }
|
||||
public ItemManager Context { get; }
|
||||
|
||||
public BehaviorData Data => _data;
|
||||
|
||||
public float ToolingTime { get; private set; }
|
||||
|
||||
public Guid Blueprint
|
||||
{
|
||||
get => _blueprint;
|
||||
set
|
||||
{
|
||||
if (value != _blueprint)
|
||||
{
|
||||
_blueprint = value;
|
||||
Active = false;
|
||||
if(value != Guid.Empty)
|
||||
{
|
||||
ItemName = Context.ItemData.Get<ItemData>(Context.ItemData.Get<BlueprintData>(value).Item).Name;
|
||||
RetoolingTime = ToolingTime;
|
||||
_retooling = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FactoryData _data;
|
||||
|
||||
private Guid _blueprint;
|
||||
private bool _retooling = false;
|
||||
private float _currentProductionQuality;
|
||||
|
||||
public Factory(ItemManager context, FactoryData data, Entity entity, EquippedItem item)
|
||||
{
|
||||
Context = context;
|
||||
_data = data;
|
||||
Entity = entity;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public bool Execute(float delta)
|
||||
{
|
||||
// ToolingTime = Context.Evaluate(_data.ToolingTime, Item, Entity);
|
||||
// var blueprint = Context.ItemData.Get<BlueprintData>(_blueprint);
|
||||
// if (blueprint == null)
|
||||
// return false;
|
||||
//
|
||||
// if (ItemUnderConstruction != Guid.Empty)
|
||||
// {
|
||||
// Entity.IncompleteCargo[ItemUnderConstruction] =
|
||||
// Entity.IncompleteCargo[ItemUnderConstruction] - delta * (AssignedPopulation + _data.AutomationPoints) /
|
||||
// pow(lerp(blueprint.QualityFloor, 1, saturate(_currentProductionQuality)),
|
||||
// blueprint.ProductionExponent);
|
||||
//
|
||||
// if(Entity.IncompleteCargo[ItemUnderConstruction] < 0)
|
||||
// {
|
||||
// var item = Context.ItemData.Get<ItemInstance>(ItemUnderConstruction);
|
||||
// if (item is SimpleCommodity simpleCommodity)
|
||||
// Entity.AddCargo(simpleCommodity);
|
||||
// else if (item is CraftedItemInstance craftedItemInstance)
|
||||
// Entity.AddCargo(craftedItemInstance);
|
||||
// Entity.IncompleteCargo.Remove(ItemUnderConstruction);
|
||||
// ItemUnderConstruction = Guid.Empty;
|
||||
// foreach (var attribute in _data.ProductionProfile)
|
||||
// Entity.Personality[attribute.Key] = lerp(Entity.Personality[attribute.Key], attribute.Value,
|
||||
// Context.GameplaySettings.ProductionPersonalityLerp * ((float) AssignedPopulation / Entity.Population));
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// if (RetoolingTime > 0)
|
||||
// {
|
||||
// RetoolingTime -= delta;
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// if (_retooling)
|
||||
// {
|
||||
// _retooling = false;
|
||||
// }
|
||||
//
|
||||
// if (Active)
|
||||
// {
|
||||
// var profileDistance = 0f;
|
||||
// if (_data.ProductionProfile.Any())
|
||||
// profileDistance = _data.ProductionProfile.Sum(x => abs(x.Value - Entity.Personality[x.Key])) /
|
||||
// _data.ProductionProfile.Count;
|
||||
// var personalityQuality =
|
||||
// (_data.AutomationPoints * _data.AutomationQuality + AssignedPopulation * (1 - profileDistance)) /
|
||||
// (_data.AutomationPoints + AssignedPopulation);
|
||||
// ItemUnderConstruction = Entity.Build(blueprint,
|
||||
// blueprint.Quality *
|
||||
// pow(personalityQuality, blueprint.PersonalityExponent) *
|
||||
// pow(ProductionQuality, blueprint.QualityExponent) *
|
||||
// // Applying exponents to two random numbers and averaging them produces a range of interesting probability distributions for quality
|
||||
// (pow(Context.Random.NextFloat(), blueprint.RandomQualityExponent) +
|
||||
// pow(Context.Random.NextFloat(), blueprint.RandomQualityExponent)) / 2, ItemName);
|
||||
// }
|
||||
//
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// // TODO Update Factory Persistence
|
||||
// public PersistentBehaviorData Store()
|
||||
// {
|
||||
// return new FactoryPersistence
|
||||
// {
|
||||
// Blueprint = _blueprint,
|
||||
// RetoolingTime = RetoolingTime,
|
||||
// AssignedPopulation = AssignedPopulation,
|
||||
// ProductionQuality = ProductionQuality
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// public void Restore(PersistentBehaviorData data)
|
||||
// {
|
||||
// var factoryPersistence = data as FactoryPersistence;
|
||||
// _blueprint = factoryPersistence.Blueprint;
|
||||
// RetoolingTime = factoryPersistence.RetoolingTime;
|
||||
// AssignedPopulation = factoryPersistence.AssignedPopulation;
|
||||
// ProductionQuality = factoryPersistence.ProductionQuality;
|
||||
// }
|
||||
//
|
||||
// public Guid Build(BlueprintData blueprint, float quality, string name, bool direct = false)
|
||||
// {
|
||||
// if (direct)
|
||||
// {
|
||||
// if(blueprint.FactoryItem!=Guid.Empty)
|
||||
// throw new ArgumentException("Attempted to directly build a blueprint which requires a factory!");
|
||||
// var blueprintItem = Context.Cache.Get<GearData>(blueprint.Item);
|
||||
// if(blueprintItem == null)
|
||||
// throw new ArgumentException("Attempted to directly build a blueprint for a missing or incompatible item!");
|
||||
// }
|
||||
//
|
||||
// //var newItemID = Guid.Empty;
|
||||
//
|
||||
// // GetBlueprintIngredients will assign the output lists with the items matching the blueprint, and return false if they are not found
|
||||
// if (!GetBlueprintIngredients(blueprint, out var simpleIngredients, out var compoundIngredients))
|
||||
// return Guid.Empty;
|
||||
//
|
||||
// // These will be bundled with the data for the compound commodity instance
|
||||
// var ingredients = new List<ItemInstance>();
|
||||
// ingredients.AddRange(compoundIngredients.Select(RemoveCargo));
|
||||
// ingredients.AddRange(simpleIngredients.Select(sc => RemoveCargo(sc, blueprint.Ingredients[sc.Data])));
|
||||
//
|
||||
// var blueprintItemData = Context.Cache.Get(blueprint.Item);
|
||||
//
|
||||
// // Creating new crafted item instances is a bit more complicated
|
||||
// if (blueprintItemData is CraftedItemData)
|
||||
// {
|
||||
// CraftedItemInstance newItem;
|
||||
//
|
||||
// if (blueprintItemData is EquippableItemData equippableItemData)
|
||||
// {
|
||||
// var newGear = new EquippableItem
|
||||
// {
|
||||
// Context = Context,
|
||||
// Data = blueprintItemData.ID,
|
||||
// Ingredients = ingredients.Select(ii=>ii.ID).ToList(),
|
||||
// Quality = quality,
|
||||
// Blueprint = blueprint.ID,
|
||||
// Name = name,
|
||||
// SourceEntity = ID
|
||||
// };
|
||||
// newGear.Durability = Context.Evaluate(equippableItemData.Durability, newGear);
|
||||
// newItem = newGear;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// newItem = new CompoundCommodity
|
||||
// {
|
||||
// Context = Context,
|
||||
// Data = blueprintItemData.ID,
|
||||
// Ingredients = ingredients.Select(ii=>ii.ID).ToList(),
|
||||
// Quality = quality,
|
||||
// Blueprint = blueprint.ID,
|
||||
// Name = name,
|
||||
// SourceEntity = ID
|
||||
// };
|
||||
// }
|
||||
// Context.Cache.Add(newItem);
|
||||
// if (direct)
|
||||
// IncompleteGear[newItem.ID] = blueprint.ProductionTime;
|
||||
// else
|
||||
// IncompleteCargo[newItem.ID] = blueprint.ProductionTime;
|
||||
// return newItem.ID;
|
||||
// }
|
||||
//
|
||||
// var newSimpleCommodity = new SimpleCommodity
|
||||
// {
|
||||
// Context = Context,
|
||||
// Data = blueprintItemData.ID,
|
||||
// Quantity = 1
|
||||
// };
|
||||
// Context.Cache.Add(newSimpleCommodity);
|
||||
// IncompleteCargo[newSimpleCommodity.ID] = blueprint.ProductionTime;
|
||||
// return newSimpleCommodity.ID;
|
||||
// }
|
||||
//
|
||||
// public bool GetBlueprintIngredients(BlueprintData blueprint, out List<SimpleCommodity> simpleIngredients,
|
||||
// out List<CompoundCommodity> compoundIngredients)
|
||||
// {
|
||||
// simpleIngredients = new List<SimpleCommodity>();
|
||||
// compoundIngredients = new List<CompoundCommodity>();
|
||||
// var hasAllIngredients = true;
|
||||
// var cargoInstances = Cargo.Select(c => Context.Cache.Get<ItemInstance>(c));
|
||||
// foreach (var kvp in blueprint.Ingredients)
|
||||
// {
|
||||
// var itemData = Context.Cache.Get(kvp.Key);
|
||||
// if (itemData is SimpleCommodityData)
|
||||
// {
|
||||
// var matchingItem = cargoInstances.FirstOrDefault(ii =>
|
||||
// {
|
||||
// if (!(ii is SimpleCommodity simpleCommodity)) return false;
|
||||
// return simpleCommodity.Data == itemData.ID && simpleCommodity.Quantity >= kvp.Value;
|
||||
// }) as SimpleCommodity;
|
||||
// hasAllIngredients = hasAllIngredients && matchingItem != null;
|
||||
// if(matchingItem != null)
|
||||
// simpleIngredients.Add(matchingItem);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var matchingItems =
|
||||
// cargoInstances.Where(ii => (ii as CompoundCommodity)?.Data == itemData.ID).Cast<CompoundCommodity>().ToArray();
|
||||
// hasAllIngredients = hasAllIngredients && matchingItems.Length >= kvp.Value;
|
||||
// if(matchingItems.Length >= kvp.Value)
|
||||
// compoundIngredients.AddRange(matchingItems.Take(kvp.Value));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return hasAllIngredients;
|
||||
// }
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class FactoryPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("blueprint"), Key(0)] public Guid Blueprint;
|
||||
[JsonProperty("retoolingTime"), Key(2)] public double RetoolingTime;
|
||||
[JsonProperty("assignedPopulation"), Key(5)] public int AssignedPopulation;
|
||||
[JsonProperty("productionQuality"), Key(6)] public float ProductionQuality;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f6378c7d7a9be24c9830679aabe55ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -103,10 +103,13 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
|
|||
|
||||
private bool UseAmmo()
|
||||
{
|
||||
if (_data.AmmoType != Guid.Empty)
|
||||
if (_data.MagazineSize <= 1) return true;
|
||||
|
||||
if (_ammo > 0) _ammo--;
|
||||
else
|
||||
{
|
||||
if (_data.MagazineSize > 1 && _ammo > 0) _ammo--;
|
||||
else
|
||||
var hasAmmo = true;
|
||||
if (_data.AmmoType != Guid.Empty)
|
||||
{
|
||||
var cargo = Entity.FindItemInCargo(_data.AmmoType);
|
||||
if (cargo != null)
|
||||
|
|
@ -114,18 +117,18 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
|
|||
var item = cargo.ItemsOfType[_data.AmmoType][0];
|
||||
if (item is SimpleCommodity simpleCommodity)
|
||||
cargo.Remove(simpleCommodity, 1);
|
||||
|
||||
if(_data.MagazineSize > 1)
|
||||
{
|
||||
OnReloadBegin?.Invoke();
|
||||
_cooldown = 1;
|
||||
_coolingDown = true;
|
||||
_firing = false;
|
||||
}
|
||||
}
|
||||
_burstRemaining = 0;
|
||||
return false;
|
||||
else hasAmmo = false;
|
||||
}
|
||||
if(hasAmmo)
|
||||
{
|
||||
OnReloadBegin?.Invoke();
|
||||
_cooldown = 1;
|
||||
_coolingDown = true;
|
||||
_firing = false;
|
||||
}
|
||||
_burstRemaining = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -101,4 +101,14 @@ public enum StatModifierType
|
|||
{
|
||||
Constant,
|
||||
Multiplier
|
||||
}
|
||||
|
||||
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class StatReference
|
||||
{
|
||||
[InspectableType(typeof(BehaviorData)), JsonProperty("behavior"), Key(1)]
|
||||
public string Target;
|
||||
|
||||
[InspectableField, JsonProperty("stat"), Key(2)]
|
||||
public string Stat;
|
||||
}
|
||||
|
|
@ -19,7 +19,10 @@ public class ThrusterData : BehaviorData
|
|||
[InspectableField, JsonProperty("heat"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat Heat = new PerformanceStat();
|
||||
|
||||
[InspectablePrefab, JsonProperty("Particles"), Key(4)]
|
||||
[InspectableField, JsonProperty("energy"), Key(4), RuntimeInspectable]
|
||||
public PerformanceStat EnergyUsage = new PerformanceStat();
|
||||
|
||||
[InspectablePrefab, JsonProperty("Particles"), Key(5)]
|
||||
public string ParticlesPrefab;
|
||||
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
|
|
@ -66,13 +69,18 @@ public class Thruster : IAnalogBehavior
|
|||
|
||||
public bool Execute(float delta)
|
||||
{
|
||||
Thrust = Item.Evaluate(_data.Thrust);
|
||||
Entity.Velocity -= Entity.Direction.Rotate(Item.EquippableItem.Rotation) * _input * Thrust / Entity.Mass * delta;
|
||||
Entity.Direction = mul(Entity.Direction, Unity.Mathematics.float2x2.Rotate(_input * Torque * Thrust * Context.GameplaySettings.TorqueMultiplier / Entity.Mass * delta));
|
||||
Item.AddHeat(_input * Item.Evaluate(_data.Heat) * delta);
|
||||
var vis = _input * Item.Evaluate(_data.Visibility);
|
||||
if(!Entity.VisibilitySources.ContainsKey(this) || vis > Entity.VisibilitySources[this])
|
||||
Entity.VisibilitySources[this] = vis;
|
||||
return _input > .01f;
|
||||
if(_input > .01f && Item.Entity.TryConsumeEnergy(_input * Item.Evaluate(_data.EnergyUsage)))
|
||||
{
|
||||
Thrust = Item.Evaluate(_data.Thrust);
|
||||
Entity.Velocity -= Entity.Direction.Rotate(Item.EquippableItem.Rotation) * _input * Thrust / Entity.Mass * delta;
|
||||
Entity.Direction = mul(Entity.Direction,
|
||||
Unity.Mathematics.float2x2.Rotate(_input * Torque * Thrust * Context.GameplaySettings.TorqueMultiplier / Entity.Mass * delta));
|
||||
Item.AddHeat(_input * Item.Evaluate(_data.Heat) * delta);
|
||||
var vis = _input * Item.Evaluate(_data.Visibility);
|
||||
if (!Entity.VisibilitySources.ContainsKey(this) || vis > Entity.VisibilitySources[this])
|
||||
Entity.VisibilitySources[this] = vis;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[RethinkTable("Items"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class BlueprintData : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[InspectableField, JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[InspectableDatabaseLink(typeof(ItemData)), JsonProperty("ingredients"), Key(2)]
|
||||
public Dictionary<Guid, int> Ingredients = new Dictionary<Guid, int>();
|
||||
|
||||
[JsonProperty("item"), Key(3)]
|
||||
public Guid Item;
|
||||
|
||||
[InspectableField, JsonProperty("productionTime"), Key(4)]
|
||||
public float ProductionTime;
|
||||
|
||||
[InspectableField, JsonProperty("quality"), Key(5)]
|
||||
public float Quality;
|
||||
|
||||
[InspectableField, JsonProperty("qualityExponent"), Key(6)]
|
||||
public float QualityExponent = 1;
|
||||
|
||||
[InspectableField, JsonProperty("productionExponent"), Key(7)]
|
||||
public float ProductionExponent = 1;
|
||||
|
||||
[InspectableField, JsonProperty("randomExponent"), Key(8)]
|
||||
public float RandomQualityExponent = 1;
|
||||
|
||||
[InspectableField, JsonProperty("personalityExponent"), Key(9)]
|
||||
public float PersonalityExponent = 1;
|
||||
|
||||
[InspectableField, JsonProperty("qualityFloor"), Key(10)]
|
||||
public float QualityFloor = .25f;
|
||||
|
||||
[InspectableField, JsonProperty("statEffects"), Key(11)]
|
||||
public List<BlueprintStatEffect> StatEffects = new List<BlueprintStatEffect>();
|
||||
|
||||
[InspectableField, JsonProperty("researchTime"), Key(12)]
|
||||
public float ResearchTime;
|
||||
|
||||
[InspectableDatabaseLink(typeof(BlueprintData)), JsonProperty("researchDependencies"), Key(13)]
|
||||
public List<Guid> Dependencies = new List<Guid>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(CraftedItemData)), JsonProperty("factoryItem"), Key(14)]
|
||||
public Guid FactoryItem;
|
||||
|
||||
[InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("resourceRequirements"), Key(15)]
|
||||
public Dictionary<Guid, int> ResourceRequirements = new Dictionary<Guid, int>();
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class BlueprintStatEffect
|
||||
{
|
||||
[InspectableField, JsonProperty("ingredient"), Key(1)]
|
||||
public Guid Ingredient;
|
||||
|
||||
[InspectableField, JsonProperty("stat"), Key(2)]
|
||||
public StatReference StatReference = new StatReference();
|
||||
}
|
||||
|
||||
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class StatReference
|
||||
{
|
||||
[InspectableType(typeof(BehaviorData)), JsonProperty("behavior"), Key(1)]
|
||||
public string Target;
|
||||
|
||||
[InspectableField, JsonProperty("stat"), Key(2)]
|
||||
public string Stat;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f2b1f367d240824408eb1e151c60bc79
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -25,7 +25,6 @@ public interface INamedEntry
|
|||
Union(4, typeof(SimpleCommodity)),
|
||||
Union(5, typeof(CompoundCommodity)),
|
||||
Union(6, typeof(EquippableItem)),
|
||||
Union(7, typeof(BlueprintData)),
|
||||
Union(8, typeof(GalaxyMapLayerData)),
|
||||
Union(9, typeof(NameFile)),
|
||||
//Union(10, typeof(ZoneData)),
|
||||
|
|
@ -37,7 +36,7 @@ public interface INamedEntry
|
|||
Union(16, typeof(BodyData)),
|
||||
Union(17, typeof(PersonalityAttribute)),
|
||||
Union(18, typeof(AgentTask)),
|
||||
Union(19, typeof(LoadoutData)),
|
||||
// Union(19, typeof(LoadoutData)),
|
||||
Union(20, typeof(Ship)),
|
||||
Union(21, typeof(Mining)),
|
||||
Union(22, typeof(StationTowing)),
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ public abstract class Entity
|
|||
Zone = zone;
|
||||
Hull = hull;
|
||||
HullData = itemManager.GetData(hull) as HullData;
|
||||
Name = hull.Name;
|
||||
Name = HullData.Name;
|
||||
MapEntity();
|
||||
TriggerGroups = new (List<Weapon> triggers, List<EquippedItem> items)[itemManager.GameplaySettings.TriggerGroupCount];
|
||||
for(int i=0; i<itemManager.GameplaySettings.TriggerGroupCount; i++)
|
||||
|
|
@ -955,8 +955,14 @@ public class EquippedItem
|
|||
EquippableItem = item;
|
||||
Position = position;
|
||||
Conductivity = Data.Conductivity;
|
||||
ThermalExponent = ItemManager.Evaluate(Data.HeatExponent, EquippableItem);
|
||||
DurabilityExponent = ItemManager.Evaluate(Data.DurabilityExponent, EquippableItem);
|
||||
ThermalExponent = lerp(
|
||||
ItemManager.GameplaySettings.ThermalQualityMin,
|
||||
ItemManager.GameplaySettings.ThermalQualityMax,
|
||||
pow(item.Quality, ItemManager.GameplaySettings.ThermalQualityExponent));
|
||||
DurabilityExponent = lerp(
|
||||
ItemManager.GameplaySettings.DurabilityQualityMin,
|
||||
ItemManager.GameplaySettings.DurabilityQualityMax,
|
||||
pow(item.Quality, ItemManager.GameplaySettings.DurabilityQualityExponent));
|
||||
var hullData = itemManager.GetData(entity.Hull);
|
||||
InsetShape = hullData.Shape.Inset(Data.Shape, position, item.Rotation);
|
||||
|
||||
|
|
@ -989,13 +995,9 @@ public class EquippedItem
|
|||
|
||||
public float Evaluate(PerformanceStat stat)
|
||||
{
|
||||
var heat = 1f;
|
||||
if(stat.HeatDependent)
|
||||
heat = pow(ThermalPerformance, ThermalExponent * stat.HeatExponentMultiplier);
|
||||
var durability = 1f;
|
||||
if(stat.DurabilityDependent)
|
||||
durability = pow(DurabilityPerformance, DurabilityExponent);
|
||||
var quality = pow(ItemManager.Quality(stat, EquippableItem), stat.QualityExponent);
|
||||
var heat = pow(ThermalPerformance, ThermalExponent * stat.HeatExponentMultiplier);
|
||||
var durability = pow(DurabilityPerformance, DurabilityExponent * stat.DurabilityExponentMultiplier);
|
||||
var quality = pow(EquippableItem.Quality, stat.QualityExponent);
|
||||
|
||||
var scaleModifier = 1.0f;
|
||||
foreach (var value in stat.GetScaleModifiers(Entity).Values) scaleModifier = scaleModifier * value;
|
||||
|
|
@ -1025,7 +1027,7 @@ public class EquippedItem
|
|||
DurabilityPerformance = EquippableItem.Durability / Data.Durability;
|
||||
var performanceThreshold = Entity.Settings.ShutdownPerformance;
|
||||
Wear = (1 - pow(Data.Performance(temp),
|
||||
(1 - pow(ItemManager.CompoundQuality(EquippableItem), ItemManager.GameplaySettings.QualityWearExponent)) *
|
||||
(1 - pow(EquippableItem.Quality, ItemManager.GameplaySettings.QualityWearExponent)) *
|
||||
ItemManager.GameplaySettings.ThermalWearExponent)
|
||||
) * Data.Durability / Data.ThermalResilience;
|
||||
ThermalOnline.Value = ThermalPerformance > performanceThreshold || Entity.OverrideShutdown && EquippableItem.OverrideShutdown;
|
||||
|
|
|
|||
|
|
@ -316,11 +316,11 @@ public abstract class EquippableItemData : CraftedItemData
|
|||
[InspectableTemperature, JsonProperty("maxTemp"), Key(14)]
|
||||
public float MaximumTemperature;
|
||||
|
||||
[InspectableField, JsonProperty("durabilityExponent"), Key(15), SimplePerformanceStat]
|
||||
public PerformanceStat DurabilityExponent = new PerformanceStat();
|
||||
|
||||
[InspectableField, JsonProperty("heatExponent"), Key(16), SimplePerformanceStat]
|
||||
public PerformanceStat HeatExponent = new PerformanceStat();
|
||||
// [InspectableField, JsonProperty("durabilityExponent"), Key(15), SimplePerformanceStat]
|
||||
// public PerformanceStat DurabilityExponent = new PerformanceStat();
|
||||
//
|
||||
// [InspectableField, JsonProperty("heatExponent"), Key(16), SimplePerformanceStat]
|
||||
// public PerformanceStat HeatExponent = new PerformanceStat();
|
||||
|
||||
[InspectableAnimationCurve, JsonProperty("performanceCurve"), Key(17)]
|
||||
public float4[] HeatPerformanceCurve;
|
||||
|
|
@ -495,17 +495,14 @@ public class PerformanceStat
|
|||
|
||||
[JsonProperty("max"), Key(1)] public float Max;
|
||||
|
||||
[JsonProperty("durabilityDependent"), Key(2)]
|
||||
public bool DurabilityDependent;
|
||||
[JsonProperty("heatExponentMultiplier"), Key(2)]
|
||||
public float HeatExponentMultiplier;
|
||||
|
||||
[JsonProperty("qualityExponent"), Key(3)]
|
||||
[JsonProperty("durabilityExponentMultiplier"), Key(3)]
|
||||
public float DurabilityExponentMultiplier;
|
||||
|
||||
[JsonProperty("qualityExponent"), Key(4)]
|
||||
public float QualityExponent;
|
||||
|
||||
[JsonProperty("heatDependent"), Key(4)]
|
||||
public bool HeatDependent;
|
||||
|
||||
[JsonProperty("heatExponentMultiplier"), Key(5)]
|
||||
public float HeatExponentMultiplier = 1;
|
||||
|
||||
//[JsonProperty("id"), Key(5)] public Guid ID = Guid.NewGuid();
|
||||
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ public abstract class CraftedItemInstance : ItemInstance
|
|||
{
|
||||
[JsonProperty("quality"), Key(2)] public float Quality;
|
||||
|
||||
[JsonProperty("ingredients"), Key(3)] public List<ItemInstance> Ingredients = new List<ItemInstance>();
|
||||
//[JsonProperty("ingredients"), Key(3)] public List<ItemInstance> Ingredients = new List<ItemInstance>();
|
||||
|
||||
[JsonProperty("blueprint"), Key(4)] public Guid Blueprint;
|
||||
//[JsonProperty("blueprint"), Key(4)] public Guid Blueprint;
|
||||
|
||||
[JsonProperty("name"), Key(5)] public string Name;
|
||||
//[JsonProperty("name"), Key(3)] public string Name;
|
||||
|
||||
[JsonProperty("sourceEntity"), Key(6)] public Guid SourceEntity;
|
||||
//[JsonProperty("sourceEntity"), Key(4)] public Guid SourceEntity;
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ public class ItemManager
|
|||
|
||||
private Action<string> _logger;
|
||||
|
||||
private Dictionary<BlueprintStatEffect, PerformanceStat> AffectedStats =
|
||||
new Dictionary<BlueprintStatEffect, PerformanceStat>();
|
||||
|
||||
private double _time;
|
||||
private float _deltaTime;
|
||||
private Dictionary<Guid, Zone> _zones = new Dictionary<Guid, Zone>();
|
||||
|
|
@ -158,118 +155,20 @@ public class ItemManager
|
|||
return 0;
|
||||
}
|
||||
|
||||
public PerformanceStat GetAffectedStat(BlueprintData blueprint, BlueprintStatEffect effect)
|
||||
{
|
||||
// We've already cached this effect's stat, return it directly
|
||||
if (AffectedStats.ContainsKey(effect)) return AffectedStats[effect];
|
||||
|
||||
// Get the data for the item the blueprint is for, return null if not found or not equippable
|
||||
var blueprintItem = ItemData.Get<EquippableItemData>(blueprint.Item);
|
||||
if (blueprintItem == null)
|
||||
{
|
||||
_logger($"Attempted to get stat effect but Blueprint {blueprint.ID} is not for an equippable item!");
|
||||
return AffectedStats[effect] = null;
|
||||
}
|
||||
|
||||
// Get the first behavior of the type specified in the blueprint stat effect, return null if not found
|
||||
var effectObject = effect.StatReference.Target == blueprintItem.Name ? (object) blueprintItem :
|
||||
blueprintItem.Behaviors.FirstOrDefault(b => b.GetType().Name == effect.StatReference.Target);
|
||||
if (effectObject == null)
|
||||
{
|
||||
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but stat references missing behavior \"{effect.StatReference.Target}\"!");
|
||||
return AffectedStats[effect] = null;
|
||||
}
|
||||
|
||||
// Get the first field in the behavior matching the name specified in the stat effect, return null if not found
|
||||
var type = effectObject.GetType();
|
||||
var field = type.GetField(effect.StatReference.Stat);
|
||||
if (field == null)
|
||||
{
|
||||
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but object {effect.StatReference.Target} does not have a stat named \"{effect.StatReference.Stat}\"!");
|
||||
return AffectedStats[effect] = null;
|
||||
}
|
||||
|
||||
// Finally we've confirmed the stat effect is valid, return the affected stat
|
||||
return AffectedStats[effect] = field.GetValue(effectObject) as PerformanceStat;
|
||||
}
|
||||
|
||||
private readonly Dictionary<CraftedItemInstance, float> ItemQuality = new Dictionary<CraftedItemInstance, float>();
|
||||
|
||||
public float CompoundQuality(CraftedItemInstance item)
|
||||
{
|
||||
if (ItemQuality.ContainsKey(item)) return ItemQuality[item];
|
||||
|
||||
var quality = item.Quality;
|
||||
|
||||
var craftedIngredients = item.Ingredients.Where(i => i is CraftedItemInstance).ToArray();
|
||||
if (craftedIngredients.Length > 0)
|
||||
{
|
||||
var ingredientQualityWeight = ItemData.Get<CraftedItemData>(item.Data).IngredientQualityWeight;
|
||||
quality = quality * (1 - ingredientQualityWeight) +
|
||||
craftedIngredients.Cast<CraftedItemInstance>().Average(CompoundQuality) * ingredientQualityWeight;
|
||||
}
|
||||
|
||||
ItemQuality[item] = quality;
|
||||
|
||||
return ItemQuality[item];
|
||||
}
|
||||
|
||||
private readonly Dictionary<(PerformanceStat stat, EquippableItem item), float> StatQuality = new Dictionary<(PerformanceStat stat, EquippableItem item), float>();
|
||||
|
||||
// Determine quality of either the item itself or the specific ingredient this stat depends on
|
||||
public float Quality(PerformanceStat stat, EquippableItem item)
|
||||
{
|
||||
if (StatQuality.ContainsKey((stat, item)))
|
||||
return StatQuality[(stat, item)];
|
||||
|
||||
var quality = CalcQuality(stat, item);
|
||||
StatQuality[(stat, item)] = quality;
|
||||
return quality;
|
||||
}
|
||||
|
||||
private float CalcQuality(PerformanceStat stat, EquippableItem item)
|
||||
{
|
||||
var itemData = GetData(item);
|
||||
var blueprint = ItemData.Get<BlueprintData>(item.Blueprint);
|
||||
var activeEffects = blueprint.StatEffects.Where(x => GetAffectedStat(blueprint, x) == stat).ToArray();
|
||||
float quality;
|
||||
if (!activeEffects.Any())
|
||||
quality = CompoundQuality(item);
|
||||
else
|
||||
{
|
||||
var ingredients = item.Ingredients.Where(i => activeEffects.Any(e => e.Ingredient == i.Data)).ToArray();
|
||||
var distinctIngredients = ingredients.Select(i => i.Data).Distinct();
|
||||
if(distinctIngredients.Count() != activeEffects.Length)
|
||||
{
|
||||
_logger($"Item {itemData.Name} does not have the ingredients specified by the stat effects of its blueprint!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
foreach (var i in ingredients)
|
||||
{
|
||||
if (i is CraftedItemInstance ci)
|
||||
sum += CompoundQuality(ci);
|
||||
else _logger($"Blueprint stat effect for item {itemData.Name} specifies invalid (non crafted) ingredient!");
|
||||
}
|
||||
|
||||
quality = sum / ingredients.Length;
|
||||
}
|
||||
|
||||
return quality;
|
||||
}
|
||||
|
||||
// Returns stat when not equipped
|
||||
public float Evaluate(PerformanceStat stat, EquippableItem item)
|
||||
{
|
||||
var quality = pow(Quality(stat, item), stat.QualityExponent);
|
||||
|
||||
var result = lerp(stat.Min, stat.Max, quality);
|
||||
|
||||
if (float.IsNaN(result))
|
||||
return stat.Min;
|
||||
|
||||
var data = GetData(item);
|
||||
var quality = pow(item.Quality, stat.QualityExponent);
|
||||
var durabilityExponent = lerp(
|
||||
GameplaySettings.DurabilityQualityMin,
|
||||
GameplaySettings.DurabilityQualityMax,
|
||||
pow(item.Quality, GameplaySettings.DurabilityQualityExponent));
|
||||
var durability = pow(item.Durability / data.Durability, durabilityExponent * stat.DurabilityExponentMultiplier);
|
||||
var result = lerp(stat.Min, stat.Max, quality * durability);
|
||||
if (float.IsNaN(result)) throw new InvalidOperationException("Performance Stat evaluating as NaN: input data is invalid!");
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public int GetPrice(CraftedItemInstance item)
|
||||
|
|
@ -317,57 +216,10 @@ public class ItemManager
|
|||
{
|
||||
if (item == null)
|
||||
{
|
||||
_logger("Attempted to create crafted item instance using missing or incorrect item id!");
|
||||
_logger("Attempted to create crafted item instance using missing or incorrect item data!");
|
||||
return null;
|
||||
}
|
||||
|
||||
var blueprint = ItemData.GetAll<BlueprintData>().FirstOrDefault(b => b.Item == item.ID);
|
||||
if (blueprint == null)
|
||||
{
|
||||
_logger("Attempted to create crafted item instance which has no blueprint!");
|
||||
return null;
|
||||
}
|
||||
|
||||
bool invalidIngredientFound = false;
|
||||
ItemData invalidIngredient = null;
|
||||
var ingredients = new List<ItemInstance>();
|
||||
foreach (var ingredient in blueprint.Ingredients)
|
||||
{
|
||||
var itemData = ItemData.Get<ItemData>(ingredient.Key);
|
||||
if (itemData is SimpleCommodityData simpleIngredientData)
|
||||
{
|
||||
var itemInstance = CreateInstance(simpleIngredientData, ingredient.Value);
|
||||
if(itemInstance == null)
|
||||
{
|
||||
invalidIngredientFound = true;
|
||||
invalidIngredient = itemData;
|
||||
}
|
||||
else ingredients.Add(itemInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var craftedIngredientData = ItemData.Get<CraftedItemData>(ingredient.Key);
|
||||
for (int i = 0; i < ingredient.Value; i++)
|
||||
{
|
||||
var itemInstance = CreateInstance(craftedIngredientData);
|
||||
if (itemInstance == null)
|
||||
{
|
||||
invalidIngredientFound = true;
|
||||
invalidIngredient = itemData;
|
||||
break;
|
||||
}
|
||||
|
||||
ingredients.Add(itemInstance);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (invalidIngredientFound)
|
||||
{
|
||||
_logger($"Unable to create crafted item ingredient: {invalidIngredient?.Name??"null"} for item {item.Name}");
|
||||
}
|
||||
|
||||
var quality = Random.NextFloat();
|
||||
var tier = GameplaySettings.Tiers[0];
|
||||
foreach (var t in GameplaySettings.Tiers)
|
||||
|
|
@ -381,10 +233,7 @@ public class ItemManager
|
|||
var newGear = new EquippableItem
|
||||
{
|
||||
Data = item.ID,
|
||||
Ingredients = ingredients,
|
||||
Quality = tier.Quality,
|
||||
Blueprint = blueprint.ID,
|
||||
Name = $"{item.Name}"
|
||||
Quality = tier.Quality
|
||||
};
|
||||
newGear.Durability = equippableItemData.Durability;
|
||||
return newGear;
|
||||
|
|
@ -393,10 +242,7 @@ public class ItemManager
|
|||
var newCommodity = new CompoundCommodity
|
||||
{
|
||||
Data = item.ID,
|
||||
Ingredients = ingredients,
|
||||
Quality = tier.Quality,
|
||||
Blueprint = blueprint.ID,
|
||||
Name = $"{item.Name}"
|
||||
Quality = tier.Quality
|
||||
};
|
||||
return newCommodity;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class LoadoutData : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[InspectableField, JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[InspectableDatabaseLink(typeof(HullData)), JsonProperty("hull"), Key(2)]
|
||||
public Guid Hull;
|
||||
|
||||
[JsonProperty("items"), Key(3)]
|
||||
public List<Guid> Gear = new List<Guid>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("simpleCargo"), Key(4)]
|
||||
public Dictionary<Guid, int> SimpleCargo = new Dictionary<Guid, int>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(CraftedItemData)), JsonProperty("compoundCargo"), Key(5)]
|
||||
public Dictionary<Guid, int> CompoundCargo = new Dictionary<Guid, int>();
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 897e13bb0462456b800522cd213bf70d
|
||||
timeCreated: 1591829121
|
||||
|
|
@ -135,6 +135,12 @@ public class GameplaySettings
|
|||
public EntitySettings DefaultEntitySettings;
|
||||
public RarityTier[] Tiers;
|
||||
public ExponentialLerp QualityPriceModifier;
|
||||
public float DurabilityQualityExponent = 2;
|
||||
public float DurabilityQualityMin = 2;
|
||||
public float DurabilityQualityMax = .25f;
|
||||
public float ThermalQualityExponent = 2;
|
||||
public float ThermalQualityMin = 2;
|
||||
public float ThermalQualityMax = .25f;
|
||||
public float DefaultShutdownPerformance = .25f;
|
||||
public float SevereHeatstrokeRiskThreshold = .25f;
|
||||
public float WormholeDepth = 1000;
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ public class Ship : Entity
|
|||
{
|
||||
var exitLerp = (_wormholeAnimationProgress - ItemManager.GameplaySettings.WormholeExitCurveStart) /
|
||||
(1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
|
||||
exitLerp = AetheriaMath.Smoothstep(exitLerp); // Square the interpolation variable to produce curve with zero slope at start
|
||||
exitLerp = AetheriaMath.Smootherstep(exitLerp); // Square the interpolation variable to produce curve with zero slope at start
|
||||
Position.xz = _wormholePosition + normalize(_wormholeExitVelocity) * exitLerp * ItemManager.GameplaySettings.WormholeExitRadius;
|
||||
Rotation = quaternion.LookRotation(
|
||||
lerp(float3(0, 1, 0), forward, exitLerp),
|
||||
|
|
@ -326,7 +326,7 @@ public class Ship : Entity
|
|||
if (_wormholeAnimationProgress < 1 - ItemManager.GameplaySettings.WormholeExitCurveStart)
|
||||
{
|
||||
var enterLerp = _wormholeAnimationProgress / (1 - ItemManager.GameplaySettings.WormholeExitCurveStart);
|
||||
enterLerp = AetheriaMath.Smoothstep(enterLerp); // Square the interpolation variable to produce curve with zero slope at vertical
|
||||
enterLerp = AetheriaMath.Smootherstep(enterLerp); // Square the interpolation variable to produce curve with zero slope at vertical
|
||||
Position.xz = lerp(_wormholeEntryPosition, _wormholePosition, enterLerp);
|
||||
Rotation = quaternion.LookRotation(
|
||||
lerp(forward, float3(0, -1, 0), enterLerp),
|
||||
|
|
|
|||
Loading…
Reference in a new issue