Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions BDArmory.Core/BDArmorySettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,8 @@ public class BDArmorySettings
[BDAPersistantSettingsField] public static bool PERFORMANCE_LOGGING = false;
[BDAPersistantSettingsField] public static bool AUTOCATEGORIZE_PARTS = true;
[BDAPersistantSettingsField] public static bool SHOW_CATEGORIES = false;
[BDAPersistantSettingsField] public static bool RESOURCE_STEAL_ENABLED = false;
[BDAPersistantSettingsField] public static float RESOURCE_STEAL_FUEL_RATION = 0.2f;
[BDAPersistantSettingsField] public static float RESOURCE_STEAL_AMMO_RATION = 0.2f;
}
}
174 changes: 174 additions & 0 deletions BDArmory/Bullets/PooledBullet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,22 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p
tData.lastPersonWhoHitMe = aName;
tData.lastHitTime = Planetarium.GetUniversalTime();
tData.everyoneWhoHitMe.Add(aName);

if (BDArmorySettings.RESOURCE_STEAL_ENABLED)
{
float fuelRation = BDArmorySettings.RESOURCE_STEAL_FUEL_RATION;
float ammoRation = BDArmorySettings.RESOURCE_STEAL_AMMO_RATION;
Vessel attacker = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(aName));
Vessel defender = FlightGlobals.Vessels.Find(v => v.vesselName.Equals(tName));
if (attacker != null && defender != null)
{
StealResource(attacker, defender, "LiquidFuel", fuelRation);
StealResource(attacker, defender, "Oxidizer", fuelRation);
StealResource(attacker, defender, "20x102Ammo", ammoRation);
StealResource(attacker, defender, "30x173Ammo", ammoRation);
StealResource(attacker, defender, "50CalAmmo", ammoRation);
}
}
}
}

Expand All @@ -559,6 +575,164 @@ private void ApplyDamage(Part hitPart, RaycastHit hit, float multiplier, float p
}
}

private class PriorityQueue
{
private Dictionary<int, List<PartResource>> partResources = new Dictionary<int, List<PartResource>>();

public PriorityQueue(HashSet<PartResource> elements)
{
foreach (PartResource r in elements)
{
Add(r);
}
}

public void Add(PartResource r)
{
int key = r.part.resourcePriorityOffset;
if( partResources.ContainsKey(key) )
{
List<PartResource> existing = partResources[key];
existing.Add(r);
partResources[key] = existing;
}
else
{
List<PartResource> newList = new List<PartResource>();
newList.Add(r);
partResources.Add(key, newList);
}
}

public List<PartResource> Pop()
{
if( partResources.Count == 0 )
{
return new List<PartResource>();
}
int key = partResources.Keys.Max();
List<PartResource> result = partResources[key];
partResources.Remove(key);
return result;
}

public bool HasNext()
{
return partResources.Count != 0;
}
}

