diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md index c0dddae..443354e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Subsystem is a mod loader for _Homeworld: Deserts of Kharak_. It aims to have a safe, auditable and data-oriented design. -## Disclaimer +### Disclaimer Subsystem is currently in alpha. It may be extremely unstable, and it's not likely to provide useful debugging information. Use at your own risk, and please try to dig into logs on your own before reporting crashes or other odd behavior. @@ -41,10 +41,26 @@ Note that the keys (`Entities`, `UnitAttributes`, etc) are case-sensitive. The stats are reloaded at the beginning of every game, -## Multiplayer Notes +### Multiplayer Notes To use this in multiplayer, all players in the game **must** have the same version of Subsystem *and* the same `patch.json` file contents. If any player has different data, the game is liable to crash with a synchronization error. -## Modifiable Attributes +### Modifiable Attributes See https://github.com/Majiir/Subsystem/blob/master/Subsystem/UnitAttributesPatch.cs for a list of attributes that can be modified. + +### Serialization Notes + +* Some enums are marked with `[Flags]`. You must use a particular syntax in order to assign multiple flags. For example, to set a unit's `Class` to multiple values: + +```json +... +"UnitAttributes": { + "Class": "Hover, Carrier" +} +... +``` + +* Non-flags enums should be set as strings. (Example: `"HackableProperties": "InstantHackable"`) + +* `Fixed64` values are set as Numbers (equivalent to `double`) in JSON. This is technically a lossy conversion, but it will work well in most circumstances. diff --git a/Subsystem/AbilityAttributesPatch.cs b/Subsystem/AbilityAttributesPatch.cs new file mode 100644 index 0000000..835efad --- /dev/null +++ b/Subsystem/AbilityAttributesPatch.cs @@ -0,0 +1,27 @@ +using BBI.Game.Data; + +namespace Subsystem +{ + public class AbilityAttributesPatch + { + public AbilityClass? AbilityType { get; set; } + public AbilityTargetingType? TargetingType { get; set; } + public AbilityTargetAlignment? TargetAlignment { get; set; } + public UnitClass? AbilityMapTargetLayers { get; set; } + public GroundAutoTargetAlignmentType? GroundAutoTargetAlignment { get; set; } + public double? EdgeOfTargetShapeMinDistance { get; set; } + + public bool? CasterMovesToTarget { get; set; } + public AbilityGroupActivationType? GroupActivationType { get; set; } + public AbilityRemovedInMode? StartsRemovedInGameMode { get; set; } + public double? CooldownTimeSecs { get; set; } + public double? WarmupTimeSecs { get; set; } + public int? SharedCooldownChannel { get; set; } + public SkipCastOnArrivalConditions? SkipCastOnArrivalConditions { get; set; } + public bool? IsToggleable { get; set; } + public bool? CastOnDeath { get; set; } + + public int? Resource1Cost { get; set; } + public int? Resource2Cost { get; set; } + } +} diff --git a/Subsystem/AbilityAttributesWrapper.cs b/Subsystem/AbilityAttributesWrapper.cs new file mode 100644 index 0000000..47f9bad --- /dev/null +++ b/Subsystem/AbilityAttributesWrapper.cs @@ -0,0 +1,109 @@ +using BBI.Core; +using BBI.Core.Utility.FixedPoint; +using BBI.Game.Data; + +namespace Subsystem +{ + public class AbilityAttributesWrapper : NamedObjectBase, AbilityAttributes + { + public AbilityAttributesWrapper(AbilityAttributes other) : base(other.Name) + { + AbilityMapTargetLayers = other.AbilityMapTargetLayers; + AbilityType = other.AbilityType; + ActivationDependencies = other.ActivationDependencies; + AirSortie = other.AirSortie; + ApplyStatusEffect = other.ApplyStatusEffect; + Autocast = other.Autocast; + AutoToggleOffConditions = other.AutoToggleOffConditions; + CasterMovesToTarget = other.CasterMovesToTarget; + CastOnDeath = other.CastOnDeath; + ChainCasting = other.ChainCasting; + ChangeContext = other.ChangeContext; + Charges = other.Charges; + CooldownTimeSecs = other.CooldownTimeSecs; + Cost = other.Cost; + EdgeOfTargetShapeMinDistance = other.EdgeOfTargetShapeMinDistance; + GroundAutoTargetAlignment = other.GroundAutoTargetAlignment; + GroupActivationType = other.GroupActivationType; + IsToggleable = other.IsToggleable; + ModifyInventory = other.ModifyInventory; + ProduceUnit = other.ProduceUnit; + Repair = other.Repair; + ResearchDependencies = other.ResearchDependencies; + Salvage = other.Salvage; + SelfDestruct = other.SelfDestruct; + SharedCooldownChannel = other.SharedCooldownChannel; + SkipCastOnArrivalConditions = other.SkipCastOnArrivalConditions; + StartsRemovedInGameMode = other.StartsRemovedInGameMode; + TargetAlignment = other.TargetAlignment; + TargetHighlighting = other.TargetHighlighting; + TargetingType = other.TargetingType; + UseWeapon = other.UseWeapon; + WarmupTimeSecs = other.WarmupTimeSecs; + } + + public AbilityClass AbilityType { get; set; } + + public AbilityTargetingType TargetingType { get; set; } + + public AbilityTargetAlignment TargetAlignment { get; set; } + + public UnitClass AbilityMapTargetLayers { get; set; } + + public GroundAutoTargetAlignmentType GroundAutoTargetAlignment { get; set; } + + public Fixed64 EdgeOfTargetShapeMinDistance { get; set; } + + public TargetHighlightingAttributes TargetHighlighting { get; set; } + + public bool CasterMovesToTarget { get; set; } + + public AbilityGroupActivationType GroupActivationType { get; set; } + + public AbilityRemovedInMode StartsRemovedInGameMode { get; set; } + + public Fixed64 CooldownTimeSecs { get; set; } + + public Fixed64 WarmupTimeSecs { get; set; } + + public int SharedCooldownChannel { get; set; } + + public SkipCastOnArrivalConditions SkipCastOnArrivalConditions { get; set; } + + public bool IsToggleable { get; set; } + + public bool CastOnDeath { get; set; } + + public CostAttributes Cost { get; set; } + + public ChargeAttributes Charges { get; set; } + + public AutocastAttributes Autocast { get; set; } + + public ProduceUnitAttributes ProduceUnit { get; set; } + + public UseWeaponAttributes UseWeapon { get; set; } + + public ChangeContextAttributes ChangeContext { get; set; } + + public AirSortieAttributes AirSortie { get; set; } + + public SalvageAttributes Salvage { get; set; } + + public ApplyStatusEffectAttributes ApplyStatusEffect { get; set; } + + public RepairAttributes Repair { get; set; } + + public SelfDestructAttributes SelfDestruct { get; set; } + + public ModifyInventoryAttributes ModifyInventory { get; set; } + + public ResearchDependenciesAttributes ResearchDependencies { get; set; } + + public ActivationDependenciesAttributes ActivationDependencies { get; set; } + + public AutoToggleOffConditionsAttributes AutoToggleOffConditions { get; set; } + + public ChainCastingAttributes ChainCasting { get; set; } + } +} diff --git a/Subsystem/AttributeLoader.cs b/Subsystem/AttributeLoader.cs index 0022a63..9d35061 100644 --- a/Subsystem/AttributeLoader.cs +++ b/Subsystem/AttributeLoader.cs @@ -1,8 +1,10 @@ -using BBI.Core.Data; +using BBI.Core; +using BBI.Core.Data; using BBI.Core.Utility.FixedPoint; using BBI.Game.Data; using LitJson; using System.IO; +using System.Linq; using UnityEngine; namespace Subsystem @@ -28,10 +30,78 @@ public static void ApplyAttributesPatch(EntityTypeCollection entityTypeCollectio var entityType = entityTypeCollection.GetEntityType(entityTypeName); - var unitAttributes = entityType.Get(); + if (entityTypePatch.UnitAttributes != null) + { + var unitAttributes = entityType.Get(); + var unitAttributesWrapper = new UnitAttributesWrapper(unitAttributes); + + ApplyUnitAttributesPatch(entityTypePatch.UnitAttributes, unitAttributesWrapper); + + entityType.Replace(unitAttributes, unitAttributesWrapper); + } + + if (entityTypePatch.ResearchItemAttributes != null) + { + var researchItemAttributes = entityType.Get(); + var researchItemAttributesWrapper = new ResearchItemAttributesWrapper(researchItemAttributes); + + ApplyResearchItemAttributesPatch(entityTypePatch.ResearchItemAttributes, researchItemAttributesWrapper); + + entityType.Replace(researchItemAttributes, researchItemAttributesWrapper); + } + + foreach (var kvp2 in entityTypePatch.AbilityAttributes) + { + var abilityAttributesName = kvp2.Key; + var abilityAttributesPatch = kvp2.Value; + + var abilityAttributes = entityType.Get(abilityAttributesName); + var abilityAttributesWrapper = new AbilityAttributesWrapper(abilityAttributes); + + ApplyAbilityAttributesPatch(abilityAttributesPatch, abilityAttributesWrapper); + + entityType.Replace(abilityAttributes, abilityAttributesWrapper); + } + + foreach (var kvp2 in entityTypePatch.WeaponAttributes) + { + var weaponAttributesName = kvp2.Key; + var weaponAttributesPatch = kvp2.Value; + + var weaponAttributes = entityType.Get(weaponAttributesName); + var weaponAttributesWrapper = new WeaponAttributesWrapper(weaponAttributes); + + ApplyWeaponAttributesPatch(weaponAttributesPatch, weaponAttributesWrapper); + + entityType.Replace(weaponAttributes, weaponAttributesWrapper); + + rebindWeaponAttributes(entityType, weaponAttributesWrapper); + } + } + } + + private static void rebindWeaponAttributes(EntityTypeAttributes entityType, WeaponAttributesWrapper weaponAttributesWrapper) + { + var unitAttributes = entityType.Get(); + if (unitAttributes != null) + { var unitAttributesWrapper = new UnitAttributesWrapper(unitAttributes); - ApplyUnitAttributesPatch(entityTypePatch.UnitAttributes, unitAttributesWrapper); + var weaponLoadout = unitAttributesWrapper.WeaponLoadout.Select(weaponBinding => + new WeaponBinding( + weaponID: weaponBinding.WeaponID, + weaponBindingIndex: weaponBinding.WeaponBindingIndex, + weapon: weaponAttributesWrapper, + ammoID: weaponBinding.AmmoID, + turretIndex: weaponBinding.TurretIndex, + defaultTurretAngleOffsetRadians: weaponBinding.DefaultTurretAngleOffsetRadians, + disabledOnSpawn: weaponBinding.DisabledOnSpawn, + weaponOffsetFromUnitOrigin: weaponBinding.OffsetFromUnitCenterInLocalSpace, + showAmmoOnHUD: weaponBinding.ShowAmmoOnHUD + ) + ); + + unitAttributesWrapper.WeaponLoadout = weaponLoadout.ToArray(); entityType.Replace(unitAttributes, unitAttributesWrapper); } @@ -39,6 +109,8 @@ public static void ApplyAttributesPatch(EntityTypeCollection entityTypeCollectio public static void ApplyUnitAttributesPatch(UnitAttributesPatch unitAttributesPatch, UnitAttributesWrapper unitAttributesWrapper) { + if (unitAttributesPatch.Class.HasValue) { unitAttributesWrapper.Class = unitAttributesPatch.Class.Value; } + if (unitAttributesPatch.SelectionFlags.HasValue) { unitAttributesWrapper.SelectionFlags = unitAttributesPatch.SelectionFlags.Value; } if (unitAttributesPatch.MaxHealth.HasValue) { unitAttributesWrapper.MaxHealth = unitAttributesPatch.MaxHealth.Value; } if (unitAttributesPatch.Armour.HasValue) { unitAttributesWrapper.Armour = unitAttributesPatch.Armour.Value; } if (unitAttributesPatch.DamageReceivedMultiplier.HasValue) { unitAttributesWrapper.DamageReceivedMultiplier = Fixed64.UnsafeFromDouble(unitAttributesPatch.DamageReceivedMultiplier.Value); } @@ -50,6 +122,8 @@ public static void ApplyUnitAttributesPatch(UnitAttributesPatch unitAttributesPa if (unitAttributesPatch.LeashRange.HasValue) { unitAttributesWrapper.LeashRange = Fixed64.UnsafeFromDouble(unitAttributesPatch.LeashRange.Value); } if (unitAttributesPatch.AlertRange.HasValue) { unitAttributesWrapper.AlertRange = Fixed64.UnsafeFromDouble(unitAttributesPatch.AlertRange.Value); } if (unitAttributesPatch.RepairPickupRange.HasValue) { unitAttributesWrapper.RepairPickupRange = Fixed64.UnsafeFromDouble(unitAttributesPatch.RepairPickupRange.Value); } + if (unitAttributesPatch.UnitPositionReaggroConditions.HasValue) { unitAttributesWrapper.UnitPositionReaggroConditions = unitAttributesPatch.UnitPositionReaggroConditions.Value; } + if (unitAttributesPatch.LeashPositionReaggroConditions.HasValue) { unitAttributesWrapper.LeashPositionReaggroConditions = unitAttributesPatch.LeashPositionReaggroConditions.Value; } if (unitAttributesPatch.LeadPriority.HasValue) { unitAttributesWrapper.LeadPriority = unitAttributesPatch.LeadPriority.Value; } if (unitAttributesPatch.Selectable.HasValue) { unitAttributesWrapper.Selectable = unitAttributesPatch.Selectable.Value; } if (unitAttributesPatch.Controllable.HasValue) { unitAttributesWrapper.Controllable = unitAttributesPatch.Controllable.Value; } @@ -70,10 +144,98 @@ public static void ApplyUnitAttributesPatch(UnitAttributesPatch unitAttributesPa if (unitAttributesPatch.ProductionQueueDepth.HasValue) { unitAttributesWrapper.ProductionQueueDepth = unitAttributesPatch.ProductionQueueDepth.Value; } if (unitAttributesPatch.ShowProductionQueues.HasValue) { unitAttributesWrapper.ShowProductionQueues = unitAttributesPatch.ShowProductionQueues.Value; } if (unitAttributesPatch.NoTextNotifications.HasValue) { unitAttributesWrapper.NoTextNotifications = unitAttributesPatch.NoTextNotifications.Value; } + if (unitAttributesPatch.NotificationFlags.HasValue) { unitAttributesWrapper.NotificationFlags = unitAttributesPatch.NotificationFlags.Value; } if (unitAttributesPatch.FireRateDisplay.HasValue) { unitAttributesWrapper.FireRateDisplay = unitAttributesPatch.FireRateDisplay.Value; } if (unitAttributesPatch.PriorityAsTarget.HasValue) { unitAttributesWrapper.PriorityAsTarget = Fixed64.UnsafeFromDouble(unitAttributesPatch.PriorityAsTarget.Value); } + + unitAttributesWrapper.ThreatData = new ThreatData + { + BaseThreat = unitAttributesPatch.BaseThreat ?? unitAttributesWrapper.ThreatData.BaseThreat, + Tier = unitAttributesPatch.ThreatTier ?? unitAttributesWrapper.ThreatData.Tier, + }; + + if (unitAttributesPatch.ThreatCounters != null) { unitAttributesWrapper.ThreatCounters = unitAttributesPatch.ThreatCounters.Select(x => new ThreatCounter(x)); } + if (unitAttributesPatch.ThreatCounteredBys != null) { unitAttributesWrapper.ThreatCounteredBys = unitAttributesPatch.ThreatCounteredBys.Select(x => new ThreatCounter(x)); } + if (unitAttributesPatch.Resource1Cost.HasValue) { unitAttributesWrapper.Resource1Cost = unitAttributesPatch.Resource1Cost.Value; } if (unitAttributesPatch.Resource2Cost.HasValue) { unitAttributesWrapper.Resource2Cost = unitAttributesPatch.Resource2Cost.Value; } } + + public static void ApplyResearchItemAttributesPatch(ResearchItemAttributesPatch researchItemAttributesPatch, ResearchItemAttributesWrapper researchItemAttributesWrapper) + { + if (researchItemAttributesPatch.TypeOfResearch.HasValue) { researchItemAttributesWrapper.TypeOfResearch = researchItemAttributesPatch.TypeOfResearch.Value; } + if (researchItemAttributesPatch.IconSpriteName != null) { researchItemAttributesWrapper.IconSpriteName = researchItemAttributesPatch.IconSpriteName; } + if (researchItemAttributesPatch.LocalizedResearchTitleStringID != null) { researchItemAttributesWrapper.LocalizedResearchTitleStringID = researchItemAttributesPatch.LocalizedResearchTitleStringID; } + if (researchItemAttributesPatch.LocalizedShortDescriptionStringID != null) { researchItemAttributesWrapper.LocalizedShortDescriptionStringID = researchItemAttributesPatch.LocalizedShortDescriptionStringID; } + if (researchItemAttributesPatch.LocalizedLongDescriptionStringID != null) { researchItemAttributesWrapper.LocalizedLongDescriptionStringID = researchItemAttributesPatch.LocalizedLongDescriptionStringID; } + if (researchItemAttributesPatch.ResearchTime.HasValue) { researchItemAttributesWrapper.ResearchTime = Fixed64.UnsafeFromDouble(researchItemAttributesPatch.ResearchTime.Value); } + if (researchItemAttributesPatch.Dependencies != null) { researchItemAttributesWrapper.Dependencies = researchItemAttributesPatch.Dependencies; } + if (researchItemAttributesPatch.ResearchVOCode != null) { researchItemAttributesWrapper.ResearchVOCode = researchItemAttributesPatch.ResearchVOCode; } + if (researchItemAttributesPatch.Resource1Cost.HasValue) { researchItemAttributesWrapper.Resource1Cost = researchItemAttributesPatch.Resource1Cost.Value; } + if (researchItemAttributesPatch.Resource2Cost.HasValue) { researchItemAttributesWrapper.Resource2Cost = researchItemAttributesPatch.Resource2Cost.Value; } + } + + public static void ApplyAbilityAttributesPatch(AbilityAttributesPatch abilityAttributesPatch, AbilityAttributesWrapper abilityAttributesWrapper) + { + if (abilityAttributesPatch.AbilityType.HasValue) { abilityAttributesWrapper.AbilityType = abilityAttributesPatch.AbilityType.Value; } + if (abilityAttributesPatch.TargetingType.HasValue) { abilityAttributesWrapper.TargetingType = abilityAttributesPatch.TargetingType.Value; } + if (abilityAttributesPatch.TargetAlignment.HasValue) { abilityAttributesWrapper.TargetAlignment = abilityAttributesPatch.TargetAlignment.Value; } + if (abilityAttributesPatch.AbilityMapTargetLayers.HasValue) { abilityAttributesWrapper.AbilityMapTargetLayers = abilityAttributesPatch.AbilityMapTargetLayers.Value; } + if (abilityAttributesPatch.GroundAutoTargetAlignment.HasValue) { abilityAttributesWrapper.GroundAutoTargetAlignment = abilityAttributesPatch.GroundAutoTargetAlignment.Value; } + if (abilityAttributesPatch.EdgeOfTargetShapeMinDistance.HasValue) { abilityAttributesWrapper.EdgeOfTargetShapeMinDistance = Fixed64.UnsafeFromDouble(abilityAttributesPatch.EdgeOfTargetShapeMinDistance.Value); } + if (abilityAttributesPatch.CasterMovesToTarget.HasValue) { abilityAttributesWrapper.CasterMovesToTarget = abilityAttributesPatch.CasterMovesToTarget.Value; } + if (abilityAttributesPatch.GroupActivationType.HasValue) { abilityAttributesWrapper.GroupActivationType = abilityAttributesPatch.GroupActivationType.Value; } + if (abilityAttributesPatch.StartsRemovedInGameMode.HasValue) { abilityAttributesWrapper.StartsRemovedInGameMode = abilityAttributesPatch.StartsRemovedInGameMode.Value; } + if (abilityAttributesPatch.CooldownTimeSecs.HasValue) { abilityAttributesWrapper.CooldownTimeSecs = Fixed64.UnsafeFromDouble(abilityAttributesPatch.CooldownTimeSecs.Value); } + if (abilityAttributesPatch.WarmupTimeSecs.HasValue) { abilityAttributesWrapper.WarmupTimeSecs = Fixed64.UnsafeFromDouble(abilityAttributesPatch.WarmupTimeSecs.Value); } + if (abilityAttributesPatch.SharedCooldownChannel.HasValue) { abilityAttributesWrapper.SharedCooldownChannel = abilityAttributesPatch.SharedCooldownChannel.Value; } + if (abilityAttributesPatch.SkipCastOnArrivalConditions.HasValue) { abilityAttributesWrapper.SkipCastOnArrivalConditions = abilityAttributesPatch.SkipCastOnArrivalConditions.Value; } + if (abilityAttributesPatch.IsToggleable.HasValue) { abilityAttributesWrapper.IsToggleable = abilityAttributesPatch.IsToggleable.Value; } + if (abilityAttributesPatch.CastOnDeath.HasValue) { abilityAttributesWrapper.CastOnDeath = abilityAttributesPatch.CastOnDeath.Value; } + + var cost = new CostAttributesWrapper(abilityAttributesWrapper.Cost); + abilityAttributesWrapper.Cost = cost; + + if (abilityAttributesPatch.Resource1Cost.HasValue) { cost.Resource1Cost = abilityAttributesPatch.Resource1Cost.Value; } + if (abilityAttributesPatch.Resource2Cost.HasValue) { cost.Resource2Cost = abilityAttributesPatch.Resource2Cost.Value; } + } + + public static void ApplyWeaponAttributesPatch(WeaponAttributesPatch weaponAttributesPatch, WeaponAttributesWrapper weaponAttributesWrapper) + { + if (weaponAttributesPatch.ExcludeFromAutoTargetAcquisition.HasValue) { weaponAttributesWrapper.ExcludeFromAutoTargetAcquisition = weaponAttributesPatch.ExcludeFromAutoTargetAcquisition.Value; } + if (weaponAttributesPatch.ExcludeFromAutoFire.HasValue) { weaponAttributesWrapper.ExcludeFromAutoFire = weaponAttributesPatch.ExcludeFromAutoFire.Value; } + if (weaponAttributesPatch.ExcludeFromHeightAdvantage.HasValue) { weaponAttributesWrapper.ExcludeFromHeightAdvantage = weaponAttributesPatch.ExcludeFromHeightAdvantage.Value; } + if (weaponAttributesPatch.DamageType.HasValue) { weaponAttributesWrapper.DamageType = weaponAttributesPatch.DamageType.Value; } + if (weaponAttributesPatch.IsTracer.HasValue) { weaponAttributesWrapper.IsTracer = weaponAttributesPatch.IsTracer.Value; } + if (weaponAttributesPatch.TracerSpeed.HasValue) { weaponAttributesWrapper.TracerSpeed = Fixed64.UnsafeFromDouble(weaponAttributesPatch.TracerSpeed.Value); } + if (weaponAttributesPatch.TracerLength.HasValue) { weaponAttributesWrapper.TracerLength = Fixed64.UnsafeFromDouble(weaponAttributesPatch.TracerLength.Value); } + if (weaponAttributesPatch.BaseDamagePerRound.HasValue) { weaponAttributesWrapper.BaseDamagePerRound = Fixed64.UnsafeFromDouble(weaponAttributesPatch.BaseDamagePerRound.Value); } + if (weaponAttributesPatch.BaseWreckDamagePerRound.HasValue) { weaponAttributesWrapper.BaseWreckDamagePerRound = Fixed64.UnsafeFromDouble(weaponAttributesPatch.BaseWreckDamagePerRound.Value); } + if (weaponAttributesPatch.FiringRecoil.HasValue) { weaponAttributesWrapper.FiringRecoil = weaponAttributesPatch.FiringRecoil.Value; } + if (weaponAttributesPatch.WindUpTimeMS.HasValue) { weaponAttributesWrapper.WindUpTimeMS = weaponAttributesPatch.WindUpTimeMS.Value; } + if (weaponAttributesPatch.RateOfFire.HasValue) { weaponAttributesWrapper.RateOfFire = weaponAttributesPatch.RateOfFire.Value; } + if (weaponAttributesPatch.NumberOfBursts.HasValue) { weaponAttributesWrapper.NumberOfBursts = weaponAttributesPatch.NumberOfBursts.Value; } + if (weaponAttributesPatch.DamagePacketsPerShot.HasValue) { weaponAttributesWrapper.DamagePacketsPerShot = weaponAttributesPatch.DamagePacketsPerShot.Value; } + if (weaponAttributesPatch.BurstPeriodMinTimeMS.HasValue) { weaponAttributesWrapper.BurstPeriodMinTimeMS = weaponAttributesPatch.BurstPeriodMinTimeMS.Value; } + if (weaponAttributesPatch.BurstPeriodMaxTimeMS.HasValue) { weaponAttributesWrapper.BurstPeriodMaxTimeMS = weaponAttributesPatch.BurstPeriodMaxTimeMS.Value; } + if (weaponAttributesPatch.CooldownTimeMS.HasValue) { weaponAttributesWrapper.CooldownTimeMS = weaponAttributesPatch.CooldownTimeMS.Value; } + if (weaponAttributesPatch.WindDownTimeMS.HasValue) { weaponAttributesWrapper.WindDownTimeMS = weaponAttributesPatch.WindDownTimeMS.Value; } + if (weaponAttributesPatch.ReloadTimeMS.HasValue) { weaponAttributesWrapper.ReloadTimeMS = weaponAttributesPatch.ReloadTimeMS.Value; } + if (weaponAttributesPatch.LineOfSightRequired.HasValue) { weaponAttributesWrapper.LineOfSightRequired = weaponAttributesPatch.LineOfSightRequired.Value; } + if (weaponAttributesPatch.LeadsTarget.HasValue) { weaponAttributesWrapper.LeadsTarget = weaponAttributesPatch.LeadsTarget.Value; } + if (weaponAttributesPatch.KillSkipsUnitDeathSequence.HasValue) { weaponAttributesWrapper.KillSkipsUnitDeathSequence = weaponAttributesPatch.KillSkipsUnitDeathSequence.Value; } + if (weaponAttributesPatch.RevealTriggers.HasValue) { weaponAttributesWrapper.RevealTriggers = weaponAttributesPatch.RevealTriggers.Value; } + if (weaponAttributesPatch.UnitStatusAttackingTriggers.HasValue) { weaponAttributesWrapper.UnitStatusAttackingTriggers = weaponAttributesPatch.UnitStatusAttackingTriggers.Value; } + if (weaponAttributesPatch.TargetStyle.HasValue) { weaponAttributesWrapper.TargetStyle = weaponAttributesPatch.TargetStyle.Value; } + if (weaponAttributesPatch.AreaOfEffectFalloffType.HasValue) { weaponAttributesWrapper.AreaOfEffectFalloffType = weaponAttributesPatch.AreaOfEffectFalloffType.Value; } + if (weaponAttributesPatch.AreaOfEffectRadius.HasValue) { weaponAttributesWrapper.AreaOfEffectRadius = Fixed64.UnsafeFromDouble(weaponAttributesPatch.AreaOfEffectRadius.Value); } + if (weaponAttributesPatch.ExcludeWeaponOwnerFromAreaOfEffect.HasValue) { weaponAttributesWrapper.ExcludeWeaponOwnerFromAreaOfEffect = weaponAttributesPatch.ExcludeWeaponOwnerFromAreaOfEffect.Value; } + if (weaponAttributesPatch.FriendlyFireDamageScalar.HasValue) { weaponAttributesWrapper.FriendlyFireDamageScalar = Fixed64.UnsafeFromDouble(weaponAttributesPatch.FriendlyFireDamageScalar.Value); } + if (weaponAttributesPatch.WeaponOwnerFriendlyFireDamageScalar.HasValue) { weaponAttributesWrapper.WeaponOwnerFriendlyFireDamageScalar = Fixed64.UnsafeFromDouble(weaponAttributesPatch.WeaponOwnerFriendlyFireDamageScalar.Value); } + if (weaponAttributesPatch.ProjectileEntityTypeToSpawn != null) { weaponAttributesWrapper.ProjectileEntityTypeToSpawn = weaponAttributesPatch.ProjectileEntityTypeToSpawn; } + if (weaponAttributesPatch.StatusEffectsTargetAlignment.HasValue) { weaponAttributesWrapper.StatusEffectsTargetAlignment = weaponAttributesPatch.StatusEffectsTargetAlignment.Value; } + if (weaponAttributesPatch.StatusEffectsExcludeTargetType.HasValue) { weaponAttributesWrapper.StatusEffectsExcludeTargetType = weaponAttributesPatch.StatusEffectsExcludeTargetType.Value; } + if (weaponAttributesPatch.ActiveStatusEffectsIndex.HasValue) { weaponAttributesWrapper.ActiveStatusEffectsIndex = weaponAttributesPatch.ActiveStatusEffectsIndex.Value; } + } } } diff --git a/Subsystem/CostAttributesWrapper.cs b/Subsystem/CostAttributesWrapper.cs new file mode 100644 index 0000000..6350221 --- /dev/null +++ b/Subsystem/CostAttributesWrapper.cs @@ -0,0 +1,17 @@ +using BBI.Game.Data; + +namespace Subsystem +{ + public class CostAttributesWrapper : CostAttributes + { + public CostAttributesWrapper(CostAttributes other) + { + Resource1Cost = other.Resource1Cost; + Resource2Cost = other.Resource2Cost; + } + + public int Resource1Cost { get; set; } + + public int Resource2Cost { get; set; } + } +} diff --git a/Subsystem/EntityTypePatch.cs b/Subsystem/EntityTypePatch.cs index 8f81a52..d3dcad0 100644 --- a/Subsystem/EntityTypePatch.cs +++ b/Subsystem/EntityTypePatch.cs @@ -1,7 +1,12 @@ -namespace Subsystem +using System.Collections.Generic; + +namespace Subsystem { public class EntityTypePatch { - public UnitAttributesPatch UnitAttributes { get; set; } = new UnitAttributesPatch(); + public UnitAttributesPatch UnitAttributes { get; set; } + public ResearchItemAttributesPatch ResearchItemAttributes { get; set; } + public Dictionary AbilityAttributes { get; set; } = new Dictionary(); + public Dictionary WeaponAttributes { get; set; } = new Dictionary(); } } diff --git a/Subsystem/Properties/AssemblyInfo.cs b/Subsystem/Properties/AssemblyInfo.cs index 24372e0..2c8d5f5 100644 --- a/Subsystem/Properties/AssemblyInfo.cs +++ b/Subsystem/Properties/AssemblyInfo.cs @@ -34,4 +34,4 @@ // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: AssemblyInformationalVersion("0.1.0")] +[assembly: AssemblyInformationalVersion("0.2.0")] diff --git a/Subsystem/ResearchItemAttributesPatch.cs b/Subsystem/ResearchItemAttributesPatch.cs new file mode 100644 index 0000000..f326f48 --- /dev/null +++ b/Subsystem/ResearchItemAttributesPatch.cs @@ -0,0 +1,19 @@ +using BBI.Game.Data; + +namespace Subsystem +{ + public class ResearchItemAttributesPatch + { + public ResearchType? TypeOfResearch { get; set; } + public string IconSpriteName { get; set; } + public string LocalizedResearchTitleStringID { get; set; } + public string LocalizedShortDescriptionStringID { get; set; } + public string LocalizedLongDescriptionStringID { get; set; } + public double? ResearchTime { get; set; } + public string[] Dependencies { get; set; } + public string ResearchVOCode { get; set; } + + public int? Resource1Cost { get; set; } + public int? Resource2Cost { get; set; } + } +} diff --git a/Subsystem/ResearchItemAttributesWrapper.cs b/Subsystem/ResearchItemAttributesWrapper.cs new file mode 100644 index 0000000..18b54d9 --- /dev/null +++ b/Subsystem/ResearchItemAttributesWrapper.cs @@ -0,0 +1,49 @@ +using BBI.Core; +using BBI.Core.Utility.FixedPoint; +using BBI.Game.Data; + +namespace Subsystem +{ + public class ResearchItemAttributesWrapper : NamedObjectBase, ResearchItemAttributes + { + public ResearchItemAttributesWrapper(ResearchItemAttributes other) : base(other.Name) + { + TypeOfResearch = other.TypeOfResearch; + IconSpriteName = other.IconSpriteName; + LocalizedResearchTitleStringID = other.LocalizedResearchTitleStringID; + LocalizedShortDescriptionStringID = other.LocalizedShortDescriptionStringID; + LocalizedLongDescriptionStringID = other.LocalizedLongDescriptionStringID; + ResearchTime = other.ResearchTime; + Dependencies = other.Dependencies; + ResearchVOCode = other.ResearchVOCode; + UnitTypeBuffs = other.UnitTypeBuffs; + CommandsToRun = other.CommandsToRun; + Resource1Cost = other.Resource1Cost; + Resource2Cost = other.Resource2Cost; + } + + public ResearchType TypeOfResearch { get; set; } + + public string IconSpriteName { get; set; } + + public string LocalizedResearchTitleStringID { get; set; } + + public string LocalizedShortDescriptionStringID { get; set; } + + public string LocalizedLongDescriptionStringID { get; set; } + + public Fixed64 ResearchTime { get; set; } + + public string[] Dependencies { get; set; } + + public string ResearchVOCode { get; set; } + + public UnitTypeBuff[] UnitTypeBuffs { get; set; } + + public CommandAttributesBase[] CommandsToRun { get; set; } + + public int Resource1Cost { get; set; } + + public int Resource2Cost { get; set; } + } +} diff --git a/Subsystem/Subsystem.csproj b/Subsystem/Subsystem.csproj index 6b75aeb..09c291b 100644 --- a/Subsystem/Subsystem.csproj +++ b/Subsystem/Subsystem.csproj @@ -43,12 +43,19 @@ + + + + + + + \ No newline at end of file diff --git a/Subsystem/UnitAttributesPatch.cs b/Subsystem/UnitAttributesPatch.cs index 77fe612..c4f9ffe 100644 --- a/Subsystem/UnitAttributesPatch.cs +++ b/Subsystem/UnitAttributesPatch.cs @@ -4,6 +4,9 @@ namespace Subsystem { public class UnitAttributesPatch { + public UnitClass? Class { get; set; } + public UnitSelectionFlags? SelectionFlags { get; set; } + public int? MaxHealth { get; set; } public int? Armour { get; set; } @@ -17,6 +20,9 @@ public class UnitAttributesPatch public double? AlertRange { get; set; } public double? RepairPickupRange { get; set; } + public UnitPositionReaggroConditions? UnitPositionReaggroConditions { get; set; } + public LeashPositionReaggroConditions? LeashPositionReaggroConditions { get; set; } + public int? LeadPriority { get; set; } public bool? Selectable { get; set; } public bool? Controllable { get; set; } @@ -24,7 +30,9 @@ public class UnitAttributesPatch public bool? NonAutoTargetable { get; set; } public bool? RetireTargetable { get; set; } public bool? HackedReturnTargetable { get; set; } + public HackableProperties? HackableProperties { get; set; } + public bool? ExcludeFromUnitStats { get; set; } public bool? BlocksLOF { get; set; } public double? WorldHeightOffset { get; set; } @@ -38,10 +46,18 @@ public class UnitAttributesPatch public bool? ShowProductionQueues { get; set; } public bool? NoTextNotifications { get; set; } + public UnitNotificationFlags? NotificationFlags { get; set; } + public int? FireRateDisplay { get; set; } public double? PriorityAsTarget { get; set; } + public int? BaseThreat { get; set; } + public int? ThreatTier { get; set; } + + public string[] ThreatCounters { get; set; } + public string[] ThreatCounteredBys { get; set; } + public int? Resource1Cost { get; set; } public int? Resource2Cost { get; set; } } diff --git a/Subsystem/WeaponAttributesPatch.cs b/Subsystem/WeaponAttributesPatch.cs new file mode 100644 index 0000000..5f01838 --- /dev/null +++ b/Subsystem/WeaponAttributesPatch.cs @@ -0,0 +1,41 @@ +using BBI.Game.Data; +namespace Subsystem +{ + public class WeaponAttributesPatch + { + public bool? ExcludeFromAutoTargetAcquisition { get; set; } + public bool? ExcludeFromAutoFire { get; set; } + public bool? ExcludeFromHeightAdvantage { get; set; } + public DamageType? DamageType { get; set; } + public bool? IsTracer { get; set; } + public double? TracerSpeed { get; set; } + public double? TracerLength { get; set; } + public double? BaseDamagePerRound { get; set; } + public double? BaseWreckDamagePerRound { get; set; } + public float? FiringRecoil { get; set; } + public int? WindUpTimeMS { get; set; } + public int? RateOfFire { get; set; } + public int? NumberOfBursts { get; set; } + public int? DamagePacketsPerShot { get; set; } + public int? BurstPeriodMinTimeMS { get; set; } + public int? BurstPeriodMaxTimeMS { get; set; } + public int? CooldownTimeMS { get; set; } + public int? WindDownTimeMS { get; set; } + public int? ReloadTimeMS { get; set; } + public bool? LineOfSightRequired { get; set; } + public TargetAimingType? LeadsTarget { get; set; } + public bool? KillSkipsUnitDeathSequence { get; set; } + public RevealTrigger? RevealTriggers { get; set; } + public UnitStatusAttackingTrigger? UnitStatusAttackingTriggers { get; set; } + public WeaponTargetStyle? TargetStyle { get; set; } + public AOEFalloffType? AreaOfEffectFalloffType { get; set; } + public double? AreaOfEffectRadius { get; set; } + public bool? ExcludeWeaponOwnerFromAreaOfEffect { get; set; } + public double? FriendlyFireDamageScalar { get; set; } + public double? WeaponOwnerFriendlyFireDamageScalar { get; set; } + public string ProjectileEntityTypeToSpawn { get; set; } + public AbilityTargetAlignment? StatusEffectsTargetAlignment { get; set; } + public UnitClass? StatusEffectsExcludeTargetType { get; set; } + public int? ActiveStatusEffectsIndex { get; set; } + } +} diff --git a/Subsystem/WeaponAttributesWrapper.cs b/Subsystem/WeaponAttributesWrapper.cs new file mode 100644 index 0000000..fa311c0 --- /dev/null +++ b/Subsystem/WeaponAttributesWrapper.cs @@ -0,0 +1,133 @@ +using BBI.Core; +using BBI.Core.Utility.FixedPoint; +using BBI.Game.Data; + +namespace Subsystem +{ + public class WeaponAttributesWrapper : NamedObjectBase, WeaponAttributes + { + public WeaponAttributesWrapper(WeaponAttributes other) : base(other.Name) + { + ExcludeFromAutoTargetAcquisition = other.ExcludeFromAutoTargetAcquisition; + ExcludeFromAutoFire = other.ExcludeFromAutoFire; + ExcludeFromHeightAdvantage = other.ExcludeFromHeightAdvantage; + DamageType = other.DamageType; + IsTracer = other.IsTracer; + TracerSpeed = other.TracerSpeed; + TracerLength = other.TracerLength; + BaseDamagePerRound = other.BaseDamagePerRound; + BaseWreckDamagePerRound = other.BaseWreckDamagePerRound; + FiringRecoil = other.FiringRecoil; + WindUpTimeMS = other.WindUpTimeMS; + RateOfFire = other.RateOfFire; + NumberOfBursts = other.NumberOfBursts; + DamagePacketsPerShot = other.DamagePacketsPerShot; + BurstPeriodMinTimeMS = other.BurstPeriodMinTimeMS; + BurstPeriodMaxTimeMS = other.BurstPeriodMaxTimeMS; + CooldownTimeMS = other.CooldownTimeMS; + WindDownTimeMS = other.WindDownTimeMS; + ReloadTimeMS = other.ReloadTimeMS; + LineOfSightRequired = other.LineOfSightRequired; + LeadsTarget = other.LeadsTarget; + KillSkipsUnitDeathSequence = other.KillSkipsUnitDeathSequence; + RevealTriggers = other.RevealTriggers; + UnitStatusAttackingTriggers = other.UnitStatusAttackingTriggers; + TargetStyle = other.TargetStyle; + Modifiers = other.Modifiers; + AreaOfEffectFalloffType = other.AreaOfEffectFalloffType; + AreaOfEffectRadius = other.AreaOfEffectRadius; + ExcludeWeaponOwnerFromAreaOfEffect = other.ExcludeWeaponOwnerFromAreaOfEffect; + FriendlyFireDamageScalar = other.FriendlyFireDamageScalar; + WeaponOwnerFriendlyFireDamageScalar = other.WeaponOwnerFriendlyFireDamageScalar; + Turret = other.Turret; + Ranges = other.Ranges; + ProjectileEntityTypeToSpawn = other.ProjectileEntityTypeToSpawn; + StatusEffectsTargetAlignment = other.StatusEffectsTargetAlignment; + StatusEffectsExcludeTargetType = other.StatusEffectsExcludeTargetType; + ActiveStatusEffectsIndex = other.ActiveStatusEffectsIndex; + StatusEffectsSets = other.StatusEffectsSets; + EntityTypesToSpawnOnImpact = other.EntityTypesToSpawnOnImpact; + TargetPriorizationAttributes = other.TargetPriorizationAttributes; + } + + public bool ExcludeFromAutoTargetAcquisition { get; set; } + + public bool ExcludeFromAutoFire { get; set; } + + public bool ExcludeFromHeightAdvantage { get; set; } + + public DamageType DamageType { get; set; } + + public bool IsTracer { get; set; } + + public Fixed64 TracerSpeed { get; set; } + + public Fixed64 TracerLength { get; set; } + + public Fixed64 BaseDamagePerRound { get; set; } + + public Fixed64 BaseWreckDamagePerRound { get; set; } + + public float FiringRecoil { get; set; } + + public int WindUpTimeMS { get; set; } + + public int RateOfFire { get; set; } + + public int NumberOfBursts { get; set; } + + public int DamagePacketsPerShot { get; set; } + + public int BurstPeriodMinTimeMS { get; set; } + + public int BurstPeriodMaxTimeMS { get; set; } + + public int CooldownTimeMS { get; set; } + + public int WindDownTimeMS { get; set; } + + public int ReloadTimeMS { get; set; } + + public bool LineOfSightRequired { get; set; } + + public TargetAimingType LeadsTarget { get; set; } + + public bool KillSkipsUnitDeathSequence { get; set; } + + public RevealTrigger RevealTriggers { get; set; } + + public UnitStatusAttackingTrigger UnitStatusAttackingTriggers { get; set; } + + public WeaponTargetStyle TargetStyle { get; set; } + + public WeaponModifierInfo[] Modifiers { get; set; } + + public AOEFalloffType AreaOfEffectFalloffType { get; set; } + + public Fixed64 AreaOfEffectRadius { get; set; } + + public bool ExcludeWeaponOwnerFromAreaOfEffect { get; set; } + + public Fixed64 FriendlyFireDamageScalar { get; set; } + + public Fixed64 WeaponOwnerFriendlyFireDamageScalar { get; set; } + + public TurretAttributes Turret { get; set; } + + public RangeBasedWeaponAttributes[] Ranges { get; set; } + + public string ProjectileEntityTypeToSpawn { get; set; } + + public AbilityTargetAlignment StatusEffectsTargetAlignment { get; set; } + + public UnitClass StatusEffectsExcludeTargetType { get; set; } + + public int ActiveStatusEffectsIndex { get; set; } + + public StatusEffectsSetAttributes[] StatusEffectsSets { get; set; } + + public EntityTypeToSpawnAttributes[] EntityTypesToSpawnOnImpact { get; set; } + + public TargetPriorizationAttributes TargetPriorizationAttributes { get; set; } + } +}