/// <summary> /// Draws army number into the map. TODO: respect to highlighting /// </summary> /// <param name="region">Region to draw it into.</param> /// <param name="army">Army number to draw.</param> public void OverDrawArmyNumber(Region region, int army) { // get color that match the region Color?colorOrNull = templateProcessor.GetColor(region); if (colorOrNull == null) { return; } // source color Color sourceColor = colorOrNull.Value; // recolor back to the previous color if (region.Owner != null) { coloringHandler.Recolor(sourceColor, Color.FromKnownColor(region.Owner.Color)); } else { // doesnt have owner => recolor to visible color coloringHandler.Recolor(sourceColor, Global.RegionVisibleUnoccupiedColor); } DrawArmyNumber(region, army); }
/// <summary> /// Resets attacking phase recoloring everything back. /// Notice: deploying phase passed in parameter must be corect in order /// to make this method work properly. /// </summary> /// <param name="attackingPhase">Attacking phase</param> /// <param name="deployingPhase">Deploying phase</param> public void ResetAttackingPhase(Attacking attackingPhase, Deploying deployingPhase) { // TODO: check + should not clear var attacks = attackingPhase.Attacks; IEnumerable <IGrouping <Region, Attack> > attackerRegionsGroups = from attack in attacks group attack by attack.Attacker; var regionAttackingArmyPairEnumerable = from gr in attackerRegionsGroups select new { Attacker = gr.Key, AttackingArmy = gr.Sum(x => x.AttackingArmy) }; foreach (var item in regionAttackingArmyPairEnumerable) { Region attacker = item.Attacker; IEnumerable <int> regionDeployedArmy = from tuple in deployingPhase.ArmiesDeployed where tuple.Region == attacker select tuple.Army; if (!regionDeployedArmy.Any()) { textDrawingHandler.OverDrawArmyNumber(attacker, attacker.Army); } else { int army = regionDeployedArmy.First(); textDrawingHandler.OverDrawArmyNumber(attacker, army); } OnImageChanged?.Invoke(); } }
/// <summary> /// Resets round, recoloring region selected by player to the default color. /// </summary> /// <param name="gameBeginningRound">What happened in the game round.</param> internal void ResetRound(GameBeginningTurn gameBeginningRound) { foreach (var tuple in gameBeginningRound.SelectedRegions) { Region region = tuple.Region; coloringHandler.Recolor(region, Global.RegionNotVisibleColor); } }
/// <summary> /// Seizes specified region for player on turn. /// </summary> /// <param name="region"></param> /// <param name="playerPerspective"></param> public void Seize(Region region, Player playerPerspective) { coloringHandler.Recolor(region, playerPerspective.Color); if (!isFogOfWar) { textDrawingHandler.DrawArmyNumber(region, region.Army); } OnImageChanged?.Invoke(); }
/// <summary> /// Resets deploying phase, recoloring everything to the previous color, /// redrawing everything to the original state. /// </summary> /// <param name="deployingPhase"></param> public void ResetDeployingPhase(Deploying deployingPhase) { foreach (var tuple in deployingPhase.ArmiesDeployed) { Region region = tuple.Region; if (region.Owner == null) { throw new ArgumentException(); } coloringHandler.Recolor(region, Color.FromKnownColor(region.Owner.Color)); textDrawingHandler.DrawArmyNumber(region, region.Army); } OnImageChanged?.Invoke(); }
/// <summary> /// Recolors given region to target color. /// </summary> /// <param name="region">Given region.</param> /// <param name="targetColor">Color that given region will be recolored to.</param> public void Recolor(Region region, Color targetColor) { if (region == null) { throw new ArgumentException("Region must not be null."); } Color?colorOrNull = templateProcessor.GetColor(region); if (colorOrNull == null) { throw new ArgumentException("There is no color matching region passed as parameter."); } Recolor(colorOrNull.Value, targetColor); }
/// <summary> /// Draws army number onto screen. Respects highlighting. /// </summary> /// <param name="region"></param> /// <param name="army"></param> public void DrawArmyNumber(Region region, int army) { // get color that match the region Color?colorOrNull = templateProcessor.GetColor(region); if (colorOrNull == null) { return; } // source color Color sourceColor = colorOrNull.Value; Rectangle rect = new Rectangle(0, 0, templateProcessor.RegionHighlightedImage.Width, templateProcessor.RegionHighlightedImage.Height); BitmapData bmpData = templateProcessor.RegionHighlightedImage.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); PointF point = default(PointF); try { IntPtr ptr = bmpData.Scan0; int stride = bmpData.Stride; var rgbValues = new byte[bmpData.Stride * bmpData.Height]; Marshal.Copy(ptr, rgbValues, 0, rgbValues.Length); PointF GetMatchingPoint() { for (int column = 0; column < bmpData.Height; column++) { Color previousColor = default(Color); for (int row = 0; row < bmpData.Width; row++) { byte red = rgbValues[column * stride + row * 3 + 2]; byte green = rgbValues[column * stride + row * 3 + 1]; byte blue = rgbValues[column * stride + row * 3]; Color color = Color.FromArgb(red, green, blue); // if it is point to draw and its in the correct region, get point coordinates if (color == Global.TextPlacementColor && previousColor == sourceColor) { return(new PointF(row, column)); } previousColor = color; } } throw new ArgumentException(); } // get point where to draw the number of armies point = GetMatchingPoint(); } finally { templateProcessor.RegionHighlightedImage.UnlockBits(bmpData); } Graphics gr = Graphics.FromImage(mapImage); gr.SmoothingMode = SmoothingMode.AntiAlias; gr.InterpolationMode = InterpolationMode.HighQualityBicubic; gr.PixelOffsetMode = PixelOffsetMode.HighQuality; // draw the string onto map gr.DrawString(army.ToString(), new Font("Tahoma", 8), Brushes.Black, point); gr.Flush(); }
public void Recolor(Region region, KnownColor targetColor) { Recolor(region, Color.FromKnownColor(targetColor)); }
/// <summary> /// Initializes an instance of MapImageProcessor. /// </summary> /// <param name="map">Map of the future game.</param> /// <param name="regionHighlightedImagePath"> /// Path of image whose role is to map region to certain color to recognize what /// image has been clicked on by the user. /// </param> /// <param name="regionColorMappingPath">Path of file mapping color to certain existing map region.</param> /// <param name="mapImagePath">Map of image that will be used as map and displayed to the user.</param> /// <param name="isFogOfWar">True, if the given map should be processed as fog of war type.</param> /// <returns>Initialized instance.</returns> public static MapImageProcessor Create(Map map, string regionHighlightedImagePath, string regionColorMappingPath, string mapImagePath, bool isFogOfWar) { Bitmap regionHighlightedImage = new Bitmap(regionHighlightedImagePath); Bitmap image = new Bitmap(mapImagePath); // images are not equally sized if (image.Size != regionHighlightedImage.Size) { throw new ArgumentException(); } // read the file XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation; settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; settings.ValidationEventHandler += (sender, args) => { switch (args.Severity) { case XmlSeverityType.Error: throw new XmlSchemaValidationException(); case XmlSeverityType.Warning: break; default: throw new ArgumentOutOfRangeException(); } }; var dictionary = new Dictionary <Color, Region>(); using (XmlReader reader = XmlReader.Create(regionColorMappingPath, settings)) { Color color = default(Color); Region region = default(Region); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.Name) { case "Entry": break; case nameof(Color): // TODO : maybe better way is possible byte red = Convert.ToByte(reader.GetAttribute("Red")); byte green = Convert.ToByte(reader.GetAttribute("Green")); byte blue = Convert.ToByte(reader.GetAttribute("Blue")); byte alpha = Convert.ToByte(reader.GetAttribute("Alpha")); color = Color.FromArgb(alpha, red, green, blue); break; case nameof(Region): region = (from item in map.Regions where item.Name == reader.GetAttribute("Name") select item).First(); break; } break; case XmlNodeType.EndElement: if (reader.Name == "Entry") { dictionary.Add(color, region); } break; } } } MapImageTemplateProcessor mapImageTemplateProcessor = new MapImageTemplateProcessor(map, regionHighlightedImage, dictionary); ColoringHandler coloringHandler = new ColoringHandler(image, mapImageTemplateProcessor); TextDrawingHandler textDrawingHandler = new TextDrawingHandler(image, mapImageTemplateProcessor, coloringHandler); HighlightHandler highlightHandler = new HighlightHandler(image, mapImageTemplateProcessor, textDrawingHandler, coloringHandler); SelectRegionHandler selectRegionHandler = new SelectRegionHandler(mapImageTemplateProcessor, highlightHandler, isFogOfWar); return(new MapImageProcessor(mapImageTemplateProcessor, image, textDrawingHandler, coloringHandler, selectRegionHandler, isFogOfWar)); }
/// <summary> /// Deploys army graphically. /// </summary> /// <param name="region"></param> /// <param name="newArmy"></param> public void Deploy(Region region, int newArmy) { textDrawingHandler.OverDrawArmyNumber(region, newArmy); OnImageChanged?.Invoke(); }
/// <summary> /// Returns color mapped to region. If no such regions is found, null is returned. /// </summary> /// <param name="region">Region to match the color.</param> /// <returns>Color matching the region.</returns> public Color?GetColor(Region region) { bool correct = regionsColorsMapped.TryGetValue(region, out Color color); return(correct ? new Color?(color) : null); }
/// <summary> /// Is region selected? /// </summary> /// <param name="region"></param> /// <returns></returns> public bool IsSelected(Region region) { return(selectedRegions.Any(x => x == region)); }
/// <summary> /// Initializes map instance. /// </summary> /// <param name="templatePath"></param> private void Initialize(string templatePath) { IList <SuperRegion> superRegions = new List <SuperRegion>(); IList <Region> regions = new List <Region>(); // set validation against xsd settings XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation; settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings; settings.ValidationEventHandler += (sender, args) => { switch (args.Severity) { case XmlSeverityType.Error: throw new XmlSchemaValidationException(); case XmlSeverityType.Warning: break; default: throw new ArgumentOutOfRangeException(); } }; // verify xml against loaded xsd, read everything except for neighbours using (XmlReader reader = XmlReader.Create(templatePath, settings)) { #region SuperRegion stats int superRegionCounter = 1; bool isSuperRegionElement = false; #endregion #region Region stats int regionCounter = 1; bool isRegionElement = false; #endregion bool isNeighbours = false; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.Name) { case nameof(SuperRegion): isSuperRegionElement = true; if (!isRegionElement && !isNeighbours) // is SuperRegion attribute { string superRegionName = reader.GetAttribute("Name"); int superRegionBonus = int.Parse(reader.GetAttribute("Bonus")); SuperRegion superRegion = new SuperRegion(superRegionCounter++, superRegionName, superRegionBonus); superRegions.Add(superRegion); } break; case nameof(Region): isRegionElement = true; if (isSuperRegionElement && !isNeighbours) // is Region element { string regionName = reader.GetAttribute("Name"); // TODO: may drop int army = int.Parse(reader.GetAttribute("Army")); Region region = new Region(regionCounter++, regionName, superRegions.Last()) { Army = army }; regions.Add(region); superRegions.Last().Regions.Add(region); } break; case "Neighbours": isNeighbours = true; break; } break; case XmlNodeType.EndElement: switch (reader.Name) { case nameof(SuperRegion): // reset isSuperRegionElement = false; break; case nameof(Region): // reset isRegionElement = false; break; case "Neighbours": isNeighbours = false; break; } break; } } } // dont verify, just read neighbours and load them appropriately using (XmlReader reader = XmlReader.Create(templatePath)) { bool isSuperRegion = false; int isRegion = 0; Region givenRegion = null; bool isNeighbours = false; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.Name) { case nameof(SuperRegion): isSuperRegion = true; break; case nameof(Region): isRegion++; if (isSuperRegion && isRegion == 1 && !isNeighbours) { givenRegion = (from region in regions where region.Name == reader.GetAttribute("Name") select region).First(); } else if (isSuperRegion && isRegion == 2 && isNeighbours) { // find region with this name and add it to given regions neighbours // TODO: slow Region regionsNeighbour = (from region in regions where region.Name == reader.GetAttribute("Name") select region).First(); givenRegion.NeighbourRegions.Add(regionsNeighbour); // empty element doesnt invoke EndElement action, so => if (reader.IsEmptyElement) { isRegion--; } } break; case "Neighbours": isNeighbours = true; break; } break; case XmlNodeType.EndElement: switch (reader.Name) { case nameof(SuperRegion): isSuperRegion = false; break; case nameof(Region): isRegion--; if (isSuperRegion && isRegion == 0 && !isNeighbours) { givenRegion = null; } break; case "Neighbours": isNeighbours = false; break; } break; } } } SuperRegions = superRegions; Regions = regions; #if DEBUG var exceptions = ValidateRegionsSymmetry().ToList(); if (exceptions.Any()) { throw new AggregateException(exceptions); } #endif }