public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value) { var svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; if ((value is string || value == null) && svc != null) { // Preselect old entry. _dialog.SelectedItemName = value as string; // Restrict selection. var giContext = context as GridItem; if (giContext == null || giContext.Parent == null || giContext.Parent.Parent == null || giContext.Parent.Parent.Parent == null || giContext.Parent.Parent.Parent.Value == null) { MessageBox.Show("Cannot edit here.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } if (giContext.Parent.Parent.Parent.Value is ShipFactory) { // Top level item, only allow fuselage. _dialog.AvailableSlots = new[] { new ItemFactory.ItemSlotInfo { Size = ItemSlotSize.Small, Type = ItemFactory.ItemSlotInfo.ItemType.Fuselage } }; } else { // Somewhere in the tree, get parent. var containingItem = giContext.Parent.Parent.Parent.Value as ShipFactory.ItemInfo; if (containingItem == null || string.IsNullOrWhiteSpace(containingItem.Name)) { // Null parent, don't allow adding items. MessageBox.Show("Cannot add to empty items.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } var containingFactory = FactoryManager.GetFactory(containingItem.Name) as ItemFactory; if (containingFactory == null) { // Invalid parent, don't allow adding items. MessageBox.Show("Cannot determine valid items due to invalid parent entry.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Figure out available slots. var availableSlots = new List <ItemFactory.ItemSlotInfo>(); if (containingFactory.Slots != null) { availableSlots.AddRange(containingFactory.Slots); } else { // Item has no slots, don't allow adding items. MessageBox.Show("Cannot add any more items: no more free slots.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Remove used ones. foreach (var slot in containingItem.Slots) { // Skip self. if (slot == context.Instance) { continue; } // Skip empty ones. if (string.IsNullOrWhiteSpace(slot.Name)) { continue; } // Get the item of that type. var slotItemFactory = FactoryManager.GetFactory(slot.Name) as ItemFactory; if (slotItemFactory == null) { continue; } // OK, try to consume a slot (the smallest one possible). var type = slotItemFactory.GetType().ToItemType(); var size = slotItemFactory.RequiredSlotSize; ItemFactory.ItemSlotInfo bestSlot = null; foreach (var availableSlot in availableSlots) { if (availableSlot.Type != type || availableSlot.Size < size) { continue; } if (bestSlot == null || availableSlot.Size < bestSlot.Size) { bestSlot = availableSlot; } } if (bestSlot != null) { availableSlots.Remove(bestSlot); } } // Skip if no slots remain. if (availableSlots.Count == 0) { MessageBox.Show("Cannot add any more items: no items known that would fit the remaining slots.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Set remaining slots. _dialog.AvailableSlots = availableSlots; } if (svc.ShowDialog(_dialog) == DialogResult.OK) { return(_dialog.SelectedItemName); } } return(base.EditValue(context, provider, value)); }
/// <summary> /// Check default loadout (equipment) of ships for validity. /// </summary> /// <param name="factory">The factory.</param> private void ScanFactory(ShipFactory factory) { if (factory == null) { return; } // Check collision bounds. if (factory.CollisionRadius <= 0f) { AddIssue("Ship has no collision radius.", factory, "CollisionRadius", IssueType.Information); } // Validate selected items. Make sure the root item is a fuselage. var root = factory.Items; if (root != null) { // We only check if the root item is a fuselage here, other checks will // we done in the loop below. var rootItem = FactoryManager.GetFactory(root.Name) as ItemFactory; if (rootItem != null && !(rootItem is FuselageFactory)) { AddIssue("Root item must always be a fuselage.", factory, "Items", IssueType.Error); } } else { // Nothing to do. return; } // Start with the fuselage. var items = new Stack <Tuple <ShipFactory.ItemInfo, string> >(); items.Push(Tuple.Create(root, "Items")); while (items.Count > 0) { // Get entry info, skip empty ones. var entry = items.Pop(); var item = entry.Item1; var prefix = entry.Item2; if (item == null) { continue; } // Check asset references. ScanReferences(factory, item, prefix); // Adjust prefix for further access. prefix = string.IsNullOrWhiteSpace(prefix) ? "" : (prefix + "."); // Notify about empty slots that can be removed, but keep going // to properly warn if any items are equipped in this null item. if (string.IsNullOrWhiteSpace(item.Name)) { AddIssue("Empty item name, branch will be skipped when generating the ship.", factory, prefix + "Name", IssueType.Information); } // Queue checks for children. for (var i = 0; i < item.Slots.Length; i++) { items.Push(Tuple.Create(item.Slots[i], prefix + "Slots[" + i + "]")); } // Get slot information to validate occupied slots. var itemFactory = FactoryManager.GetFactory(item.Name) as ItemFactory; var availableSlots = new List <ItemFactory.ItemSlotInfo>(); if (itemFactory != null && itemFactory.Slots != null) { availableSlots.AddRange(itemFactory.Slots); } for (var i = 0; i < item.Slots.Length; i++) { var slot = item.Slots[i]; // Skip empty ones. if (string.IsNullOrWhiteSpace(slot.Name)) { continue; } // Get the item of that type. Skip if unknown (warning will come when that // item itself is processed). var slotItemFactory = FactoryManager.GetFactory(slot.Name) as ItemFactory; if (slotItemFactory == null) { continue; } // OK, try to consume a slot (the smallest one possible). var type = slotItemFactory.GetType().ToItemType(); var size = slotItemFactory.RequiredSlotSize; ItemFactory.ItemSlotInfo bestSlot = null; foreach (var availableSlot in availableSlots) { if (availableSlot.Type != type || availableSlot.Size < size) { continue; } if (bestSlot == null || availableSlot.Size < bestSlot.Size) { bestSlot = availableSlot; } } if (bestSlot == null) { AddIssue("Equipped item cannot be fit into any slot.", factory, prefix + "Slots[" + i + "]", IssueType.Error); } else { availableSlots.Remove(bestSlot); } } } }