public override double TransferTo(PartResourceInfo destination, double amount) { SimplePartResource dest = (SimplePartResource)destination; amount = Math.Min(Math.Min(amount, Amount), dest.MaxAmount - dest.Amount); dest.resource.amount += amount; resource.amount -= amount; return(amount); }
public override double TransferTo(PartResourceInfo destination, double amount) { RocketFuelResource dest = (RocketFuelResource)destination; double liquidSpace = dest.liquidFuel.maxAmount - dest.liquidFuel.amount, oxidizerSpace = dest.oxidizer.maxAmount - dest.oxidizer.amount; amount = Math.Min(Math.Min(amount, Amount), Math.Min(liquidSpace * (10d / 9), oxidizerSpace * (10d / 11))); double fuel = amount * (9d / 10), oxygen = amount * (11d / 10); dest.liquidFuel.amount += fuel; liquidFuel.amount -= fuel; dest.oxidizer.amount += oxygen; oxidizer.amount -= oxygen; return(amount); }
private void BalanceResources(double maxFlow, List <ResourcePartMap> balanceParts) { if (balanceParts.Count < 2) { return; } // sort the parts by percent full and figure out what the desired percentage is PartResourceInfo[] resources = new PartResourceInfo[balanceParts.Count]; double totalAmount = 0, totalCapacity = 0; for (int i = 0; i < balanceParts.Count; i++) { resources[i] = balanceParts[i].resource; totalAmount += resources[i].Amount; totalCapacity += resources[i].MaxAmount; } Array.Sort(resources, (a, b) => a.PercentFull.CompareTo(b.PercentFull)); double desiredPercentage = totalAmount / totalCapacity; // if the difference between the fullest and emptiest tank is small, we're done if (resources[resources.Length - 1].PercentFull - resources[0].PercentFull < PercentEpsilon) { return; } // work from both sides transferring from fuller tanks (near the end) to emptier tanks (near the beginning) for (int di = 0, si = resources.Length - 1; si > di && desiredPercentage - resources[di].PercentFull >= PercentEpsilon; di++) { PartResourceInfo dest = resources[di]; double needed = (desiredPercentage - dest.PercentFull) * dest.MaxAmount; for (; si > di && resources[si].PercentFull - desiredPercentage >= PercentEpsilon; si--) { PartResourceInfo src = resources[si]; double available = Math.Min(maxFlow, (src.PercentFull - desiredPercentage) * src.MaxAmount); needed -= src.TransferTo(dest, Math.Min(available, needed)); if (needed < AmountEpsilon) { break; // if the dest tank became full enough, move to the next without advancing the source tank } } } }
protected override void DrawWindowContents(int windowID) { headerScrollPosition = GUILayout.BeginScrollView(headerScrollPosition, GUILayout.ExpandHeight(false)); GUILayout.BeginHorizontal(); List <ResourceInfo> sortedResources = controller.GetResourceInfo().Values.ToList(); sortedResources.Sort((a, b) => a.title.CompareTo(b.title)); foreach (ResourceInfo resource in sortedResources) { bool toggled = GUILayout.Toggle(resource.isShowing, resource.title, buttonStyle) != resource.isShowing; if (toggled) { SetResourceVisibility(resource, !resource.isShowing); if (resource.isShowing && settings.OneTabOnly) { foreach (ResourceInfo otherResource in sortedResources) { if (otherResource != resource) { SetResourceVisibility(otherResource, false); } } } } } GUILayout.EndHorizontal(); GUILayout.EndScrollView(); scrollPosition = GUILayout.BeginScrollView(scrollPosition); GUILayout.BeginVertical(); // cache the value so we only do it once per call isControllable = controller.IsControllable(); // avoid allocating new options and arrays for every cell GUILayoutOption[] width20 = new[] { GUILayout.Width(20) }, width46 = new[] { GUILayout.Width(46) }, width60 = new[] { GUILayout.Width(60) }; foreach (ResourceInfo resource in sortedResources) { if (resource.isShowing) { GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.Label(resource.title, sectionStyle, GUILayout.Width(100)); if (resource.parts[0].resource.TransferMode == ResourceTransferMode.PUMP && isControllable) { resource.balance = GUILayout.Toggle(resource.balance, "Balance All", buttonStyle); } if (GUILayout.Button("Select All", buttonStyle)) { bool ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); SelectParts(resource, resource.parts, resource.parts.Any(p => !p.isSelected), ctrl); ResetRangeSelection(); } PopupWindow.Draw("Sort", windowPos, DrawSortMenu, buttonStyle, null); GUILayout.EndHorizontal(); foreach (ResourcePartMap partInfo in resource.parts) { PartResourceInfo partResource = partInfo.resource; double percentFull = partResource.PercentFull * 100.0; if (percentFull < settings.FuelCriticalLevel) { labelStyle.normal.textColor = new Color(0.88f, 0.20f, 0.20f, 1.0f); } else if (percentFull < settings.FuelWarningLevel) { labelStyle.normal.textColor = Color.yellow; } else { labelStyle.normal.textColor = Color.white; } labelStyle.fontStyle = partInfo.isSelected ? FontStyle.Bold : FontStyle.Normal; GUILayout.BeginHorizontal(); string partTitle = partInfo.part.partInfo.title; if (GUILayout.Button(partTitle.Substring(0, Math.Min(30, partTitle.Length)), labelStyle)) // if the user clicked an item name... { bool shift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); bool ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); bool alt = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt); if (alt) // alt-click selects either all parts on the same ship or all parts of the same type { List <ResourcePartMap> parts; if (shift) { parts = resource.parts.FindAll(p => p.part.partInfo.title == partTitle); } else { parts = resource.parts.FindAll(p => p.shipId == partInfo.shipId); } SelectParts(resource, parts, parts.Any(p => !p.isSelected), ctrl); // select all those parts if any is unselected ResetRangeSelection(); } else // otherwise, select and deselect items normally { ICollection <ResourcePartMap> parts; // shift-click selects a range of items in the view if (shift && resource == lastResourceClicked && partInfo != lastPartClicked && lastPartClicked != null) { int partIndex = resource.parts.IndexOf(partInfo), lastIndex = resource.parts.IndexOf(lastPartClicked); if (lastIndex < 0) { lastIndex = partIndex; } parts = resource.parts.GetRange(Math.Min(partIndex, lastIndex), Math.Abs(partIndex - lastIndex) + 1); } else { parts = new ResourcePartMap[] { partInfo }; } SelectParts(resource, parts, !partInfo.isSelected || !ctrl && resource.parts.Count(p => p.isSelected) > parts.Count, ctrl); lastResourceClicked = resource; lastPartClicked = partInfo; } } GUILayout.FlexibleSpace(); if (settings.ShowShipNumber) { GUILayout.Label(partInfo.shipId.ToString(), labelStyle, width20); } if (settings.ShowStageNumber) { GUILayout.Label(partInfo.part.inverseStage.ToString(), labelStyle, width20); } if (settings.ShowMaxAmount) { GUILayout.Label(partResource.MaxAmount.ToString("N1"), labelStyle, width60); } if (settings.ShowCurrentAmount) { GUILayout.Label(partResource.Amount.ToString("N1"), labelStyle, width60); } if (settings.ShowPercentFull) { GUILayout.Label(percentFull.ToString("N1") + "%", labelStyle, width46); } PopupWindow.Draw(GetControlText(partInfo), windowPos, DrawPopupContents, buttonStyle, partInfo, width20); GUILayout.EndHorizontal(); } } } GUILayout.EndVertical(); GUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Toggle((settings.RateMultiplier == 100.0), "x100", buttonStyle)) { settings.RateMultiplier = 100.0; } if (GUILayout.Toggle((settings.RateMultiplier == 10.0), "x10", buttonStyle)) { settings.RateMultiplier = 10.0; } if (GUILayout.Toggle((settings.RateMultiplier == 1.0), "x1", buttonStyle)) { settings.RateMultiplier = 1.0; } if (GUILayout.Toggle((settings.RateMultiplier == 0.1), "x0.1", buttonStyle)) { settings.RateMultiplier = 0.1; } GUILayout.EndHorizontal(); // Extra title bar buttons if (GUI.Button(new Rect(windowPos.width - 72, 4, 20, 20), resetContent, closeButtonStyle)) { controller.RebuildActiveVesselLists( ); } if (GUI.Button(new Rect(windowPos.width - 48, 4, 20, 20), settingsContent, closeButtonStyle)) { settingsWindow.ToggleVisible( ); } if (GUI.Button(new Rect(windowPos.width - 24, 4, 20, 20), helpContent, closeButtonStyle)) { helpWindow.ToggleVisible( ); } }
public ResourcePartMap(PartResourceInfo resource, Part part, int shipId) { this.resource = resource; this.part = part; this.shipId = shipId; }
/// <summary>Attempts to transfer the given amount of resource to another <see cref="PartResourceInfo"/> object, /// which must be of the same type. /// </summary> /// <returns>Returns the amount actually transferred, which may be less if the destination became full or /// otherwise cannot accept more resources, or the source doesn't have enough. /// </returns> public abstract double TransferTo(PartResourceInfo destination, double amount);
protected override void DrawWindowContents(int windowID) { headerScrollPosition = GUILayout.BeginScrollView(headerScrollPosition, GUILayout.ExpandHeight(false)); GUILayout.BeginHorizontal(); List <ResourceInfo> sortedResources = controller.GetResourceInfo().Values.ToList(); sortedResources.Sort((a, b) => a.title.CompareTo(b.title)); foreach (ResourceInfo resource in sortedResources) { if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_1>().hideNontransferableResources&& (resource.parts[0].resource.TransferMode != ResourceTransferMode.PUMP || !isControllable) ) { continue; } bool toggled = (GUILayout.Toggle(resource.isShowing, resource.title, buttonStyle) != resource.isShowing); if (toggled) { SetResourceVisibility(resource, !resource.isShowing); if (resource.isShowing && settings.OneTabOnly) { foreach (ResourceInfo otherResource in sortedResources) { if (otherResource != resource) { SetResourceVisibility(otherResource, false); } } } } } GUILayout.EndHorizontal(); GUILayout.EndScrollView(); scrollPosition = GUILayout.BeginScrollView(scrollPosition); GUILayout.BeginVertical(); // cache the value so we only do it once per call isControllable = controller.IsControllable(); // avoid allocating new options and arrays for every cell //GUILayoutOption[] width20 = new[] { GUILayout.Width(20) }, width46 = new[] { GUILayout.Width(46) }, width60 = new[] { GUILayout.Width(60) }; foreach (ResourceInfo resource in sortedResources) { if (resource.isShowing) { if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_1>().hideNontransferableResources&& (resource.parts[0].resource.TransferMode != ResourceTransferMode.PUMP || !isControllable) ) { continue; } GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.Label(resource.title, sectionStyle, GUILayout.Width(100)); if (resource.parts[0].resource.TransferMode == ResourceTransferMode.PUMP && isControllable) { resource.balance = GUILayout.Toggle(resource.balance, "Balance All", buttonStyle); } if (GUILayout.Button("Select All", buttonStyle)) { bool ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); SelectParts(resource, resource.parts, resource.parts.Any(p => !p.isSelected), ctrl); ResetRangeSelection(); } PopupWindow.Draw("Sort", windowPos, DrawSortMenu, buttonStyle, null); GUILayout.EndHorizontal(); foreach (ResourcePartMap partInfo in resource.parts) { PartResourceInfo partResource = partInfo.resource; double percentFull = partResource.PercentFull * 100.0; if (percentFull < settings.FuelCriticalLevel) { labelStyle.normal.textColor = new Color(0.88f, 0.20f, 0.20f, 1.0f); } else if (percentFull < settings.FuelWarningLevel) { labelStyle.normal.textColor = Color.yellow; } else { labelStyle.normal.textColor = Color.white; } labelStyle.fontStyle = partInfo.isSelected ? FontStyle.Bold : FontStyle.Normal; GUILayout.BeginHorizontal(); string partTitle = partInfo.part.partInfo.title; if (GUILayout.Button(partTitle.Substring(0, Math.Min(30, partTitle.Length)), labelStyle)) // if the user clicked an item name... { bool shift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); bool ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); bool alt = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt); if (alt) // alt-click selects either all parts on the same ship or all parts of the same type { List <ResourcePartMap> parts; if (shift) { parts = resource.parts.FindAll(p => p.part.partInfo.title == partTitle); } else { parts = resource.parts.FindAll(p => p.shipId == partInfo.shipId); } SelectParts(resource, parts, parts.Any(p => !p.isSelected), ctrl); // select all those parts if any is unselected ResetRangeSelection(); } else // otherwise, select and deselect items normally { ICollection <ResourcePartMap> parts; // shift-click selects a range of items in the view if (shift && resource == lastResourceClicked && partInfo != lastPartClicked && lastPartClicked != null) { int partIndex = resource.parts.IndexOf(partInfo), lastIndex = resource.parts.IndexOf(lastPartClicked); if (lastIndex < 0) { lastIndex = partIndex; } parts = resource.parts.GetRange(Math.Min(partIndex, lastIndex), Math.Abs(partIndex - lastIndex) + 1); } else { parts = new ResourcePartMap[] { partInfo }; } SelectParts(resource, parts, !partInfo.isSelected || !ctrl && resource.parts.Count(p => p.isSelected) > parts.Count, ctrl); lastResourceClicked = resource; lastPartClicked = partInfo; } } GUILayout.FlexibleSpace(); if (settings.ShowShipNumber) { GUILayout.Label(partInfo.shipId.ToString(), labelStyle, width20); } if (settings.ShowStageNumber) { GUILayout.Label(partInfo.part.inverseStage.ToString(), labelStyle, width20); } if (settings.ShowMaxAmount) { GUILayout.Label(partResource.MaxAmount.ToString("N1"), labelStyle, width60); } if (settings.ShowCurrentAmount) { GUILayout.Label(partResource.Amount.ToString("N1"), labelStyle, width60); } if (settings.ShowPercentFull) { GUILayout.Label(percentFull.ToString("N1") + "%", labelStyle, width46); } GUILayout.Space(10); // Lock, Transfer In, Transfer Out, Balance, Dump, Highlight, then maybe Edit...?? if (settings.ShowToggles) { List <ResourcePartMap> selectedParts = partInfo.isSelected ? EnumerateSelectedParts().ToList() : new List <ResourcePartMap>(1) { partInfo }; bool canPump = true, allHighlighted = true; foreach (ResourcePartMap part in selectedParts) { canPump &= part.resource.TransferMode == ResourceTransferMode.PUMP; allHighlighted &= part.isHighlighted; } for (int toggleNum = 1; toggleNum < 6; toggleNum++) { if (canPump && isControllable) { if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().lockedPos == toggleNum) { DrawToggleButton(partInfo, TransferDirection.LOCKED, "L", "Lock"); } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().transferInPos == toggleNum) { DrawToggleButton(partInfo, TransferDirection.IN, "I", "Transfer In"); } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().transferOutPos == toggleNum) { DrawToggleButton(partInfo, TransferDirection.OUT, "O", "Transfer Out"); } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().balancePos == toggleNum) { DrawToggleButton(partInfo, TransferDirection.BALANCE, "B", "Balance"); } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().dumpPos == toggleNum) { DrawToggleButton(partInfo, TransferDirection.DUMP, "D", "Dump"); } } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().lockedPos == toggleNum) { bool highlight = GUILayout.Toggle(allHighlighted, new GUIContent("H", "Highlight"), buttonStyle, width20); if (highlight != allHighlighted) { foreach (ResourcePartMap part in selectedParts) { if (!highlight && part.isHighlighted && !part.isSelected) { part.part.SetHighlightDefault(); } part.isHighlighted = highlight; } //guiChanged = true; } } } } if (HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_1>().popupMenu) { PopupWindow.Draw(GetControlText(partInfo), windowPos, DrawPopupContents, coloredButtonStyle, partInfo, width20); } GUILayout.EndHorizontal(); } } } GUILayout.EndVertical(); GUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Toggle((settings.RateMultiplier == 100.0), "x100", buttonStyle)) { settings.RateMultiplier = 100.0; } if (GUILayout.Toggle((settings.RateMultiplier == 10.0), "x10", buttonStyle)) { settings.RateMultiplier = 10.0; } if (GUILayout.Toggle((settings.RateMultiplier == 1.0), "x1", buttonStyle)) { settings.RateMultiplier = 1.0; } if (GUILayout.Toggle((settings.RateMultiplier == 0.1), "x0.1", buttonStyle)) { settings.RateMultiplier = 0.1; } GUILayout.EndHorizontal(); // Extra title bar buttons #if false if (GUI.Button(new Rect(windowPos.width - 72, 4, 20, 20), resetContent, closeButtonStyle)) #else if (GUI.Button(new Rect(windowPos.width - 48, 4, 20, 20), resetContent, closeButtonStyle)) #endif { controller.RebuildActiveVesselLists(); } #if false if (!HighLogic.CurrentGame.Parameters.CustomParams <TacSettings_3>().disableOldSettings) { if (GUI.Button(new Rect(windowPos.width - 48, 4, 20, 20), settingsContent, closeButtonStyle)) { settingsWindow.ToggleVisible(); } } #endif if (GUI.Button(new Rect(windowPos.width - 24, 4, 20, 20), helpContent, closeButtonStyle)) { helpWindow.ToggleVisible(); } }