/// <summary> /// Operator* to scale (multiply) properties in the ship design. /// Only laying rates scale, and this only makes sense if the mine layers produce /// the same mines. For Stars! like mines they are the same if HitChance is the /// same. /// </summary> /// <param name="op1"><see cref="MineLayer"/> to be scaled.</param> /// <param name="scalar">Number of <see cref="MineLayer"/>s in the stack.</param> /// <returns></returns> public static MineLayer operator *(MineLayer op1, int scalar) { MineLayer sum = new MineLayer(op1); sum.LayerRate = op1.LayerRate * scalar; return(sum); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="existing"><see cref="MineLayer"/> to copy.</param> public MineLayer(MineLayer existing) { this.LayerRate = existing.LayerRate; this.SafeSpeed = existing.SafeSpeed; this.HitChance = existing.HitChance; this.DamagePerEngine = existing.DamagePerEngine; this.DamagePerRamScoop = existing.DamagePerRamScoop; this.MinFleetDamage = existing.MinFleetDamage; this.MinRamScoopDamage = existing.MinRamScoopDamage; }
/// <summary> /// Provide a way to add properties in the ship design. /// Only laying rates sum up, and this only makes sense if the mine layers produce /// the same mines. /// </summary> /// <remarks> /// In Stars! mines are the same if HitChance is the /// same, and that test is used here. /// </remarks> /// <param name="op1">LHS operator.</param> /// <param name="op2">RHS operator.</param> /// <returns>A single <see cref="MineLayer"/> property with a laying rate equal to the total of op1 and op2.</returns> public static MineLayer operator +(MineLayer op1, MineLayer op2) { if (op1.HitChance != op2.HitChance) { Report.Error("MineLayer.operator+ Attempted to add together different types of mine layers."); return(op1); } MineLayer sum = new MineLayer(op1); sum.LayerRate = op1.LayerRate + op2.LayerRate; return(sum); }
/// <summary> /// Add a property to the ShipDesign.Summary. /// </summary> /// <param name="property"> /// The property to be added to the ShipDesign.Summary. /// </param><param name="type"> /// The type of the property: one of Component.propertyKeys, normally /// the key used to obtain it from a Properties dictionary. /// </param> private void SumProperty(ComponentProperty property, string type, int componentCount) { switch (type) { // properties that can be summed up to a single property case "Armor": case "Capacitor": case "Cargo": case "Cloak": case "Computer": case "Defense": case "Driver": case "Fuel": case "Jammer": case "Movement": case "Orbital Adjuster": case "Radiation": case "Robot": case "Scanner": case "Shield": case "Terraforming": if (Summary.Properties.ContainsKey(type)) { ComponentProperty toAdd = property.Clone() as ComponentProperty; // create a copy so scaling doesn't mess it up. toAdd.Scale(componentCount); Summary.Properties[type].Add(toAdd); } else { ComponentProperty toAdd = property.Clone() as ComponentProperty; // create a copy so scaling doesn't mess it up. toAdd.Scale(componentCount); Summary.Properties.Add(type, toAdd); } break; // sum up the components in the slot, but keep a separate entry for 'different components'<-- has different meaning for each of these case "Bomb": Bomb bomb = property as Bomb; if (bomb.IsSmart) { SmartBombs += bomb * componentCount; } else { ConventionalBombs += bomb * componentCount; } break; case "Mine Layer": MineLayer layer = property as MineLayer; if (layer.HitChance == MineLayer.HeavyHitChance) { HeavyMines += layer * componentCount; } else if (layer.HitChance == MineLayer.SpeedTrapHitChance) { SpeedBumbMines += layer * componentCount; } else { StandardMines += layer * componentCount; } break; case "Weapon": Weapon weapon = property as Weapon; Weapons.Add(weapon * componentCount); break; // keep one of each type only - TODO (priority 2) keep the right one case "Colonizer": case "Engine": case "Gate": case "Hull": case "Mine Layer Efficiency": if (Summary.Properties.ContainsKey(type)) { break; } else { Summary.Properties.Add(type, property); } break; // Ignore in this context case "Hull Affinity": case "Transport Ships Only": break; } }
/// <summary> /// Load from XML: Initializing constructor from an XML node. /// </summary> /// <param name="node">An <see cref="XmlNode"/> within /// a Nova component definition file (xml document). /// </param> public Component(XmlNode node) : base(node) { Properties = new Dictionary <string, ComponentProperty>(); XmlNode mainNode = node.FirstChild; while (mainNode != null) { try { switch (mainNode.Name.ToLower()) { case "mass": Mass = int.Parse(mainNode.FirstChild.Value, System.Globalization.CultureInfo.InvariantCulture); break; case "cost": Cost = new Resources(mainNode); break; case "tech": RequiredTech = new TechLevel(mainNode); break; case "description": XmlText xmltxtDescription = (XmlText)mainNode.FirstChild; if (xmltxtDescription != null) { this.Description = xmltxtDescription.Value; } break; case "race_restrictions": Restrictions = new RaceRestriction(mainNode); break; case "image": { // Paths are always stored in external files using forward slashes. ImageFile = mainNode.FirstChild.Value; ImageFile = ImageFile.Replace('/', Path.DirectorySeparatorChar); // relative or absolute path? we normally store the relative path but will handle loading either incase the file has been manually modified. try { FileInfo info = new FileInfo(ImageFile); if (info.Exists) { // was absolute, so keep as is and load up the image ComponentImage = new Bitmap(ImageFile); } else { { string graphicsPath = FileSearcher.GetGraphicsPath(); if (graphicsPath != null) { ImageFile = Path.Combine(graphicsPath, ImageFile); info = new FileInfo(ImageFile); } } if (info.Exists) { // now we have an absolute path, load the image ComponentImage = new Bitmap(ImageFile); } else { // No further action. FileSearcher will report an error (once only) if the graphics are not available. } } } catch (System.NotSupportedException) { // The path doesn't make sense, maybe it wasn't relative. // Don't change anything and don't load the image ImageFile = mainNode.FirstChild.Value.Replace('/', Path.DirectorySeparatorChar); ComponentImage = null; Report.Error("Unable to locate the image file " + ImageFile); } break; } case "property": { // Load the property. It may be of any type (Bomb, IntegerProperty, Hull, etc), so // check the save file first to determine what to load, and use the appropriate constructor. string propertyType = mainNode.SelectSingleNode("Type").FirstChild.Value; ComponentProperty newProperty; switch (propertyType.ToLower()) { case "armor": { newProperty = new IntegerProperty(mainNode); break; } case "battle movement": { newProperty = new DoubleProperty(mainNode); break; } case "beam deflector": { newProperty = new ProbabilityProperty(mainNode); break; } case "bomb": { newProperty = new Bomb(mainNode); break; } case "capacitor": { newProperty = new CapacitorProperty(mainNode); break; } case "cloak": { newProperty = new ProbabilityProperty(mainNode); break; } case "defense": { newProperty = new Defense(mainNode); break; } case "energy dampener": { newProperty = new DoubleProperty(mainNode); break; } case "cargo": { newProperty = new IntegerProperty(mainNode); break; } case "colonizer": { newProperty = new Colonizer(mainNode); break; } case "computer": { newProperty = new Computer(mainNode); break; } case "engine": { newProperty = new Engine(mainNode); break; } case "fuel": { newProperty = new Fuel(mainNode); break; } case "gate": { newProperty = new Gate(mainNode); break; } case "hull": { newProperty = new Hull(mainNode); break; } case "hull affinity": { newProperty = new HullAffinity(mainNode); break; } case "jammer": { newProperty = new ProbabilityProperty(mainNode); break; } case "mass driver": { newProperty = new MassDriver(mainNode); break; } case "mine layer": { newProperty = new MineLayer(mainNode); break; } case "mine layer efficiency": { newProperty = new DoubleProperty(mainNode); break; } case "mining robot": { newProperty = new IntegerProperty(mainNode); break; } case "orbital adjuster": { newProperty = new IntegerProperty(mainNode); break; } case "radiation": { newProperty = new Radiation(mainNode); break; } case "shield": { newProperty = new IntegerProperty(mainNode); break; } case "scanner": { newProperty = new Scanner(mainNode); break; } case "tachyon detector": { newProperty = new ProbabilityProperty(mainNode); break; } case "terraform": { newProperty = new Terraform(mainNode); break; } case "transport ships only": { newProperty = new SimpleProperty(mainNode); break; } case "weapon": { newProperty = new Weapon(mainNode); break; } default: { // it is an error to arrive here, but try to recover using an integer property Report.Error("Component property type " + propertyType + " not recognised, using default constructor"); newProperty = new IntegerProperty(mainNode); break; } } if (newProperty != null) { this.Properties.Add(propertyType, newProperty); } break; } } } catch (Exception e) { Report.FatalError(e.Message + "\n Details: \n" + e.ToString()); } mainNode = mainNode.NextSibling; } }