public static void SetWorldPosition(CompoundPart part, Vector3 newPosition, bool targetSelected) { bool targetActive = IsTargetActive(part, targetSelected); Vector3 localPosition = part.transform.InverseTransformPoint(newPosition); if (targetActive) { SetTargetPosition(part, newPosition); } else { part.transform.position = newPosition; } UpdateEditorGizmo(part, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartOffset, part); if (part.symMethod == SymmetryMethod.Mirror) { UpdateMirrorSymmetryCounterpartsPosition(part, targetActive); } else if (part.symMethod == SymmetryMethod.Radial) { UpdateRadialSymmetryCounterpartsPosition(part, localPosition, targetActive); } EditorLogic.fetch.SetBackup(); }
public static bool PartIsStrutOrFuelLine(CompoundPart part, bool techRequired = true) { if (part == null || !HighLogic.CurrentGame.Parameters.CustomParams <KLFCustomParams2>().allowStrutFuelFailures) { return(false); } if (HighLogic.CurrentGame.Mode != Game.Modes.SANDBOX && !techRequired) { ProtoTechNode techNode = ResearchAndDevelopment.Instance.GetTechState(part.partInfo.TechRequired); if (techNode != null && techNode.state == RDTech.State.Available) { return(false); } } if (part.name != "fuelLine" && part.name != "strutConnector") { return(false); } if (part.attachState == CompoundPart.AttachState.Detached || part.attachState == CompoundPart.AttachState.Attaching) { return(false); } if (part.target == part.parent) { return(false); } return(true); }
private static void RotateRadialSymmetryCounterparts(CompoundPart part, Vector3 eulerAngles, Space space, bool targetActive) { if (space == Space.World) { if (targetActive) { CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); eulerAngles = module.targetAnchor.InverseTransformDirection(eulerAngles); } else { eulerAngles = part.transform.InverseTransformDirection(eulerAngles); } } foreach (CompoundPart symmetryCounterpart in part.symmetryCounterparts) { if (targetActive) { RotateTarget(symmetryCounterpart, eulerAngles, Space.Self); } else { symmetryCounterpart.transform.Rotate(eulerAngles, Space.Self); symmetryCounterpart.onEditorEndTweak(); } UpdateEditorGizmo(symmetryCounterpart, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartRotated, symmetryCounterpart); } }
private static void UpdateMirrorSymmetryCounterpartsPosition(CompoundPart part, bool targetActive) { Vector3 mirrorPosition; if (targetActive) { Vector3 targetPosition = PartUtil.GetPosition(part, Space.World, targetActive); mirrorPosition = MirrorPosition(targetPosition); } else { mirrorPosition = MirrorPosition(part.transform.position); } foreach (CompoundPart symmetryCounterpart in part.symmetryCounterparts) { if (targetActive) { SetTargetPosition(symmetryCounterpart, mirrorPosition); } else { symmetryCounterpart.transform.position = mirrorPosition; } UpdateEditorGizmo(symmetryCounterpart, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartOffset, symmetryCounterpart); } }
public override void OnStart(PartModule.StartState state) { if (state != StartState.Editor) { cPart = GetComponent <CompoundPart>(); } }
public static Vector3 GetPosition(Part part, Space space, bool compoundTargetSelected) { bool targetActive = IsTargetActive(part, compoundTargetSelected); CompoundPart compoundPart = null; if (targetActive) { compoundPart = (CompoundPart)part; } if (space == Space.Self) { if (targetActive) { Vector3 worldPosition = compoundPart.transform.TransformPoint(compoundPart.targetPosition); return((compoundPart.parent != null) ? compoundPart.parent.transform.InverseTransformPoint(worldPosition) : worldPosition); } else { return(part.transform.localPosition); } } else { if (targetActive) { return(compoundPart.transform.TransformPoint(compoundPart.targetPosition)); } else { return(part.transform.position); } } }
public static Quaternion GetRotation(Part part, Space space, bool compoundTargetSelected) { bool targetActive = IsTargetActive(part, compoundTargetSelected); CompoundPart compoundPart = null; if (targetActive) { compoundPart = (CompoundPart)part; } if (space == Space.Self) { if (targetActive) { return(compoundPart.transform.localRotation * compoundPart.targetRotation); } else { return(part.transform.localRotation); } } else { if (targetActive) { return(compoundPart.transform.rotation * compoundPart.targetRotation); } else { return(part.transform.rotation); } } }
public CompoundPartGeoUpdater(CompoundPart part, GeometryPartModule geoModule) { this.part = part; this.geoModule = geoModule; lastAttachState = part.attachState; lastTarget = part.target; }
public static void Rotate(CompoundPart part, Vector3 eulerAngles, Space space, bool targetSelected) { bool targetActive = IsTargetActive(part, targetSelected); CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); if (targetActive) { RotateTarget(part, eulerAngles, space); } else { part.transform.Rotate(eulerAngles, space); part.onEditorEndTweak(); } UpdateEditorGizmo(part, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartRotated, part); if (part.symMethod == SymmetryMethod.Mirror) { RotateMirrorSymmetryCounterparts(part, eulerAngles, space, targetActive); } else if (part.symMethod == SymmetryMethod.Radial) { RotateRadialSymmetryCounterparts(part, eulerAngles, space, targetActive); } EditorLogic.fetch.SetBackup(); }
public override void OnStart(PartModule.StartState state) { if (state != StartState.Editor) { cPart = GetComponent<CompoundPart>(); } }
private void ToggleCompound() { CompoundPart compoundPart = (CompoundPart)part; if (compoundTargetSelected || compoundPart.target != null) { compoundTargetSelected = !compoundTargetSelected; } SaveCfgValue("ANCHOR", compoundTargetSelected ? "target" : "source"); }
private static void RotateTarget(CompoundPart part, Vector3 axis, float angle, Space space) { CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); bool oldTweakingTarget = module.TweakingTarget; module.TweakingTarget = true; module.targetAnchor.Rotate(axis, angle, space); module.targetAnchor.hasChanged = true; module.OnTargetUpdate(); module.TweakingTarget = oldTweakingTarget; }
private static void SetTargetPosition(CompoundPart part, Vector3 position) { CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); bool oldTweakingTarget = module.TweakingTarget; module.TweakingTarget = true; module.targetAnchor.position = position; module.targetAnchor.hasChanged = true; module.OnTargetUpdate(); module.TweakingTarget = oldTweakingTarget; }
static void RepositionPart(CompoundPart part, Part startPart, Vector3 startPosition, Vector3 destPosition) { part.transform.position = startPosition; part.transform.up = startPart.transform.up; part.transform.forward = startPart.transform.forward; part.transform.LookAt(destPosition); //this rotates the strut base towards the target, need to keep it flush with the parent part.transform.Rotate(0, 90, 0); Vector3 localDirToTarget = part.transform.InverseTransformDirection((destPosition - startPosition).normalized); Log.Debug("final direction: " + localDirToTarget.ToString()); part.raycastTarget(localDirToTarget); }
void AlignCompoundPart(CompoundPart part, bool snapHeights) { if (part.target != null && part.parent != null) { CompoundPartUtil.AlignCompoundPart(part, snapHeights); List <Part> symParts = part.symmetryCounterparts; //move any symmetry siblings/counterparts foreach (CompoundPart symPart in symParts) { CompoundPartUtil.AlignCompoundPart(symPart, snapHeights); } AddUndo(); } }
private void PartLinked(CompoundPart cpart) { if (cpart.target != null) { Log("Compound part target: " + cpart.target.name + ", mission ID: " + cpart.target.missionID.ToString() + ", part mid: " + cpart.missionID); if (cpart.target.missionID != cpart.missionID) { cpart.missionID = cpart.target.missionID; Log("Fixed mission ID for vessel: " + cpart.vessel.GetDisplayName() + " and part: " + cpart.name, LogLevel.INFO); } } else { Log("CompoundPart Linked: " + cpart.name + " - no target"); } }
void CompoundPartAttachStateSorter(CompoundPart part, List <Part> attached, List <Part> notAttached) { if (part.attachState == CompoundPart.AttachState.Detached || part.attachState == CompoundPart.AttachState.Attaching) { notAttached.Add(part); return; } if (part.target == part.parent) { notAttached.Add(part); return; } attached.Add(part); }
void CompoundPartInfo(CompoundPart part) { AddLabel("name", part.name); AddLabel("direction", part.direction.ToString(vectFormat)); AddLabel("position", part.transform.position.ToString(vectFormat)); AddLabel("localPosition", part.transform.localPosition.ToString(vectFormat)); AddLabel("maxLength", part.maxLength.ToString("F3")); AddLabel("attachState", part.attachState.ToString()); if (part.target != null) { AddLabel("target", part.target.name); AddLabel("targetPosition", part.targetPosition.ToString(vectFormat)); AddLabel("targetRotation", part.targetRotation.ToString(vectFormat)); } }
private static void UpdateRadialSymmetryCounterpartsPosition(CompoundPart part, Vector3 localPosition, bool targetActive) { foreach (CompoundPart symmetryCounterpart in part.symmetryCounterparts) { if (targetActive) { Vector3 newPosition = symmetryCounterpart.transform.TransformPoint(localPosition); SetTargetPosition(symmetryCounterpart, newPosition); } else { symmetryCounterpart.transform.Translate(localPosition); } UpdateEditorGizmo(symmetryCounterpart, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartOffset, symmetryCounterpart); } }
//get distance: Vector3.Distance(object1.transform.position, object2.transform.position); //Physics.Raycast(part.transform.position, part.transform.TransformDirection(dir), out HIT, this.maxLength, EditorLogic.LayerMask) /// <summary> /// Align compount part, leave in starting position but center and level to target /// </summary> /// <param name="part">Part</param> public static void AlignCompoundPart(CompoundPart part, bool snapHeights) { if (part.parent == null || part.target == null) { Log.Debug("Part is not fully connected"); return; } if (snapHeights) { AlignCompoundPartSnapped(part); } else { AlignCompoundPartLevel(part); } }
static void AlignCompoundPartLevel(CompoundPart part) { Part startPart = part.parent; Part targetPart = part.target; Vector3 startPosition = startPart.transform.position; Vector3 destPosition = targetPart.transform.position; GetCollisionPointOnAxis(startPart, destPosition, part.transform.localPosition.y, out startPosition); destPosition = startPart.transform.InverseTransformPoint(destPosition); //get local pos destPosition.y = part.transform.localPosition.y; //level out destPosition = startPart.transform.TransformPoint(destPosition); //back to global pos Log.Debug(string.Format("new level startPosition: {0} destPosition: {1}", startPosition.ToString(), destPosition.ToString())); RepositionPart(part, startPart, startPosition, destPosition); }
static public void dumpPartModule(PartModule pm) { AAprint("pm: " + pm.moduleName); AAprint("pm.enabled: " + pm.enabled.ToString() + "/" + pm.isEnabled); AAprint("pm.gettype: " + pm.GetType().ToString()); if (pm.moduleName == "CModuleFuelLine") { AAprint("FUEL LINE!"); CompoundPart cp = (CompoundPart)pm.part; if (cp.target == null) { print("target is null"); } else { printPart("target", cp.target); } } }
public static bool PartIsStrutOrFuelLine(CompoundPart part) { if (!HighLogic.CurrentGame.Parameters.CustomParams <KLFCustomParams2>().allowStrutFuelFailures) { return(false); } if (part.name != "fuelLine" && part.name != "strutConnector") { return(false); } if (part.attachState == CompoundPart.AttachState.Detached || part.attachState == CompoundPart.AttachState.Attaching) { return(false); } if (part.target == part.parent) { return(false); } return(true); }
private static void UpdateEditorGizmo(CompoundPart part, bool targetActive) { if (part == EditorLogic.SelectedPart) { Vector3 position; Quaternion rotation; if (targetActive) { CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); position = module.targetAnchor.position; rotation = module.targetAnchor.rotation; } else { position = part.transform.position; rotation = part.transform.rotation; } var gizmoOffset = HighLogic.FindObjectOfType <EditorGizmos.GizmoOffset>(); if (gizmoOffset != null) { gizmoOffset.transform.position = position; if (gizmoOffset.CoordSpace == Space.Self) { gizmoOffset.transform.rotation = rotation; } } var gizmoRotate = HighLogic.FindObjectOfType <EditorGizmos.GizmoRotate>(); if (gizmoRotate != null) { gizmoRotate.transform.position = position; if (gizmoRotate.CoordSpace == Space.Self) { gizmoRotate.transform.rotation = rotation; } } } }
private static void RotateMirrorSymmetryCounterparts(CompoundPart part, Vector3 eulerAngles, Space space, bool targetActive) { if (space == Space.Self) { if (targetActive) { CompoundParts.CModuleLinkedMesh module = part.FindModuleImplementing <CompoundParts.CModuleLinkedMesh>(); eulerAngles = module.targetAnchor.TransformDirection(eulerAngles); } else { eulerAngles = part.transform.TransformDirection(eulerAngles); } } eulerAngles = EditorLogic.RootPart.transform.InverseTransformDirection(eulerAngles); Quaternion rotation = Quaternion.Euler(eulerAngles); rotation.ToAngleAxis(out float angle, out Vector3 axis); Vector3 mirrorAxis = new Vector3(-axis.x, axis.y, axis.z); mirrorAxis = EditorLogic.RootPart.transform.TransformDirection(mirrorAxis); foreach (CompoundPart symmetryCounterpart in part.symmetryCounterparts) { if (targetActive) { RotateTarget(symmetryCounterpart, mirrorAxis, -angle, Space.World); } else { symmetryCounterpart.transform.Rotate(mirrorAxis, -angle, Space.World); symmetryCounterpart.onEditorEndTweak(); } UpdateEditorGizmo(symmetryCounterpart, targetActive); GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartRotated, symmetryCounterpart); } }
static void AlignCompoundPartSnapped(CompoundPart part) { Part startPart = part.parent; Part targetPart = part.target; Log.Debug("Getting parentLocalHeight"); float parentLocalHeight = GetCompoundPartPositionHeight(part, part.parent); //float parentLocalHeight = SnapCompoundPartHeight(part, part.parent); Log.Debug("Getting targetLocalHeight"); float targetLocalHeight = GetCompoundPartPositionHeight(part, part.target); //float targetLocalHeight = SnapCompoundPartHeight(part, part.target); Vector3 startPosition = startPart.transform.position; Vector3 destPosition = targetPart.transform.position; Log.Debug(string.Format("startPosition: {0} destPosition: {1}", startPosition.ToString(), destPosition.ToString())); GetCollisionPointOnAxis(startPart, destPosition, parentLocalHeight, out startPosition); GetCollisionPointOnAxis(targetPart, startPosition, targetLocalHeight, out destPosition); Log.Debug(string.Format("new collider startPosition: {0} destPosition: {1}", startPosition.ToString(), destPosition.ToString())); RepositionPart(part, startPart, startPosition, destPosition); }
private bool StrutsGoHigher(CompoundPart strut, int startingStage, Func<CompoundPart, Part> partSelector) { return partSelector(strut).inverseStage < startingStage; }
private bool StrutsGoHigher(CompoundPart strut, int startingStage, Func <CompoundPart, Part> partSelector) { return(partSelector(strut).inverseStage < startingStage); }
public override void OnRender() { try { List <Part> parts = EditorLogic.fetch.ship != null ? EditorLogic.fetch.ship.Parts : new List <Part>(); this.highlight.BeginTracking(); GUILayout.BeginVertical(); #if false // If Blizzy's toolbar is available, give the user the option to pick the stock toolbar. if (ToolbarManager.ToolbarAvailable) #endif { //bool stockToolbar = PartWizardPlugin.ToolbarIsStock; bool stockToolbar = GUILayout.Toggle(PartWizardPlugin.ToolbarIsStock, Localized.UseStockToolbar, GUILayout.Width(200)); if (stockToolbar != PartWizardPlugin.ToolbarIsStock) { #if false PartWizardPlugin.ToolbarTypeToggleActive = true; #endif PartWizardPlugin.ToolbarIsStock = stockToolbar; PartWizardPlugin.Instance.SaveToolbarConfiguration(); } } #region Display Mode Control GUILayout.BeginHorizontal(); this.viewType = (ViewType)GUIControls.HorizontalToggleSet((int)this.viewType, this.viewTypeContents, this.selectedViewTypeStyle, this.unselectedViewTypeStyle); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Sort by:"); this.sortBy = (SortBy)GUIControls.HorizontalToggleSet((int)this.sortBy, this.sortTypeContents, this.selectedViewTypeStyle, this.unselectedViewTypeStyle); GUILayout.EndHorizontal(); List <Part> buyableParts = null; if (this.viewType == ViewType.Hidden) { parts = parts.FindAll((p) => { return(p.partInfo.category == PartCategories.none); }); } else if (this.viewType == ViewType.Unavailable) { parts = parts.FindAll((p) => { bool result = false; // Get the R&D technology state for the current part. ProtoTechNode techState = ResearchAndDevelopment.Instance.GetTechState(p.partInfo.TechRequired); // If there is a state or the technology is locked or the part hasn't been purchased... if (techState == null || techState.state != RDTech.State.Available || !techState.partsPurchased.Contains(p.partInfo)) { // ...add it to the list. result = true; } return(result); }); Debug.Log("total # buyable part: " + parts.Count.ToString()); // Stash the filtered list in to the buyable list. buyableParts = parts; // Create a new collection with a copy of all the buyable parts. parts = new List <Part>(buyableParts); // Create a hash set to act as a filter for duplicate parts. HashSet <string> duplicatePartFilter = new HashSet <string>(); // Remove each part that has already been added to the hash filter. parts.RemoveAll((p) => !duplicatePartFilter.Add(p.name)); // Here parts is a list of unique buyable parts and buyableParts is all of the buyable parts, including duplicates. Debug.Log("total # buyable part after dup filter: " + parts.Count.ToString()); } #endregion if (parts != null && parts.Count > 0) { switch (sortBy) { case SortBy.Name: parts.Sort((p, q) => p.partInfo.title.CompareTo(q.partInfo.title)); break; case SortBy.StageAsc: if (this.viewType != ViewType.Unavailable) { parts.Sort((p, q) => p.inverseStage.CompareTo(q.inverseStage)); } else { parts.Sort((p, q) => p.partInfo.title.CompareTo(q.partInfo.title)); } break; case SortBy.StageDesc: if (this.viewType != ViewType.Unavailable) { parts.Sort((q, p) => p.inverseStage.CompareTo(q.inverseStage)); } else { parts.Sort((p, q) => p.partInfo.title.CompareTo(q.partInfo.title)); } break; } } #region Part List GUILayout.BeginVertical(GUIControls.PanelStyle); this.scrollPosition = GUILayout.BeginScrollView(this.scrollPosition, false, false); int totalEntryCost = 0; int visiblePartCount = 0; int lastStage = 0; if (parts != null && parts.Count > 0) { lastStage = parts[0].inverseStage; } if (this.viewType == ViewType.Category) { if (GUILayout.Button(Localized.ViewAll)) { for (int i = 0; i < visibleCategories.Length; i++) { visibleCategories[i] = true; } } if (GUILayout.Button(Localized.Clear)) { for (int i = 0; i < visibleCategories.Length; i++) { visibleCategories[i] = false; } } for (PartCategories partCategories = PartCategories.Propulsion; partCategories < PartCategories.Coupling; partCategories++) { // Need to add one to the PartCategories because "none" is a -1, and some parts have a category = none visibleCategories[(int)partCategories + 1] = GUILayout.Toggle(visibleCategories[(int)partCategories + 1], partCategories.ToString(), toggleStyle); } } else if (this.viewType == ViewType.Resources) { if (GUILayout.Button(Localized.ViewAll)) { foreach (ResourceInfo resourceInfo in this.availableResources.Values) { resourceInfo.Visible = true; } } if (GUILayout.Button(Localized.Clear)) { foreach (ResourceInfo resourceInfo in this.availableResources.Values) { resourceInfo.Visible = false; } } foreach (string availableResource in this.availableResources.Keys) { bool resourceVisible = GUILayout.Toggle(this.availableResources[availableResource].Visible, availableResource, toggleStyle); this.availableResources[availableResource].Visible = resourceVisible; } } else { foreach (Part part in parts) { // Reset part name label color to default; some conditions may change the color to indicate various things. labelStyle.normal.textColor = PartWizardWindow.DefaultPartNameColor; // Check if this part's category is currently visible. // Need to add one to the PartCategories because "none" is a -1, and some parts have a category = none if (visibleCategories[(int)part.partInfo.category + 1]) { // The part's category is visible, now check resource conditions to determine final visibility. bool partVisible = false; if (this.availableResources[Localized.ShowPartsWithoutResources].Visible && part.Resources.Count == 0) { partVisible = true; } else { foreach (PartResource partResource in part.Resources) { if (this.availableResources[partResource.resourceName].Visible) { partVisible = true; break; } } } if (partVisible) { totalEntryCost += part.partInfo.entryCost; visiblePartCount++; GUIControls.BeginMouseOverHorizontal(); bool actionEditorPartButtonMouseOver = false; #region Part Label if (sortBy == SortBy.StageAsc || sortBy == SortBy.StageDesc) { if (lastStage != part.inverseStage) { lastStage = part.inverseStage; } GUILayout.Label(lastStage.ToString() + ": "); } if (EditorLogic.fetch.editorScreen != EditorScreen.Actions) { // Check compound parts for integrity. if (part is CompoundPart) { CompoundPart compoundPart = (CompoundPart)part; if (compoundPart.attachState == CompoundPart.AttachState.Detached || compoundPart.attachState == CompoundPart.AttachState.Attaching || compoundPart.target == compoundPart.parent) { labelStyle.normal.textColor = Color.red; } } labelStyle.fixedWidth = 250; GUILayout.Label(new GUIContent(part.partInfo.title, part.partInfo.name), labelStyle); } else { Log.Write("EditorScreen.Actions, part: " + part.partInfo.title); if (GUIControls.MouseOverButton(new GUIContent(part.partInfo.title, part.partInfo.name), out actionEditorPartButtonMouseOver, this.actionEditorModePartButtonStyle)) { // Each part gets the EditorActionPartSelector added to it when the editor switches to the Actions screen. (And it // gets taken away when leaving that screen.) EditorActionPartSelector selector = part.GetComponent <EditorActionPartSelector>(); // Make sure we have it... if (selector != null) { // ...and select it. selector.Select(); Log.Write("Action editor selecting part {0}.", part.name); } } } #endregion // Adds space between the part name and the buttons (if any) associated with the part. GUILayout.FlexibleSpace(); // Only enable the following buttons if there is no actively selected part, but we want to have them drawn. GUI.enabled = EditorLogic.SelectedPart == null; bool deleted = false; // Will be set to true if the delete button was pressed. bool bought = false; // Will be set to true if the buy button was pressed. bool breakSymmetryMouseOver = false; // Will be set to true if the mouse is over the part's break symmetry button. bool deleteButtonMouseOver = false; // Will be set to true if the mouse is over the part's delete button. bool buyButtonMouseOver = false; // Will be set to true if the mouse is over the part's buy button. string deleteTooltip = default(string); string buyTooltip = default(string); if (this.viewType == ViewType.All || this.viewType == ViewType.Hidden) { #region Break Symmetry Button string breakabilityReport = default(string); GUI.enabled = EditorLogic.SelectedPart == null && EditorLogic.fetch.editorScreen == EditorScreen.Parts && PartWizard.HasBreakableSymmetry(part, out breakabilityReport); string breakSymmetryTooltip = GUI.enabled ? Localized.BreakSymmetryDescription : default(string); breakSymmetryMouseOver = false; if (GUIControls.MouseOverButton(new GUIContent(Localized.BreakSymmetryButtonText, breakSymmetryTooltip), out breakSymmetryMouseOver, Configuration.PartActionButtonWidth)) { this.symmetryEditorWindow.Part = part; if (!this.symmetryEditorWindow.Visible) { this.symmetryEditorWindow.Show(this); // Short circuit the mouse over for breaking symmetry when showing the Symmetry Editor in case it appears over top of this // button and immediately begins highlighting parts. This would cause *this* window's highlighting to be stuck on the part. breakSymmetryMouseOver = false; } } breakSymmetryMouseOver &= GUI.enabled; // Clear mouse over flag if the symmetry button was disabled. #endregion #region Delete Button GUI.enabled = EditorLogic.SelectedPart == null && EditorLogic.fetch.editorScreen == EditorScreen.Parts && PartWizard.IsDeleteable(part); deleteTooltip = GUI.enabled ? ((part.symmetryCounterparts.Count == 0) ? Localized.DeletePartSingularDescription : Localized.DeletePartPluralDescription) : default(string); if (GUIControls.MouseOverButton(new GUIContent(Localized.DeletePartButtonText, deleteTooltip), out deleteButtonMouseOver, Configuration.PartActionButtonWidth)) { PartWizard.Delete(part); // Set a flag so additional GUI logic can decide what to do in the case where a part is deleted. deleted = true; } deleteButtonMouseOver &= GUI.enabled; // Clear mouse over flag if the delete button was disabled. #endregion } else // this.viewType == ViewType.Unavailable { #region Buy Button GUI.enabled = EditorLogic.SelectedPart == null && (double)part.partInfo.entryCost <= Funding.Instance.Funds && PartWizard.IsBuyable(part); buyTooltip = GUI.enabled ? string.Format(Localized.BuyPartDescriptionTextFormat, part.partInfo.entryCost) : default(string); if (GUIControls.MouseOverButton(new GUIContent(Localized.BuyPartButtonText, buyTooltip), out buyButtonMouseOver, Configuration.PartActionButtonWidth)) { Log.Write("Buying part {0}.", part.name); PartWizard.Buy(part, true); // Set a flag so additional GUI logic can decide what to do in the case where a part is bought. bought = true; } buyButtonMouseOver &= GUI.enabled; // Clear mouse over flag if the buy button was disabled. #endregion } GUI.enabled = true; bool groupMouseOver = false; GUIControls.EndMouseOverHorizontal(out groupMouseOver); // End of row for this part. // If we deleted a part, then just jump out of the loop since the parts list has been modified. if (deleted || bought) { break; } #region Part Highlighting Control if (breakSymmetryMouseOver) { this.highlight.Add(part, Configuration.HighlightColorEditableSymmetryRoot, Configuration.HighlightColorEditableSymmetryCounterparts, true); } else if (deleteButtonMouseOver) { this.highlight.Add(part, Configuration.HighlightColorDeletablePart, Configuration.HighlightColorDeletableCounterparts, true); } else if (buyButtonMouseOver) { // TODO: Duplicate code! buyableParts.ForEach((p) => { if (part.name == p.name) { this.highlight.Add(p, Configuration.HighlightColorBuyablePart); } }); } else if (groupMouseOver) { if (viewType != ViewType.Unavailable) { Color highlightColor = (part == EditorLogic.RootPart) ? Configuration.HighlightColorRootPart : Configuration.HighlightColorSinglePart; Color counterpartHighlightColor = Configuration.HighlightColorCounterparts; if (EditorLogic.fetch.editorScreen == EditorScreen.Actions) { highlightColor = Configuration.HighlightColorActionEditorTarget; counterpartHighlightColor = Configuration.HighlightColorActionEditorTarget; } this.highlight.Add(part, highlightColor, counterpartHighlightColor, false); } else { // TODO: Duplicate code! buyableParts.ForEach((p) => { if (part.name == p.name) { Log.Write("Highlighting 2 part: " + part.partInfo.title); this.highlight.Add(p, Configuration.HighlightColorBuyablePart, false); } }); } } else if (actionEditorPartButtonMouseOver) { Log.Write("Highlighting part: " + part.partInfo.title); this.highlight.Add(part, Configuration.HighlightColorActionEditorTarget, Configuration.HighlightColorActionEditorTarget); } #endregion } } } } GUILayout.EndScrollView(); GUILayout.EndVertical(); if (viewType == ViewType.Unavailable) { int buyableEntryCost = 0; bool enableBulkBuy = false; foreach (Part p in parts) { buyableEntryCost += p.partInfo.entryCost; enableBulkBuy |= PartWizard.IsBuyable(p); } GUI.enabled = parts.Count > 0 && (double)buyableEntryCost <= Funding.Instance.Funds && enableBulkBuy; bool buyAllMouseOver = false; if (GUIControls.MouseOverButton(new GUIContent(string.Format(Localized.BuyAllButtonTextFormat, buyableEntryCost)), out buyAllMouseOver)) { foreach (Part part in parts) { if (PartWizard.IsBuyable(part)) { Log.Write("Buying part {0}.", part.name); PartWizard.Buy(part, false); } } PartWizard.SaveGame(); } // TODO: Highlight all parts that will be bought by clicking Buy All. if (buyAllMouseOver) { buyableParts.ForEach((p) => { this.highlight.Add(p, Configuration.HighlightColorBuyablePart); }); } GUI.enabled = true; } #endregion #region Status Area // Push everything above this up, otherwise it will be centered vertically. GUILayout.FlexibleSpace(); if (viewType == ViewType.All || viewType == ViewType.Hidden || viewType == ViewType.Unavailable) { string status = default(string); if (!string.IsNullOrEmpty(GUI.tooltip)) { if (parts.Count != 1) { status = string.Format(CultureInfo.CurrentCulture, Localized.StatusLabelPluralTooltipTextFormat, visiblePartCount, GUI.tooltip, parts.Count - visiblePartCount); } else { status = string.Format(CultureInfo.CurrentCulture, Localized.StatusLabelSingularTooltipTextFormat, visiblePartCount, GUI.tooltip, parts.Count - visiblePartCount); } } else { if (parts.Count != 1) { status = string.Format(CultureInfo.CurrentCulture, Localized.StatusLabelPluralTextFormat, visiblePartCount, parts.Count - visiblePartCount); } else { status = string.Format(CultureInfo.CurrentCulture, Localized.StatusLabelSingularTextFormat, visiblePartCount, parts.Count - visiblePartCount); } } GUILayout.Label(status, this.tooltipLabelStyle); } #endregion GUILayout.EndVertical(); if (this.Visible && this.mouseOver) { this.highlight.EndTracking(); } else { this.highlight.CancelTracking(); } } catch (Exception e) { Log.Write("PartWizardWindow.OnRender() unexpected exception caught."); Log.Write(e.Message); Log.Write(e.StackTrace); this.highlight.CancelTracking(); throw; } finally { GUI.DragWindow(); } }
private static bool IsTargetActive(CompoundPart part, bool targetSelected) { return(targetSelected && part.target != null); }
static float GetCompoundPartPositionHeight(CompoundPart part, Part target) { Log.Debug(string.Format("Getting new position height for {0} on {1}", part.name, target.name)); //lengthwise position on parent (extents, +/- from center) float localHeight = 0f; float parentHeight = 0f; if (part.parent == target) { localHeight = part.transform.localPosition.y; parentHeight = part.parent.GetPartRendererBound().extents.y; } else if (part.target == target) { Vector3 targetPos = part.transform.TransformPoint(part.targetPosition); targetPos = target.transform.InverseTransformPoint(targetPos); localHeight = targetPos.y; parentHeight = target.GetPartRendererBound().extents.y; } else { Log.Warn("Unable to identify part"); } Log.Debug(string.Format("localHeight: {0} parentHeight: {1}", localHeight.ToString("F3"), parentHeight.ToString("F3"))); //offset strut when attaching to top/bottom of parent const float strutOffset = 0.15f; //threshold for small parent parts const float parentSizeCutoff = 0.5f; float heightPct = localHeight / parentHeight; Log.Debug("Attachment height%: " + (heightPct * 100f).ToString("F0")); Log.Debug("Original localHeight: " + localHeight.ToString()); //+1 up, -1 down float upOrDown = 1f; if (localHeight < 0f) { upOrDown = -1f; } if (parentHeight < parentSizeCutoff) { //for small parts, just center on them Log.Debug("Parent is small, defaulting to center"); localHeight = 0f; } else if (parentHeight >= 1.5f) { //only do quarter snapping for parts >= 3.0 total height if (Math.Abs(localHeight) < parentHeight * 0.125f) { //middle 25% of parent, snap to center (12.5% of extent) Log.Debug("Centering on parent"); localHeight = 0f; } else if (Math.Abs(localHeight) < parentHeight * 0.7f) { //top/bottom quarter (70% of extent) Log.Debug("Centering quarter on parent"); localHeight = parentHeight / 2 * upOrDown; } else { //top/bottom edge Log.Debug("Aligning to edge of parent"); localHeight = (parentHeight - strutOffset) * upOrDown; } } else if (Math.Abs(localHeight) < parentHeight * 0.5f) { //middle 50% of parent, snap to center Log.Debug("Centering on parent"); localHeight = 0f; } else { //top/bottom edge Log.Debug("Aligning to edge of parent"); localHeight = (parentHeight - strutOffset) * upOrDown; } Log.Debug("new localHeight: " + localHeight.ToString()); return(localHeight); }