private void StealResource(Vessel src, Vessel dst, string resourceName, double ration)
{
// identify all parts on source vessel with resource
HashSet<PartResource> srcParts = new HashSet<PartResource>();
foreach (Part p in src.Parts)
{
DeepFind(p, resourceName, srcParts);
}

// identify all parts on destination vessel with resource
HashSet<PartResource> dstParts = new HashSet<PartResource>();
foreach (Part p in dst.Parts)
{
DeepFind(p, resourceName, dstParts);
}

if ( srcParts.Count == 0 || dstParts.Count == 0 )
{
//Debug.Log(string.Format("[BDArmoryCompetition] Steal resource {0} failed; no parts.", resourceName));
return;
}

double remainingAmount = srcParts.Sum(p => p.amount);
double amount = remainingAmount * ration;

// transfer resource from src->dst parts, honoring their priorities
PriorityQueue sources = new PriorityQueue(srcParts);
PriorityQueue recipients = new PriorityQueue(dstParts);

List<ResourceAllocation> allocations = new List<ResourceAllocation>();
List<PartResource> inputs = null, outputs = null;
while ( amount > 0 )
{
if (inputs == null)
{
inputs = sources.Pop();
}
if (outputs == null)
{
outputs = recipients.Pop();
}
double availability = inputs.Sum(e => e.amount);
double opportunity = outputs.Sum(e => e.maxAmount - e.amount);
double tAmount = Math.Min(availability, Math.Min(opportunity, amount));
double perPartAmount = tAmount / (inputs.Count * outputs.Count);
foreach (PartResource n in inputs)
{
foreach (PartResource m in outputs)
{
//Debug.Log(string.Format("[BDArmoryCompetition] Allocate {0} of {1} from {2} to {3}", perPartAmount, resourceName, n.part.name, m.part.name));
ResourceAllocation ra = new ResourceAllocation(n, m.part, perPartAmount);
allocations.Add(ra);
}
}
if( availability < amount )
{
inputs = null;
}
if( opportunity < amount )
{
outputs = null;
}
if( tAmount == 0 )
{
break;
}
amount -= tAmount;
}
if( allocations.Count == 0 )
{
return;
}
double confirmed = 0;
foreach (ResourceAllocation ra in allocations)
{
confirmed += ra.sourceResource.part.TransferResource(ra.sourceResource, ra.amount, ra.destPart);
}
if (confirmed < 0)
{
Debug.Log(string.Format("[BDArmoryCompetition] Steal completed {0} of {3} from {2} to {1}", -confirmed, src.vesselName, dst.vesselName, resourceName));
}
}

private class ResourceAllocation
{
public PartResource sourceResource;
public Part destPart;
public double amount;
public ResourceAllocation(PartResource r, Part p, double a)
{
this.sourceResource = r;
this.destPart = p;
this.amount = a;
}
}

private void DeepFind(Part p, string resourceName, HashSet<PartResource> accumulator)
{
foreach (PartResource r in p.Resources)
{
if( r.resourceName.Equals(resourceName) )
{
accumulator.Add(r);
}
}
foreach (Part child in p.children)
{
DeepFind(child, resourceName, accumulator);
}
}

private void CalculateDragNumericalIntegration()
{
Vector3 dragAcc = currentVelocity * currentVelocity.magnitude *
Expand Down
9 changes: 9 additions & 0 deletions BDArmory/UI/BDArmorySetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,15 @@ void WindowSettings(int windowID)
BDArmorySettings.MAX_NUM_BULLET_DECALS = (int)GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.MAX_NUM_BULLET_DECALS, 1f, 999);
line++;
line++;
BDArmorySettings.RESOURCE_STEAL_ENABLED = GUI.Toggle(SLeftRect(line), BDArmorySettings.RESOURCE_STEAL_ENABLED, Localizer.Format("#LOC_BDArmory_Settings_ResourceStealEnabled"));//"Resource Steal Enabled"
line++;
GUI.Label(SLeftRect(line), $"{Localizer.Format("#LOC_BDArmory_Settings_FuelStealRation")}: ({BDArmorySettings.RESOURCE_STEAL_FUEL_RATION})", leftLabel);//Fuel Steal Ration
BDArmorySettings.RESOURCE_STEAL_FUEL_RATION = GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.RESOURCE_STEAL_FUEL_RATION, 0f, 1f);
line++;
GUI.Label(SLeftRect(line), $"{Localizer.Format("#LOC_BDArmory_Settings_AmmoStealRation")}: ({BDArmorySettings.RESOURCE_STEAL_AMMO_RATION})", leftLabel);//Ammo Steal Ration
BDArmorySettings.RESOURCE_STEAL_AMMO_RATION = GUI.HorizontalSlider(SRightRect(line), BDArmorySettings.RESOURCE_STEAL_AMMO_RATION, 0f, 1f);
line++;
line++;

bool origPm = BDArmorySettings.PEACE_MODE;
BDArmorySettings.PEACE_MODE = GUI.Toggle(SLeftRect(line), BDArmorySettings.PEACE_MODE, Localizer.Format("#LOC_BDArmory_Settings_PeaceMode"));//"Peace Mode"
Expand Down