Exemplo n.º 1
0
        public void setCreature(string species, int[] colorIDs)
        {
            this.colorIDs = colorIDs;

            int si = Values.V.speciesNames.IndexOf(species);

            if (si >= 0 && Values.V.species[si].colors != null)
            {
                colorRegions = Values.V.species[si].colors;
            }
            else
            {
                // species-info is not available, show all region-buttons
                colorRegions = new List <ColorRegion>();
                for (int i = 0; i < 6; i++)
                {
                    colorRegions.Add(new ColorRegion());
                    colorRegions[i].name = "n/a";
                }
            }
            for (int r = 0; r < buttonColors.Length; r++)
            {
                ColorRegionsUseds[r]    = colorRegions[r].name != null;
                buttonColors[r].Visible = ColorRegionsUseds[r];

                if (buttonColors[r].Visible)
                {
                    setColorButton(buttonColors[r], CreatureColors.creatureColor(colorIDs[r]));
                    tt.SetToolTip(buttonColors[r], colorRegions[r].name);
                }
            }
        }
Exemplo n.º 2
0
 public void Clear()
 {
     for (int r = 0; r < buttonColors.Length; r++)
     {
         buttonColors[r].Hide();
         setColorButton(buttonColors[r], CreatureColors.creatureColor(0));
     }
 }
Exemplo n.º 3
0
 private static int parseColor(string text)
 {
     double.TryParse(text.Substring(3, 8), out double r);
     double.TryParse(text.Substring(14, 8), out double g);
     double.TryParse(text.Substring(25, 8), out double b);
     return(CreatureColors.closestColorIDFromRGB(LinearColorComponentToColorComponent(r),
                                                 LinearColorComponentToColorComponent(g),
                                                 LinearColorComponentToColorComponent(b)));
 }
Exemplo n.º 4
0
 private static int parseColor(string text)
 {
     double.TryParse(text.Substring(3, 8), System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowLeadingSign, System.Globalization.CultureInfo.GetCultureInfo("en-US"), out double r);
     double.TryParse(text.Substring(14, 8), System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowLeadingSign, System.Globalization.CultureInfo.GetCultureInfo("en-US"), out double g);
     double.TryParse(text.Substring(25, 8), System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowLeadingSign, System.Globalization.CultureInfo.GetCultureInfo("en-US"), out double b);
     return(CreatureColors.closestColorIDFromRGB(LinearColorComponentToColorComponent(r),
                                                 LinearColorComponentToColorComponent(g),
                                                 LinearColorComponentToColorComponent(b)));
 }
Exemplo n.º 5
0
        private void setColorButton(Button bt, int region)
        {
            int   colorId = _colorIDs[region];
            Color cl      = CreatureColors.creatureColor(colorId);

            bt.BackColor = cl;
            bt.ForeColor = Utils.ForeColor(cl);
            // tooltip
            if (colorRegions != null)
            {
                tt.SetToolTip(bt, colorRegions[region].name + " (" + region.ToString() + "):\n" + CreatureColors.creatureColorName(colorId) + " (" + colorId.ToString() + ")");
            }
        }
        private void setColorButton(Button bt, int region)
        {
            int   colorId = _colorIDs[region];
            Color cl      = CreatureColors.creatureColor(colorId);

            bt.BackColor = cl;
            bt.ForeColor = Utils.ForeColor(cl);
            // tooltip
            if (colorRegions != null)
            {
                tt.SetToolTip(bt, $"{colorRegions[region].name} ({region}):\n{CreatureColors.creatureColorName(colorId)} ({colorId})");
            }
        }
Exemplo n.º 7
0
 private void chooseColor(int region, Button sender)
 {
     if (creatureList[0] != null && !cp.isShown)
     {
         cp.SetColors(colors[region], "Region " + region);
         if (cp.ShowDialog() == DialogResult.OK)
         {
             // color was chosen
             colors[region] = cp.SelectedColorId;
             sender.SetBackColorAndAccordingForeColor(CreatureColors.CreatureColor(colors[region]));
             pictureBox1.SetImageAndDisposeOld(CreatureColored.GetColoredCreature(colors, uniqueSpecies ? creatureList[0].Species : null,
                                                                                  new[] { true, true, true, true, true, true }));
         }
     }
 }
        private void SetColorButton(Button bt, int region)
        {
            int colorId = _selectedRegionColorIds[region];

            bt.SetBackColorAndAccordingForeColor(CreatureColors.CreatureColor(colorId));
            if (VerboseButtonTexts)
            {
                bt.Text = $"[{region}]: {colorId}";
            }
            // tooltip
            if (_colorRegions?[region] != null)
            {
                _tt.SetToolTip(bt, $"{_colorRegions[region].name} ({region}):\n{CreatureColors.CreatureColorName(colorId)} ({colorId})");
            }
        }
        public static string RegionColorInfo(Species species, int[] colorIds)
        {
            string creatureRegionColors = "";

            if (species != null)
            {
                var cs = species.colors;
                creatureRegionColors = "Colors:";
                for (int r = 0; r < 6; r++)
                {
                    if (!string.IsNullOrEmpty(cs[r]?.name))
                    {
                        creatureRegionColors += $"\n{cs[r].name} ({r}): {CreatureColors.creatureColorName(colorIds[r])} ({colorIds[r]})";
                    }
                }
            }
            return(creatureRegionColors);
        }
Exemplo n.º 10
0
        public static string RegionColorInfo(string species, int[] colorIds)
        {
            string creatureRegionColors = "";
            int    si = Values.V.speciesIndex(species);

            if (si >= 0)
            {
                var cs = Values.V.species[si].colors;
                creatureRegionColors = "Colors:";
                for (int r = 0; r < 6; r++)
                {
                    if (cs[r].name != null)
                    {
                        creatureRegionColors += $"\n{cs[r].name} ({r}): {CreatureColors.creatureColorName(colorIds[r])} ({colorIds[r]})";
                    }
                }
            }
            return(creatureRegionColors);
        }
Exemplo n.º 11
0
        public static string RegionColorInfo(Species species, int[] colorIds)
        {
            if (species == null || colorIds == null)
            {
                return(null);
            }

            var creatureRegionColors = new StringBuilder("Colors:");
            var cs = species.colors;

            for (int r = 0; r < Species.ColorRegionCount; r++)
            {
                if (!string.IsNullOrEmpty(cs[r]?.name))
                {
                    creatureRegionColors.Append($"\n{cs[r].name} ({r}): {CreatureColors.CreatureColorName(colorIds[r])} ({colorIds[r]})");
                }
            }
            return(creatureRegionColors.ToString());
        }
        private static string FunctionColor(Match m, NamePatternParameters p)
        {
            // parameter 1: region id (0,...,5), 2: if not empty, the color name instead of the numerical id is returned, 3: if not empty, the function will return also a value even if the color region is not used on that species.
            if (!int.TryParse(m.Groups[2].Value, out int regionId) ||
                regionId < 0 || regionId > 5)
            {
                return(ParametersInvalid("color region id has to be a number in the range 0 - 5", m.Groups[0].Value, p.DisplayError));
            }

            if (!p.Creature.Species.EnabledColorRegions[regionId] &&
                string.IsNullOrWhiteSpace(m.Groups[4].Value))
            {
                return(string.Empty); // species does not use this region and user doesn't want it (param 3 is empty)
            }
            if (p.Creature.colors == null)
            {
                return(string.Empty);                           // no color info
            }
            if (string.IsNullOrWhiteSpace(m.Groups[3].Value))
            {
                return(p.Creature.colors[regionId].ToString());
            }
            return(CreatureColors.CreatureColorName(p.Creature.colors[regionId]));
        }
Exemplo n.º 13
0
        /// <summary>
        /// Creates an image with infos about the creature.
        /// </summary>
        /// <param name="creature"></param>
        /// <returns></returns>
        public static Bitmap InfoGraphic(this Creature creature)
        {
            if (creature == null)
            {
                return(null);
            }

            const int width  = 300;
            const int height = 150;

            var bmp = new Bitmap(width, height);

            using (var g = Graphics.FromImage(bmp))
                using (var font = new Font("Arial", 10))
                    using (var fontSmall = new Font("Arial", 8))
                        using (var fontHeader = new Font("Arial", 12, FontStyle.Bold))
                            using (var fontBrush = new SolidBrush(Color.Black))
                                using (var stringFormatRight = new StringFormat()
                                {
                                    Alignment = StringAlignment.Far
                                })
                                {
                                    using (var backgroundBrush = new SolidBrush(Color.AntiqueWhite))
                                        g.FillRectangle(backgroundBrush, 0, 0, width, height);
                                    g.DrawString($"{creature.Species.DescriptiveNameAndMod} (Lvl {creature.LevelHatched})", fontHeader, fontBrush, 3, 3);

                                    const int yBelowHeader = 20;
                                    // levels
                                    const int xStatName   = 8;
                                    int       xLevelValue = xStatName + 30 + (creature.levelsWild[2].ToString().Length) * 7;
                                    g.DrawString("Levels", font, fontBrush, xStatName, yBelowHeader);
                                    int statDisplayIndex = 0;
                                    for (int si = 0; si < Values.STATS_COUNT; si++)
                                    {
                                        int statIndex = Values.statsDisplayOrder[si];
                                        if (creature.Species.UsesStat(statIndex))
                                        {
                                            int y = yBelowHeader + 20 + (statDisplayIndex++) * 13;
                                            g.DrawString($"{Utils.statName(statIndex, true, creature.Species.IsGlowSpecies)}",
                                                         font, fontBrush, xStatName, y);
                                            g.DrawString($"{creature.levelsWild[statIndex]}",
                                                         font, fontBrush, xLevelValue, y, stringFormatRight);
                                        }
                                    }

                                    // colors
                                    int xColor = xLevelValue + 20;
                                    g.DrawString("Colors", font, fontBrush, xColor, yBelowHeader);
                                    int colorIndex = 0;
                                    for (int ci = 0; ci < Species.COLOR_REGION_COUNT; ci++)
                                    {
                                        if (!string.IsNullOrEmpty(creature.Species.colors[ci]?.name))
                                        {
                                            const int circleDiameter = 16;
                                            const int rowHeight      = circleDiameter + 2;
                                            int       y = yBelowHeader + 20 + (colorIndex++) * rowHeight;

                                            Color c  = CreatureColors.creatureColor(creature.colors[ci]);
                                            Color fc = Utils.ForeColor(c);

                                            using (var b = new SolidBrush(c))
                                                g.FillEllipse(b, xColor, y, circleDiameter, circleDiameter);
                                            using (var p = new Pen(Color.Black, 1))
                                                g.DrawEllipse(p, xColor, y, circleDiameter, circleDiameter);

                                            g.DrawString($"[{ci}] {creature.Species.colors[ci].name}: [{creature.colors[ci]}] {CreatureColors.creatureColorName(creature.colors[ci])}",
                                                         fontSmall, fontBrush, xColor + circleDiameter + 4, y);
                                        }
                                    }
                                }

            return(bmp);
        }
Exemplo n.º 14
0
        private void DrawData(Creature creature, bool highlight, int highlightStatIndex, ToolTip tt)
        {
            if (creature?.Species == null)
            {
                return;
            }

            var usedStats    = Enumerable.Range(0, Values.STATS_COUNT).Where(si => si != (int)StatNames.Torpidity && creature.Species.UsesStat(si)).ToArray();
            var anglePerStat = 360f / usedStats.Length;

            const int borderWidth = 1;

            // used for the tooltip text
            var colors = new ArkColor[Species.ColorRegionCount];

            (_statInheritances, _mutationInColor) = DetermineInheritanceAndMutations(creature, usedStats);

            var mutationOccurred = _mutationInColor != null;

            Bitmap bmp = new Bitmap(Width, Height);

            using (Graphics g = Graphics.FromImage(bmp))
                using (var font = new Font("Microsoft Sans Serif", _fontSize))
                    using (var pen = new Pen(Color.Black))
                        using (var brush = new SolidBrush(Color.Black))
                        {
                            g.SmoothingMode = SmoothingMode.AntiAlias;

                            var   borderColor      = Color.FromArgb(219, 219, 219);
                            float drawnBorderWidth = borderWidth;
                            if (highlight)
                            {
                                borderColor      = Color.DodgerBlue;
                                drawnBorderWidth = 1.5f;
                            }
                            else
                            {
                                Cursor = Cursors.Hand;
                                if (highlightStatIndex != -1)
                                {
                                    borderColor = Color.Black;
                                }
                            }

                            if (mutationOccurred)
                            {
                                borderColor      = Utils.MutationMarkerColor;
                                drawnBorderWidth = 1.5f;
                            }

                            pen.Color = borderColor;
                            pen.Width = drawnBorderWidth;
                            g.DrawRectangle(pen, drawnBorderWidth, drawnBorderWidth, Width - 2 * drawnBorderWidth, Height - 2 * drawnBorderWidth);

                            // stats
                            var chartMax          = CreatureCollection.CurrentCreatureCollection?.maxChartLevel ?? 50;
                            int radiusInnerCircle = (_statSize - 2 * borderWidth) / 7;
                            int centerCoord       = _statSize / 2 - 1;

                            var i = 0;
                            if (creature.levelsWild != null)
                            {
                                pen.Color = Color.Black;
                                foreach (var si in usedStats)
                                {
                                    var level = creature.levelsWild[si];

                                    var statSize  = Math.Min((double)level / chartMax, 1);
                                    var pieRadius = (int)(radiusInnerCircle + (centerCoord - radiusInnerCircle - borderWidth) * statSize);
                                    var leftTop   = centerCoord - pieRadius;
                                    var angle     = AngleOffset + anglePerStat * i++;
                                    brush.Color = Utils.GetColorFromPercent((int)(100 * statSize), creature.topBreedingStats[si] ? 0 : 0.7);
                                    g.FillPie(brush, leftTop, leftTop, 2 * pieRadius, 2 * pieRadius, angle, anglePerStat);

                                    pen.Width = highlightStatIndex == si ? 2 : 1;
                                    g.DrawPie(pen, leftTop, leftTop, 2 * pieRadius, 2 * pieRadius, angle, anglePerStat);

                                    var       mutationStatus  = _statInheritances[si];
                                    const int anyMutationMask = 0b01110111;
                                    if ((mutationStatus & anyMutationMask) == 0)
                                    {
                                        continue;
                                    }

                                    const int mutationIsNotGuaranteedMask = 0b10001000;
                                    var       guaranteedMutation          = (mutationStatus & mutationIsNotGuaranteedMask) == 0;

                                    var anglePosition = Math.PI * 2 / 360 * (angle + anglePerStat / 2);
                                    var x             = (int)Math.Round(pieRadius * Math.Cos(anglePosition) + centerCoord - _mutationMarkerRadius - 1);
                                    var y             = (int)Math.Round(pieRadius * Math.Sin(anglePosition) + centerCoord - _mutationMarkerRadius - 1);
                                    DrawFilledCircle(g, brush, pen, guaranteedMutation ? Utils.MutationMarkerColor : Utils.MutationMarkerPossibleColor, x, y, 2 * _mutationMarkerRadius);
                                }
                            }

                            // draw sex in the center
                            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                            brush.Color         = Utils.AdjustColorLight(Utils.SexColor(creature.sex), 0.2);
                            g.FillEllipse(brush, centerCoord - radiusInnerCircle, centerCoord - radiusInnerCircle, 2 * radiusInnerCircle, 2 * radiusInnerCircle);
                            pen.Width = 1;
                            g.DrawEllipse(pen, centerCoord - radiusInnerCircle, centerCoord - radiusInnerCircle, 2 * radiusInnerCircle, 2 * radiusInnerCircle);

                            brush.Color = Color.Black;
                            using (var format = new StringFormat
                            {
                                Alignment = StringAlignment.Center,
                                LineAlignment = StringAlignment.Center
                            })
                            {
                                g.DrawString(Utils.SexSymbol(creature.sex), font, brush,
                                             new RectangleF(centerCoord - radiusInnerCircle + 1, centerCoord - radiusInnerCircle + 2, 2 * radiusInnerCircle, 2 * radiusInnerCircle),
                                             format);
                                g.DrawString(creature.name, font, brush,
                                             new RectangleF(borderWidth, _statSize + borderWidth - 2, ControlWidth - borderWidth, _colorSize),
                                             format);
                            }

                            // colors
                            if (creature.colors != null)
                            {
                                var displayedColorRegions = Enumerable.Range(0, Species.ColorRegionCount)
                                                            .Where(ci => creature.Species.EnabledColorRegions[ci]).ToArray();

                                var usedColorRegionCount = displayedColorRegions.Length;
                                if (usedColorRegionCount != 0)
                                {
                                    const int margin    = 1;
                                    var       colorSize = new Size(_colorSize - 3 * margin - borderWidth,
                                                                   (_statSize - 2 * borderWidth) / usedColorRegionCount - 3 * margin);

                                    // only check for color mutations if the colors of both parents are available
                                    mutationOccurred = mutationOccurred && creature.Mother?.colors != null &&
                                                       creature.Father?.colors != null;

                                    i = 0;
                                    var left = _statSize + 2 * margin;
                                    foreach (var ci in displayedColorRegions)
                                    {
                                        var color = CreatureColors.CreatureArkColor(creature.colors[ci]);
                                        colors[ci]  = color;
                                        brush.Color = color.Color;
                                        var y = borderWidth + margin + i++ *(colorSize.Height + 2 * margin);
                                        g.FillRectangle(brush, left, y, colorSize.Width,
                                                        colorSize.Height);
                                        g.DrawRectangle(pen, left, y, colorSize.Width,
                                                        colorSize.Height);

                                        var colorMutationOccurred =
                                            mutationOccurred && creature.colors[ci] != creature.Mother.colors[ci] &&
                                            creature.colors[ci] != creature.Father.colors[ci];
                                        if (colorMutationOccurred)
                                        {
                                            var x = left - _colorMutationMarkerRadius - 2;
                                            y = y + colorSize.Height / 2 - _colorMutationMarkerRadius;
                                            DrawFilledCircle(g, brush, pen, Color.Yellow, x, y, 2 * _colorMutationMarkerRadius);
                                            _mutationInColor[ci] = true;
                                        }
                                    }
                                }
                            }

                            if (_mutationInColor != null && !_mutationInColor.Any(m => m))
                            {
                                _mutationInColor = null; // not needed, no possible mutations
                            }
                            // mutation indicator
                            if (!creature.flags.HasFlag(CreatureFlags.Placeholder))
                            {
                                int   yMarker       = _statSize - _mutationIndicatorSize - 1 - borderWidth;
                                Color mutationColor = creature.Mutations == 0 ? Color.GreenYellow
                        : creature.Mutations < GameConstants.MutationPossibleWithLessThan ? Utils.MutationColor
                        : Color.DarkRed;

                                DrawFilledCircle(g, brush, pen, mutationColor, borderWidth + 1, yMarker, _mutationIndicatorSize);
                            }
                        }

            var oldImage = Image;

            Image = bmp;
            oldImage?.Dispose();

            var statNames = creature.Species?.statNames;

            var toolTipText = $"{creature.name} ({Utils.SexSymbol(creature.sex)})";

            if (creature.flags.HasFlag(CreatureFlags.Placeholder))
            {
                toolTipText += "\nThis creature is not yet in this library. This entry is a placeholder and contains no more info";
            }
            else
            {
                string InheritanceExplanation(int statIndex)
                {
                    var mutationStatus = _statInheritances[statIndex];

                    if (mutationStatus == 0)
                    {
                        return(null);
                    }
                    var resultMother = Mutation(true);
                    var resultFather = Mutation(false);

                    if (resultMother == null && resultFather == null)
                    {
                        return(null);
                    }

                    return($" ({resultMother}{(resultMother != null && resultFather != null ? " or " : null)}{resultFather})");

                    string Mutation(bool mother)
                    {
                        var status = (mutationStatus >> (!mother ? 4 : 0)) & 0xf;

                        if (status == 0)
                        {
                            return(null);
                        }
                        var sex = mother ? "♀" : "♂";

                        if (status == 8)
                        {
                            return(sex);
                        }
                        if (status > 8)
                        {
                            var mutationCount = status & 7;
                            return($"{sex} with possible {mutationCount} mutation{(mutationCount > 1 ? "s" : null)}");
                        }
                        return($"{sex} with {status} mutation{(status > 1 ? "s" : null)}");
                    }
                }

                if (creature.levelsWild != null)
                {
                    toolTipText +=
                        $"\n{string.Join("\n", usedStats.Select(si => $"{Utils.StatName(si, true, statNames)}:\t{creature.levelsWild[si],3}{InheritanceExplanation(si)}"))}";
                }
                toolTipText +=
                    $"\n{Loc.S("Mutations")}: {creature.Mutations} = {creature.mutationsMaternal} (♀) + {creature.mutationsPaternal} (♂)";
                if (creature.colors != null)
                {
                    toolTipText +=
                        $"\n{Loc.S("Colors")}\n{string.Join("\n", colors.Select((c, i) => c == null ? null : $"[{i}]:\t{c.Id} ({c.Name}){((_mutationInColor?[i] ?? false) ? " (mutated color)" : null)}").Where(s => s != null))}";
                }
            }
Exemplo n.º 15
0
        /// <summary>
        /// Creates a colored species image and saves it as cache file. Returns true when created successful.
        /// </summary>
        /// <returns></returns>
        private static bool CreateAndSaveCacheSpeciesFile(int[] colorIds, bool[] enabledColorRegions,
                                                          string speciesBackgroundFilePath, string speciesColorMaskFilePath, string cacheFilePath, int outputSize = 256)
        {
            if (string.IsNullOrEmpty(cacheFilePath) ||
                !File.Exists(speciesBackgroundFilePath))
            {
                return(false);
            }

            using (Bitmap bmpBackground = new Bitmap(speciesBackgroundFilePath))
                using (Bitmap bmpColoredCreature = new Bitmap(bmpBackground.Width, bmpBackground.Height, PixelFormat.Format32bppArgb))
                    using (Graphics graph = Graphics.FromImage(bmpColoredCreature))
                    {
                        bool imageFine = true;
                        graph.SmoothingMode = SmoothingMode.AntiAlias;

                        //// ellipse shadow
                        const int    scx = TemplateSize / 2;
                        const int    scy = (int)(scx * 1.6);
                        const double perspectiveFactor = 0.3;
                        const int    yStart            = scy - (int)(perspectiveFactor * .7 * scx);
                        const int    yEnd       = (int)(2 * perspectiveFactor * scx);
                        GraphicsPath pathShadow = new GraphicsPath();
                        pathShadow.AddEllipse(0, yStart, TemplateSize, yEnd);
                        var colorBlend = new ColorBlend
                        {
                            Colors    = new[] { Color.FromArgb(0), Color.FromArgb(40, 0, 0, 0), Color.FromArgb(80, 0, 0, 0) },
                            Positions = new[] { 0, 0.6f, 1 }
                        };
                        PathGradientBrush pthGrBrush = new PathGradientBrush(pathShadow)
                        {
                            InterpolationColors = colorBlend
                        };
                        graph.FillEllipse(pthGrBrush, 0, yStart, TemplateSize, yEnd);
                        // shadow done

                        // shaded base image
                        graph.DrawImage(bmpBackground, 0, 0, TemplateSize, TemplateSize);

                        // if species has color regions, apply colors
                        if (File.Exists(speciesColorMaskFilePath))
                        {
                            var rgb             = new byte[Species.ColorRegionCount][];
                            var useColorRegions = new bool[Species.ColorRegionCount];
                            for (int c = 0; c < Species.ColorRegionCount; c++)
                            {
                                useColorRegions[c] = enabledColorRegions[c] && colorIds[c] != 0;
                                if (useColorRegions[c])
                                {
                                    Color cl = CreatureColors.CreatureColor(colorIds[c]);
                                    rgb[c] = new[] { cl.R, cl.G, cl.B };
                                }
                            }
                            imageFine = ApplyColorsUnsafe(rgb, useColorRegions, speciesColorMaskFilePath, TemplateSize, bmpBackground, bmpColoredCreature);
                        }

                        if (imageFine)
                        {
                            string cacheFolder = Path.GetDirectoryName(cacheFilePath);
                            if (string.IsNullOrEmpty(cacheFolder))
                            {
                                return(false);
                            }
                            if (!Directory.Exists(cacheFolder))
                            {
                                Directory.CreateDirectory(cacheFolder);
                            }
                            if (outputSize == TemplateSize)
                            {
                                return(SaveBitmapToFile(bmpColoredCreature, cacheFilePath));
                            }

                            using (var resized = new Bitmap(outputSize, outputSize))
                                using (var g = Graphics.FromImage(resized))
                                {
                                    g.CompositingQuality = CompositingQuality.HighQuality;
                                    g.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                                    g.SmoothingMode      = SmoothingMode.HighQuality;
                                    g.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                                    g.DrawImage(bmpColoredCreature, 0, 0, outputSize, outputSize);
                                    return(SaveBitmapToFile(resized, cacheFilePath));
                                }
                        }
                    }

            return(false);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Creates an image with infos about the creature.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="cc">CreatureCollection for server settings.</param>
        /// <returns></returns>
        public static Bitmap InfoGraphic(this Creature creature, CreatureCollection cc)
        {
            if (creature == null)
            {
                return(null);
            }
            int maxGraphLevel = cc?.maxChartLevel ?? 0;

            if (maxGraphLevel < 1)
            {
                maxGraphLevel = 50;
            }

            const int width  = 330;
            const int height = 180;

            var bmp = new Bitmap(width, height);

            using (var g = Graphics.FromImage(bmp))
                using (var font = new Font("Arial", 10))
                    using (var fontSmall = new Font("Arial", 8))
                        using (var fontHeader = new Font("Arial", 12, FontStyle.Bold))
                            using (var fontBrush = new SolidBrush(Color.Black))
                                using (var penBlack = new Pen(Color.Black, 1))
                                    using (var stringFormatRight = new StringFormat()
                                    {
                                        Alignment = StringAlignment.Far
                                    })
                                    {
                                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                                        int currentYPosition = 3;

                                        using (var backgroundBrush = new SolidBrush(Color.AntiqueWhite))
                                            g.FillRectangle(backgroundBrush, 0, 0, width, height);

                                        g.DrawString(creature.Species.DescriptiveNameAndMod, fontHeader, fontBrush, 3, currentYPosition);
                                        currentYPosition += 19;
                                        g.DrawString($"Level {creature.LevelHatched} | {Utils.SexSymbol(creature.sex) + (creature.flags.HasFlag(CreatureFlags.Neutered) ? $" ({Loc.S(creature.sex == Sex.Female ? "Spayed" : "Neutered")})" : string.Empty)} | {creature.Mutations} mutations | generation {creature.generation}", font, fontBrush, 8, currentYPosition);
                                        currentYPosition += 17;

                                        using (var p = new Pen(Color.LightGray, 1))
                                            g.DrawLine(p, 0, currentYPosition, width, currentYPosition);
                                        currentYPosition += 2;

                                        // levels
                                        const int xStatName     = 8;
                                        int       xLevelValue   = xStatName + 30 + (creature.levelsWild[2].ToString().Length) * 7;
                                        int       xRightBrValue = xLevelValue + 14 + MaxBreedingValueLength(creature.valuesBreeding) * 7;
                                        int       maxBoxLength  = xRightBrValue - xStatName;
                                        const int statBoxHeight = 2;
                                        g.DrawString("Levels", font, fontBrush, xLevelValue, currentYPosition, stringFormatRight);
                                        g.DrawString("Values", font, fontBrush, xRightBrValue, currentYPosition, stringFormatRight);
                                        int statDisplayIndex = 0;
                                        for (int si = 0; si < Values.STATS_COUNT; si++)
                                        {
                                            int statIndex = Values.statsDisplayOrder[si];
                                            if (statIndex == (int)StatNames.Torpidity || !creature.Species.UsesStat(statIndex))
                                            {
                                                continue;
                                            }

                                            int y = currentYPosition + 20 + (statDisplayIndex++) * 15;

                                            // box
                                            // empty box to show the max possible length
                                            using (var b = new SolidBrush(Color.DarkGray))
                                                g.FillRectangle(b, xStatName, y + 14, maxBoxLength, statBoxHeight);
                                            double levelFractionOfMax = Math.Min(1, (double)creature.levelsWild[statIndex] / maxGraphLevel);
                                            if (levelFractionOfMax < 0)
                                            {
                                                levelFractionOfMax = 0;
                                            }
                                            int levelPercentageOfMax = (int)(100 * levelFractionOfMax);
                                            int statBoxLength        = Math.Max((int)(maxBoxLength * levelFractionOfMax), 1);
                                            var statColor            = Utils.GetColorFromPercent(levelPercentageOfMax);
                                            using (var b = new SolidBrush(statColor))
                                                g.FillRectangle(b, xStatName, y + 14, statBoxLength, statBoxHeight);
                                            using (var b = new SolidBrush(Color.FromArgb(10, statColor)))
                                            {
                                                for (int r = 4; r > 0; r--)
                                                {
                                                    g.FillRectangle(b, xStatName - r, y + 13 - r, statBoxLength + 2 * r, statBoxHeight + 2 * r);
                                                }
                                            }
                                            using (var p = new Pen(Utils.GetColorFromPercent(levelPercentageOfMax, -0.5), 1))
                                                g.DrawRectangle(p, xStatName, y + 14, statBoxLength, statBoxHeight);

                                            // stat name
                                            g.DrawString($"{Utils.StatName(statIndex, true, creature.Species.statNames)}",
                                                         font, fontBrush, xStatName, y);
                                            // stat level number
                                            g.DrawString($"{creature.levelsWild[statIndex]}",
                                                         font, fontBrush, xLevelValue, y, stringFormatRight);
                                            // stat breeding value
                                            string statValueRepresentation;
                                            if (Utils.Precision(statIndex) == 3)
                                            {
                                                statValueRepresentation = (100 * creature.valuesBreeding[statIndex]).ToString("0.0");
                                                g.DrawString("%", font, fontBrush, xRightBrValue, y);
                                            }
                                            else
                                            {
                                                statValueRepresentation = creature.valuesBreeding[statIndex].ToString("0.0");
                                            }
                                            g.DrawString(statValueRepresentation, font, fontBrush, xRightBrValue, y, stringFormatRight);
                                        }

                                        // colors
                                        var       enabledColorRegions = creature.Species.EnabledColorRegions;
                                        bool      creatureImageShown  = false;
                                        const int imageSize           = 125;
                                        using (var crBmp =
                                                   CreatureColored.GetColoredCreature(creature.colors, creature.Species, enabledColorRegions, imageSize, onlyImage: true, creatureSex: creature.sex))
                                        {
                                            if (crBmp != null)
                                            {
                                                g.DrawImage(crBmp, 200, 40, imageSize, imageSize);
                                                creatureImageShown = true;
                                            }
                                        }

                                        int       xColor             = xRightBrValue + 25;
                                        const int circleDiameter     = 16;
                                        const int rowHeight          = circleDiameter + 2;
                                        int       maxColorNameLength = (width - xColor - circleDiameter) / 6; // max char length for the color region name
                                        if (maxColorNameLength < 0)
                                        {
                                            maxColorNameLength = 0;
                                        }
                                        g.DrawString("Colors", font, fontBrush, xColor, currentYPosition);
                                        int colorRow = 0;
                                        for (int ci = 0; ci < Species.ColorRegionCount; ci++)
                                        {
                                            if (!enabledColorRegions[ci])
                                            {
                                                continue;
                                            }

                                            int y = currentYPosition + 20 + (colorRow++) * rowHeight;

                                            Color c = CreatureColors.CreatureColor(creature.colors[ci]);
                                            //Color fc = Utils.ForeColor(c);

                                            using (var b = new SolidBrush(c))
                                                g.FillEllipse(b, xColor, y, circleDiameter, circleDiameter);
                                            g.DrawEllipse(penBlack, xColor, y, circleDiameter, circleDiameter);

                                            string colorRegionName = null;
                                            //string colorName = CreatureColors.CreatureColorName(creature.colors[ci]);

                                            if (!creatureImageShown)
                                            {
                                                colorRegionName = creature.Species.colors[ci].name;
                                                int totalColorLenght = colorRegionName.Length + 11;
                                                if (totalColorLenght > maxColorNameLength)
                                                {
                                                    // shorten color region name
                                                    int lengthForRegionName = colorRegionName.Length - (totalColorLenght - maxColorNameLength);
                                                    colorRegionName = lengthForRegionName < 2
                                ? string.Empty
                                : colorRegionName.Substring(0, lengthForRegionName - 1) + "…";
                                                }

                                                if (!string.IsNullOrEmpty(colorRegionName))
                                                {
                                                    colorRegionName = " (" + colorRegionName + ")";
                                                }
                                            }

                                            g.DrawString($"{creature.colors[ci]} - [{ci}]{colorRegionName}",
                                                         fontSmall, fontBrush, xColor + circleDiameter + 4, y);
                                        }

                                        // max wild level on server
                                        if (cc != null)
                                        {
                                            g.DrawString($"max wild level: {cc.maxWildLevel}",
                                                         fontSmall, fontBrush, width - 4, height - 14, stringFormatRight);
                                        }

                                        // frame
                                        using (var p = new Pen(Color.DarkRed, 1))
                                            g.DrawRectangle(p, 0, 0, width - 1, height - 1);
                                    }

            return(bmp);
        }
Exemplo n.º 17
0
        public static Bitmap getColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool dontCache = false)
        {
            //float[][] hsl = new float[6][];
            int[][] rgb = new int[6][];
            for (int c = 0; c < 6; c++)
            {
                Color cl = CreatureColors.creatureColor(colorIds[c]);
                rgb[c] = new int[] { cl.R, cl.G, cl.B };
            }
            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                string imgFolder   = Path.Combine(FileService.GetPath(), imageFolderName);
                string cacheFolder = Path.Combine(FileService.GetPath(), imageFolderName, cacheFolderName);
                string speciesName = species?.name ?? string.Empty;

                string cacheFileName = Path.Combine(cacheFolder, speciesName.Substring(0, Math.Min(speciesName.Length, 5)) + "_" + (speciesName + string.Join("", colorIds.Select(i => i.ToString()).ToArray())).GetHashCode().ToString("X8") + extension);
                if (!onlyColors && File.Exists(Path.Combine(imgFolder, speciesName + extension)) && File.Exists(Path.Combine(imgFolder, speciesName + "_m" + extension)))
                {
                    if (!File.Exists(cacheFileName))
                    {
                        const int defaultSizeOfTemplates = 256;
                        Bitmap    bmC = new Bitmap(Path.Combine(imgFolder, speciesName + extension));
                        graph.DrawImage(new Bitmap(Path.Combine(imgFolder, speciesName + extension)), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Bitmap mask = new Bitmap(defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Graphics.FromImage(mask).DrawImage(new Bitmap(Path.Combine(imgFolder, speciesName + "_m" + extension)), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        float o         = 0;
                        bool  imageFine = false;
                        try
                        {
                            for (int i = 0; i < bmC.Width; i++)
                            {
                                for (int j = 0; j < bmC.Height; j++)
                                {
                                    Color bc = bmC.GetPixel(i, j);
                                    if (bc.A > 0)
                                    {
                                        int r = mask.GetPixel(i, j).R;
                                        int g = mask.GetPixel(i, j).G;
                                        int b = mask.GetPixel(i, j).B;
                                        for (int m = 0; m < 6; m++)
                                        {
                                            if (!enabledColorRegions[m] || colorIds[m] == 0)
                                            {
                                                continue;
                                            }
                                            switch (m)
                                            {
                                            case 0:
                                                o = Math.Max(0, r - g - b) / 255f;
                                                break;

                                            case 1:
                                                o = Math.Max(0, g - r - b) / 255f;
                                                break;

                                            case 2:
                                                o = Math.Max(0, b - r - g) / 255f;
                                                break;

                                            case 3:
                                                o = Math.Min(g, b) / 255f;
                                                break;

                                            case 4:
                                                o = Math.Min(r, g) / 255f;
                                                break;

                                            case 5:
                                                o = Math.Min(r, b) / 255f;
                                                break;
                                            }
                                            if (o == 0)
                                            {
                                                continue;
                                            }
                                            // using "grain merge", e.g. see https://docs.gimp.org/en/gimp-concepts-layer-modes.html
                                            int rMix = bc.R + rgb[m][0] - 128;
                                            if (rMix < 0)
                                            {
                                                rMix = 0;
                                            }
                                            else if (rMix > 255)
                                            {
                                                rMix = 255;
                                            }
                                            int gMix = bc.G + rgb[m][1] - 128;
                                            if (gMix < 0)
                                            {
                                                gMix = 0;
                                            }
                                            else if (gMix > 255)
                                            {
                                                gMix = 255;
                                            }
                                            int bMix = bc.B + rgb[m][2] - 128;
                                            if (bMix < 0)
                                            {
                                                bMix = 0;
                                            }
                                            else if (bMix > 255)
                                            {
                                                bMix = 255;
                                            }
                                            Color c = Color.FromArgb(rMix, gMix, bMix);
                                            bc = Color.FromArgb(bc.A, (int)(o * c.R + (1 - o) * bc.R), (int)(o * c.G + (1 - o) * bc.G), (int)(o * c.B + (1 - o) * bc.B));
                                        }
                                        bmC.SetPixel(i, j, bc);
                                    }
                                }
                            }
                            imageFine = true;
                        }
                        catch
                        {
                            // error during drawing, maybe mask is smaller than image
                        }
                        if (imageFine)
                        {
                            if (!Directory.Exists(cacheFolder))
                            {
                                Directory.CreateDirectory(cacheFolder);
                            }
                            bmC.Save(cacheFileName); // safe in cache}
                        }
                    }
                }
                if (File.Exists(cacheFileName))
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cacheFileName), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions.Count(c => c);
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < 6; c++)
                    {
                        if (enabledColorRegions[c])
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.creatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize, pieNr * pieAngle + 270, pieAngle);
                                }
                            }
                            pieNr++;
                        }
                    }
                    graph.DrawEllipse(new Pen(Color.Gray), (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }
            return(bm);
        }
        /// <summary>
        /// Resolves the naming-pattern functions
        /// </summary>
        /// <param name="m"></param>
        /// <param name="creature"></param>
        /// <param name="customReplacings"></param>
        /// <param name="displayError"></param>
        /// <param name="processNumberField">The number field {n} will add the lowest possible positive integer for the name to be unique. It has to be processed after all other functions.</param>
        /// <returns></returns>
        private static string ResolveFunction(Match m, Creature creature, int[] speciesTopLevels, Dictionary <string, string> customReplacings, bool displayError, bool processNumberField)
        {
            // function parameters can be nonnumeric if numbers are parsed
            try
            {
                // first parameter value
                string p1 = m.Groups[2].Value;

                if (!processNumberField && p1.Contains("{n}"))
                {
                    return(m.Groups[0].Value);
                }

                // switch function name
                switch (m.Groups[1].Value.ToLower())
                {
                case "if":
                    // Group3 contains the result if true
                    // Group4 (optional) contains the result if false
                    int p1Length = p1.Length;
                    if (p1Length < 7)
                    {
                        return(ParametersInvalid($"The condition-parameter expects exactly 7 or 10 characters, e.g. \"isTopHP\" or \"isNewTopHP\", given is \"{p1}\""));
                    }
                    string conditional = p1.ToLower();
                    if (p1Length == 7 && conditional.Substring(0, 5) == "istop")
                    {
                        int si = StatIndexFromAbbreviation(conditional.Substring(5, 2));
                        if (si == -1)
                        {
                            return(ParametersInvalid($"Invalid stat name \"{p1}\"."));
                        }
                        return(m.Groups[speciesTopLevels == null
                                ? (creature.levelsWild[si] > 0 ? 3 : 4)
                                : (creature.levelsWild[si] >= speciesTopLevels[si]
                                ? 3 : 4)].Value);
                    }
                    else if (p1Length == 10 && conditional.Substring(0, 8) == "isnewtop")
                    {
                        int si = StatIndexFromAbbreviation(conditional.Substring(8, 2));
                        if (si == -1)
                        {
                            return(ParametersInvalid($"Invalid stat name \"{p1}\"."));
                        }
                        return(m.Groups[speciesTopLevels == null
                                ? (creature.levelsWild[si] > 0 ? 3 : 4)
                                : (creature.levelsWild[si] > speciesTopLevels[si]
                                ? 3 : 4)].Value);
                    }
                    else
                    {
                        return(ParametersInvalid($"The condition-parameter \"{p1}\"is invalid. It has to start with \"isTop\" or \"isNewTop\" followed by a stat specifier, e.g. \"hp\""));
                    }

                case "ifexpr":
                    // tries to evaluate the expression
                    // possible operators are ==, !=, <, >, =<, =>
                    var match = Regex.Match(p1, @"\A\s*(\d+(?:\.\d*)?)\s*(==|!=|<|<=|>|>=)\s*(\d+(?:\.\d*)?)\s*\Z");
                    if (match.Success &&
                        double.TryParse(match.Groups[1].Value, out double d1) &&
                        double.TryParse(match.Groups[3].Value, out double d2)
                        )
                    {
                        switch (match.Groups[2].Value)
                        {
                        case "==": return(d1 == d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "!=": return(d1 != d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "<": return(d1 < d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "<=": return(d1 <= d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case ">": return(d1 > d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case ">=": return(d1 >= d2 ? m.Groups[3].Value : m.Groups[4].Value);
                        }
                    }
                    else
                    {
                        // compare the values as strings
                        match = Regex.Match(p1, @"\A\s*(.*?)\s*(==|!=|<=|<|>=|>)\s*(.*?)\s*\Z");
                        if (match.Success)
                        {
                            int stringComparingResult = match.Groups[1].Value.CompareTo(match.Groups[3].Value);
                            switch (match.Groups[2].Value)
                            {
                            case "==": return(stringComparingResult == 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "!=": return(stringComparingResult != 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "<": return(stringComparingResult < 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "<=": return(stringComparingResult <= 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case ">": return(stringComparingResult > 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case ">=": return(stringComparingResult >= 0 ? m.Groups[3].Value : m.Groups[4].Value);
                            }
                        }
                    }
                    return(ParametersInvalid($"The expression for ifexpr invalid: \"{p1}\""));

                case "substring":
                    // check param number: 1: substring, 2: p1, 3: pos, 4: length

                    int  pos     = Convert.ToInt32(m.Groups[3].Value);
                    bool fromEnd = pos < 0;
                    pos = Math.Min(Math.Abs(pos), p1.Length);
                    if (string.IsNullOrEmpty(m.Groups[4].Value))
                    {
                        if (fromEnd)
                        {
                            return(p1.Substring(p1.Length - pos));
                        }
                        else
                        {
                            return(p1.Substring(pos));
                        }
                    }
                    else
                    {
                        int length = Math.Min(Convert.ToInt32(Convert.ToInt32(m.Groups[4].Value)), fromEnd ? pos : p1.Length - pos);
                        if (fromEnd)
                        {
                            return(p1.Substring(p1.Length - pos, length));
                        }
                        else
                        {
                            return(p1.Substring(pos, length));
                        }
                    }

                case "format":
                    // check param number: 1: format, 2: p1, 3: formatString

                    // only use last param
                    string fmt_str = m.Groups[3].Value;
                    if (!string.IsNullOrEmpty(fmt_str))
                    {
                        // convert to double
                        double value = Convert.ToDouble(p1);
                        // format it
                        return(value.ToString(fmt_str));
                    }
                    else
                    {
                        return(ParametersInvalid("No Format string given"));
                    }

                case "padleft":
                    // check param number: 1: padleft, 2: p1, 3: desired length, 4: padding char

                    int    pad_len  = Convert.ToInt32(m.Groups[3].Value);
                    string pad_char = m.Groups[4].Value;
                    if (!string.IsNullOrEmpty(pad_char))
                    {
                        return(p1.PadLeft(pad_len, pad_char[0]));
                    }
                    else
                    {
                        ParametersInvalid($"No padding char given.");
                        return(p1);
                    }

                case "padright":
                    // check param number: 1: padright, 2: p1, 3: desired length, 4: padding char

                    pad_len  = Convert.ToInt32(m.Groups[3].Value);
                    pad_char = m.Groups[4].Value;
                    if (!string.IsNullOrEmpty(pad_char))
                    {
                        return(p1.PadRight(pad_len, pad_char[0]));
                    }
                    else
                    {
                        return(ParametersInvalid($"No padding char given."));
                    }

                case "float_div":
                    // returns an float after dividing the parsed number
                    // parameter: 1: div, 2: number, 3: divided by 4: format string
                    double f_number = double.Parse(p1);
                    double f_div    = double.Parse(m.Groups[3].Value);
                    if (f_div > 0)
                    {
                        return(((f_number / f_div)).ToString(m.Groups[4].Value));
                    }
                    else
                    {
                        return(ParametersInvalid("Division by 0"));
                    }

                case "div":
                    // returns an integer after dividing the parsed number
                    // parameter: 1: div, 2: number, 3: divided by
                    double number = double.Parse(p1);
                    double div    = double.Parse(m.Groups[3].Value);
                    if (div > 0)
                    {
                        return(((int)(number / div)).ToString());
                    }
                    else
                    {
                        return(ParametersInvalid("Division by 0"));
                    }

                case "casing":
                    // parameter: 1: casing, 2: text, 3: U for UPPER, L for lower, T for Title
                    switch (m.Groups[3].Value.ToLower())
                    {
                    case "u": return(p1.ToUpperInvariant());

                    case "l": return(p1.ToLowerInvariant());

                    case "t": return(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(p1));
                    }
                    return(ParametersInvalid($"casing expects 'U', 'L' or 'T', given is '{m.Groups[3].Value}'"));

                case "replace":
                    // parameter: 1: replace, 2: text, 3: find, 4: replace
                    if (string.IsNullOrEmpty(p1) ||
                        string.IsNullOrEmpty(m.Groups[3].Value))
                    {
                        return(p1);
                    }
                    return(p1.Replace(m.Groups[3].Value.Replace("&nbsp;", " "), m.Groups[4].Value.Replace("&nbsp;", " ")));

                case "customreplace":
                    // parameter: 1: customreplace, 2: key, 3: return if key not available
                    if (customReplacings == null ||
                        string.IsNullOrEmpty(p1) ||
                        !customReplacings.ContainsKey(p1))
                    {
                        return(m.Groups[3].Value);
                    }
                    return(customReplacings[p1]);

                case "time":
                    // parameter: 1: time, 2: format
                    return(DateTime.Now.ToString(p1));

                case "color":
                    // parameter 1: region id (0,...,5), 2: if not empty, the color name instead of the numerical id is returned
                    if (!int.TryParse(p1, out int regionId) ||
                        regionId < 0 || regionId > 5)
                    {
                        return(ParametersInvalid("color region id has to be a number in the range 0 - 5"));
                    }

                    if ((creature.colors?[regionId] ?? 0) == 0)
                    {
                        return(string.Empty);                                            // no color info
                    }
                    if (string.IsNullOrWhiteSpace(m.Groups[3].Value))
                    {
                        return(creature.colors[regionId].ToString());
                    }
                    return(CreatureColors.creatureColorName(creature.colors[regionId]));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored.\n\nSpecific error-message:\n{ex.Message}",
                                "Naming pattern function error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return(string.Empty);

            string ParametersInvalid(string specificError)
            {
                if (displayError)
                {
                    MessageBox.Show($"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored."
                                    + (string.IsNullOrEmpty(specificError) ? string.Empty : $"\n\nSpecific error:\n{specificError}"),
                                    "Naming pattern function error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                return(displayError ? m.Groups[2].Value : specificError);
            }
        }
Exemplo n.º 19
0
        public static string RegionColorInfo(string species, int[] colorIds)
        {
            string creatureRegionColors = "";
            int    si = Values.V.speciesIndex(species);

            if (si >= 0)
            {
                var cs = Values.V.species[si].colors;
                creatureRegionColors = "Colors:";
                for (int r = 0; r < 6; r++)
                {
                    if (cs[r].name != null)
                    {
                        creatureRegionColors += "\n" + cs[r].name + " (" + r.ToString() + "): " + CreatureColors.creatureColorName(colorIds[r]) + " (" + colorIds[r].ToString() + ")";
                    }
                }
            }
            return(creatureRegionColors);
        }
Exemplo n.º 20
0
        public static Bitmap getColoredCreature(int[] colorIds, string species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool dontCache = false)
        {
            //float[][] hsl = new float[6][];
            int[][] rgb = new int[6][];
            for (int c = 0; c < 6; c++)
            {
                Color cl = CreatureColors.creatureColor(colorIds[c]);
                rgb[c] = new int[] { cl.R, cl.G, cl.B };
            }
            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                string imgFolder = "img/";
                // cachefilename
                string cf = imgFolder + "cache/" + species.Substring(0, Math.Min(species.Length, 5)) + "_" + (species + string.Join("", colorIds.Select(i => i.ToString()).ToArray())).GetHashCode().ToString("X8") + ".png";
                if (!onlyColors && System.IO.File.Exists(imgFolder + species + ".png") && System.IO.File.Exists(imgFolder + species + "_m.png"))
                {
                    if (!System.IO.File.Exists(cf))
                    {
                        int    defaultSizeOfTemplates = 256;
                        Bitmap bmC = new Bitmap(imgFolder + species + ".png");
                        graph.DrawImage(new Bitmap(imgFolder + species + ".png"), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Bitmap mask = new Bitmap(defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Graphics.FromImage(mask).DrawImage(new Bitmap(imgFolder + species + "_m.png"), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        float o = 0, l;
                        Color c = Color.Black, bc = Color.Black;
                        int   r, g, b, rMix, gMix, bMix;
                        bool  imageFine = false;
                        try
                        {
                            for (int i = 0; i < bmC.Width; i++)
                            {
                                for (int j = 0; j < bmC.Height; j++)
                                {
                                    bc = bmC.GetPixel(i, j);
                                    if (bc.A > 0)
                                    {
                                        r = mask.GetPixel(i, j).R;
                                        g = mask.GetPixel(i, j).G;
                                        b = mask.GetPixel(i, j).B;
                                        l = (Math.Max(bc.R, (Math.Max(bc.G, bc.B))) + Math.Min(bc.R, Math.Min(bc.G, bc.B))) / 510f;
                                        for (int m = 0; m < 6; m++)
                                        {
                                            if (!enabledColorRegions[m] || colorIds[m] == 0)
                                            {
                                                continue;
                                            }
                                            switch (m)
                                            {
                                            case 0:
                                                o = Math.Max(0, r - g - b) / 255f;
                                                break;

                                            case 1:
                                                o = Math.Max(0, g - r - b) / 255f;
                                                break;

                                            case 2:
                                                o = Math.Max(0, b - r - g) / 255f;
                                                break;

                                            case 3:
                                                o = Math.Min(g, b) / 255f;
                                                break;

                                            case 4:
                                                o = Math.Min(r, g) / 255f;
                                                break;

                                            case 5:
                                                o = Math.Min(r, b) / 255f;
                                                break;
                                            }
                                            if (o == 0)
                                            {
                                                continue;
                                            }
                                            rMix = bc.R + rgb[m][0] - 128;
                                            if (rMix < 0)
                                            {
                                                rMix = 0;
                                            }
                                            else if (rMix > 255)
                                            {
                                                rMix = 255;
                                            }
                                            gMix = bc.G + rgb[m][1] - 128;
                                            if (gMix < 0)
                                            {
                                                gMix = 0;
                                            }
                                            else if (gMix > 255)
                                            {
                                                gMix = 255;
                                            }
                                            bMix = bc.B + rgb[m][2] - 128;
                                            if (bMix < 0)
                                            {
                                                bMix = 0;
                                            }
                                            else if (bMix > 255)
                                            {
                                                bMix = 255;
                                            }
                                            c  = Color.FromArgb(rMix, gMix, bMix);
                                            bc = Color.FromArgb(bc.A, (int)(o * c.R + (1 - o) * bc.R), (int)(o * c.G + (1 - o) * bc.G), (int)(o * c.B + (1 - o) * bc.B));
                                        }
                                        bmC.SetPixel(i, j, bc);
                                    }
                                }
                            }
                            imageFine = true;
                        }
                        catch
                        {
                            // error during drawing, maybe mask is smaller than image
                        }
                        if (imageFine)
                        {
                            if (!System.IO.Directory.Exists("img/cache"))
                            {
                                System.IO.Directory.CreateDirectory("img/cache");
                            }
                            bmC.Save(cf); // safe in cache}
                        }
                    }
                }
                if (System.IO.File.Exists(cf))
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cf), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions.Count(c => c);
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < 6; c++)
                    {
                        if (enabledColorRegions[c])
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.creatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize, pieNr * pieAngle + 270, pieAngle);
                                }
                            }
                            pieNr++;
                        }
                    }
                    graph.DrawEllipse(new Pen(Color.Gray), (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }
            return(bm);
        }
Exemplo n.º 21
0
        /// <summary>
        /// Creates a colored species image and saves it as cache file. Returns true when created successful.
        /// </summary>
        /// <returns></returns>
        private static bool CreateAndSaveCacheSpeciesFile(int[] colorIds, bool[] enabledColorRegions,
                                                          string speciesBackgroundFilePath, string speciesColorMaskFilePath, string cacheFilePath, int outputSize = 256)
        {
            if (!File.Exists(speciesBackgroundFilePath))
            {
                return(false);
            }

            using (Bitmap bmpBackground = new Bitmap(speciesBackgroundFilePath))
                using (Bitmap bmpColoredCreature = new Bitmap(bmpBackground.Width, bmpBackground.Height, PixelFormat.Format32bppArgb))
                    using (Graphics graph = Graphics.FromImage(bmpColoredCreature))
                    {
                        bool imageFine = true;
                        graph.SmoothingMode = SmoothingMode.AntiAlias;

                        // shadow
                        using (var b = new SolidBrush(Color.FromArgb(12, 0, 0, 0)))
                        {
                            int    scx          = TemplateSize / 2;
                            int    scy          = (int)(scx * 1.6);
                            int    factor       = 25;
                            int    sr           = scx - 2 * factor;
                            double heightFactor = 0.3;

                            for (int i = 2; i >= 0; i--)
                            {
                                int radius = sr + i * factor;
                                graph.FillEllipse(b, scx - radius, scy - (int)(heightFactor * .7 * radius), 2 * radius,
                                                  (int)(2 * heightFactor * radius));
                            }
                        }

                        // shaded base image
                        graph.DrawImage(bmpBackground, 0, 0, TemplateSize, TemplateSize);

                        // if species has color regions, apply colors
                        if (File.Exists(speciesColorMaskFilePath))
                        {
                            var rgb             = new byte[Species.ColorRegionCount][];
                            var useColorRegions = new bool[Species.ColorRegionCount];
                            for (int c = 0; c < Species.ColorRegionCount; c++)
                            {
                                useColorRegions[c] = enabledColorRegions[c] && colorIds[c] != 0;
                                if (useColorRegions[c])
                                {
                                    Color cl = CreatureColors.CreatureColor(colorIds[c]);
                                    rgb[c] = new byte[] { cl.R, cl.G, cl.B };
                                }
                            }
                            imageFine = ApplyColorsUnsafe(rgb, useColorRegions, speciesColorMaskFilePath, TemplateSize, bmpBackground, bmpColoredCreature);
                        }

                        if (imageFine)
                        {
                            string cacheFolder = Path.GetDirectoryName(cacheFilePath);
                            if (!Directory.Exists(cacheFolder))
                            {
                                Directory.CreateDirectory(cacheFolder);
                            }
                            if (outputSize == TemplateSize)
                            {
                                return(SaveBitmapToFile(bmpColoredCreature, cacheFilePath));
                            }

                            using (var resized = new Bitmap(outputSize, outputSize))
                                using (var g = Graphics.FromImage(resized))
                                {
                                    g.CompositingQuality = CompositingQuality.HighQuality;
                                    g.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                                    g.SmoothingMode      = SmoothingMode.HighQuality;
                                    g.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                                    g.DrawImage(bmpColoredCreature, 0, 0, outputSize, outputSize);
                                    return(SaveBitmapToFile(resized, cacheFilePath));
                                }
                        }
                    }

            return(false);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Creates an image with infos about the creature.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="cc">CreatureCollection for server settings.</param>
        /// <returns></returns>
        public static Bitmap InfoGraphic(this Creature creature, CreatureCollection cc)
        {
            if (creature == null)
            {
                return(null);
            }
            int maxGraphLevel = cc?.maxChartLevel ?? 0;

            if (maxGraphLevel < 1)
            {
                maxGraphLevel = 50;
            }

            const int width  = 300;
            const int height = 180;

            var bmp = new Bitmap(width, height);

            using (var g = Graphics.FromImage(bmp))
                using (var font = new Font("Arial", 10))
                    using (var fontSmall = new Font("Arial", 8))
                        using (var fontHeader = new Font("Arial", 12, FontStyle.Bold))
                            using (var fontBrush = new SolidBrush(Color.Black))
                                using (var penBlack = new Pen(Color.Black, 1))
                                    using (var stringFormatRight = new StringFormat()
                                    {
                                        Alignment = StringAlignment.Far
                                    })
                                    {
                                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                                        int currentYPosition = 3;

                                        using (var backgroundBrush = new SolidBrush(Color.AntiqueWhite))
                                            g.FillRectangle(backgroundBrush, 0, 0, width, height);

                                        g.DrawString(creature.Species.DescriptiveNameAndMod, fontHeader, fontBrush, 3, currentYPosition);
                                        currentYPosition += 19;
                                        g.DrawString($"Lvl {creature.LevelHatched} | {Utils.sexSymbol(creature.sex) + (creature.flags.HasFlag(CreatureFlags.Neutered) ? $" ({Loc.s(creature.sex == Sex.Female ? "Spayed" : "Neutered")})" : string.Empty)} | {creature.Mutations} mutations", font, fontBrush, 8, currentYPosition);
                                        currentYPosition += 17;

                                        using (var p = new Pen(Color.LightGray, 1))
                                            g.DrawLine(p, 0, currentYPosition, width, currentYPosition);
                                        currentYPosition += 2;

                                        // levels
                                        const int xStatName    = 8;
                                        int       xLevelValue  = xStatName + 30 + (creature.levelsWild[2].ToString().Length) * 7;
                                        int       maxBoxLenght = xLevelValue - xStatName;
                                        g.DrawString("Levels", font, fontBrush, xStatName, currentYPosition);
                                        int statDisplayIndex = 0;
                                        for (int si = 0; si < Values.STATS_COUNT; si++)
                                        {
                                            int statIndex = Values.statsDisplayOrder[si];
                                            if (statIndex == (int)StatNames.Torpidity || !creature.Species.UsesStat(statIndex))
                                            {
                                                continue;
                                            }

                                            int y = currentYPosition + 20 + (statDisplayIndex++) * 15;
                                            // box
                                            double levelFractionOfMax = Math.Min(1, (double)creature.levelsWild[statIndex] / maxGraphLevel);
                                            if (levelFractionOfMax < 0)
                                            {
                                                levelFractionOfMax = 0;
                                            }
                                            int       levelPercentageOfMax = (int)(100 * levelFractionOfMax);
                                            int       statBoxLength        = Math.Max((int)(maxBoxLenght * levelFractionOfMax), 1);
                                            const int statBoxHeight        = 2;
                                            var       statColor            = Utils.getColorFromPercent(levelPercentageOfMax);
                                            using (var b = new SolidBrush(statColor))
                                                g.FillRectangle(b, xStatName, y + 14, statBoxLength, statBoxHeight);
                                            using (var b = new SolidBrush(Color.FromArgb(10, statColor)))
                                            {
                                                for (int r = 4; r > 0; r--)
                                                {
                                                    g.FillRectangle(b, xStatName - r, y + 13 - r, statBoxLength + 2 * r, statBoxHeight + 2 * r);
                                                }
                                            }
                                            using (var p = new Pen(Utils.getColorFromPercent(levelPercentageOfMax, -0.5), 1))
                                                g.DrawRectangle(p, xStatName, y + 14, statBoxLength, statBoxHeight);

                                            // stat name
                                            g.DrawString($"{Utils.statName(statIndex, true, creature.Species.IsGlowSpecies)}",
                                                         font, fontBrush, xStatName, y);
                                            // stat level number
                                            g.DrawString($"{creature.levelsWild[statIndex]}",
                                                         font, fontBrush, xLevelValue, y, stringFormatRight);
                                        }

                                        // colors
                                        const int maxColorNameLength = 38;
                                        int       xColor             = xLevelValue + 20;
                                        g.DrawString("Colors", font, fontBrush, xColor, currentYPosition);
                                        int colorIndex = 0;
                                        for (int ci = 0; ci < Species.COLOR_REGION_COUNT; ci++)
                                        {
                                            if (!string.IsNullOrEmpty(creature.Species.colors[ci]?.name))
                                            {
                                                const int circleDiameter = 16;
                                                const int rowHeight      = circleDiameter + 2;
                                                int       y = currentYPosition + 20 + (colorIndex++) * rowHeight;

                                                Color c  = CreatureColors.creatureColor(creature.colors[ci]);
                                                Color fc = Utils.ForeColor(c);

                                                using (var b = new SolidBrush(c))
                                                    g.FillEllipse(b, xColor, y, circleDiameter, circleDiameter);
                                                g.DrawEllipse(penBlack, xColor, y, circleDiameter, circleDiameter);

                                                string colorRegionName = creature.Species.colors[ci].name;
                                                string colorName       = CreatureColors.creatureColorName(creature.colors[ci]);

                                                int totalColorLenght = colorRegionName.Length + colorName.Length + 9;
                                                if (totalColorLenght > maxColorNameLength)
                                                {
                                                    // shorten color region name
                                                    int lengthForRegionName = colorRegionName.Length - (totalColorLenght - maxColorNameLength);
                                                    colorRegionName = lengthForRegionName <= 0
                                ? string.Empty
                                : lengthForRegionName < colorRegionName.Length
                                ? colorRegionName.Substring(0, lengthForRegionName)
                                : colorRegionName;
                                                }

                                                g.DrawString($"[{ci}] {colorRegionName}: [{creature.colors[ci]}] {colorName}",
                                                             fontSmall, fontBrush, xColor + circleDiameter + 4, y);
                                            }
                                        }

                                        // max wild level on server
                                        if (cc != null)
                                        {
                                            g.DrawString($"max wild level: {cc.maxWildLevel}",
                                                         fontSmall, fontBrush, width - 4, height - 14, stringFormatRight);
                                        }

                                        // frame
                                        using (var p = new Pen(Color.DarkRed, 1))
                                            g.DrawRectangle(p, 0, 0, width - 1, height - 1);
                                    }

            return(bmp);
        }
Exemplo n.º 23
0
        /// <summary>
        /// Returns a bitmap image that represents the given colors. If a species color file is available, that is used, else a pic-chart like representation.
        /// </summary>
        /// <param name="colorIds"></param>
        /// <param name="species"></param>
        /// <param name="enabledColorRegions"></param>
        /// <param name="size"></param>
        /// <param name="pieSize"></param>
        /// <param name="onlyColors">Only return a pie-chart like color representation.</param>
        /// <param name="onlyImage">Only return an image of the colored creature. If that's not possible, return null.</param>
        /// <param name="creatureSex">If given, it's tried for find a sex-specific image.</param>
        /// <returns></returns>
        public static Bitmap GetColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool onlyImage = false, Sex creatureSex = Sex.Unknown)
        {
            if (colorIds == null)
            {
                return(null);
            }

            string speciesName = SpeciesImageName(species?.name);

            // check if there are sex specific images
            if (creatureSex != Sex.Unknown)
            {
                string speciesNameWithSex;
                switch (creatureSex)
                {
                case Sex.Female:
                    speciesNameWithSex = speciesName + "F";
                    if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;

                case Sex.Male:
                    speciesNameWithSex = speciesName + "M";
                    if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;
                }
            }

            string speciesBackgroundFilePath = Path.Combine(ImgFolder, speciesName + Extension);
            string speciesColorMaskFilePath  = Path.Combine(ImgFolder, speciesName + "_m" + Extension);
            string cacheFilePath             = ColoredCreatureCacheFilePath(speciesName, colorIds);
            bool   cacheFileExists           = File.Exists(cacheFilePath);

            if (!onlyColors && !cacheFileExists)
            {
                cacheFileExists = CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFilePath);
            }

            if (onlyImage && !cacheFileExists)
            {
                return(null);
            }

            if (cacheFileExists && size == TemplateSize)
            {
                return(new Bitmap(cacheFilePath));
            }

            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                if (cacheFileExists)
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cacheFilePath), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions?.Count(c => c) ?? Species.ColorRegionCount;
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < Species.ColorRegionCount; c++)
                    {
                        if (enabledColorRegions?[c] ?? true)
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize,
                                                  pieNr * pieAngle + 270, pieAngle);
                                }
                            }

                            pieNr++;
                        }
                    }

                    using (var pen = new Pen(Color.Gray))
                        graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }

            return(bm);
        }
Exemplo n.º 24
0
        /// <summary>
        /// Resolves the naming-pattern functions
        /// </summary>
        /// <param name="m"></param>
        /// <param name="creature"></param>
        /// <param name="customReplacings"></param>
        /// <param name="displayError"></param>
        /// <param name="processNumberField">The number field {n} will add the lowest possible positive integer for the name to be unique. It has to be processed after all other functions.</param>
        /// <returns></returns>
        private static string ResolveFunction(Match m, Creature creature, Dictionary <string, string> customReplacings, bool displayError, bool processNumberField)
        {
            // function parameters can be non numeric if numbers are parsed
            try
            {
                // first parameter value
                string p1 = m.Groups[2].Value;

                if (!processNumberField && p1.Contains("{n}"))
                {
                    return(m.Groups[0].Value);
                }

                // switch function name
                switch (m.Groups[1].Value.ToLower())
                {
                case "if":
                    // check if Group2 !isNullOrWhiteSpace
                    // Group3 contains the result if true
                    // Group4 (optional) contains the result if false
                    return(string.IsNullOrWhiteSpace(p1) ? m.Groups[4].Value : m.Groups[3].Value);

                case "ifexpr":
                    // tries to evaluate the expression
                    // possible operators are ==, !=, <, >, =<, =>
                    var match = Regex.Match(p1, @"\A\s*(\d+(?:\.\d*)?)\s*(==|!=|<|<=|>|>=)\s*(\d+(?:\.\d*)?)\s*\Z");
                    if (match.Success &&
                        double.TryParse(match.Groups[1].Value, out double d1) &&
                        double.TryParse(match.Groups[3].Value, out double d2)
                        )
                    {
                        switch (match.Groups[2].Value)
                        {
                        case "==": return(d1 == d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "!=": return(d1 != d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "<": return(d1 < d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case "<=": return(d1 <= d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case ">": return(d1 > d2 ? m.Groups[3].Value : m.Groups[4].Value);

                        case ">=": return(d1 >= d2 ? m.Groups[3].Value : m.Groups[4].Value);
                        }
                    }
                    else
                    {
                        // compare the values as strings
                        match = Regex.Match(p1, @"\A\s*(.*?)\s*(==|!=|<=|<|>=|>)\s*(.*?)\s*\Z");
                        if (match.Success)
                        {
                            int stringComparingResult = match.Groups[1].Value.CompareTo(match.Groups[3].Value);
                            switch (match.Groups[2].Value)
                            {
                            case "==": return(stringComparingResult == 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "!=": return(stringComparingResult != 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "<": return(stringComparingResult < 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case "<=": return(stringComparingResult <= 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case ">": return(stringComparingResult > 0 ? m.Groups[3].Value : m.Groups[4].Value);

                            case ">=": return(stringComparingResult >= 0 ? m.Groups[3].Value : m.Groups[4].Value);
                            }
                        }
                    }
                    return(ParametersInvalid($"The expression for ifexpr invalid: \"{p1}\""));

                case "expr":
                    // tries to calculate the result of the expression
                    // possible operators are +, -, *, /
                    match = Regex.Match(p1, @"\A\s*(\d+(?:\.\d*)?)\s*(\+|\-|\*|\/)\s*(\d+(?:\.\d*)?)\s*\Z");
                    if (match.Success &&
                        double.TryParse(match.Groups[1].Value, out d1) &&
                        double.TryParse(match.Groups[3].Value, out d2)
                        )
                    {
                        switch (match.Groups[2].Value)
                        {
                        case "+": return((d1 + d2).ToString());

                        case "-": return((d1 - d2).ToString());

                        case "*": return((d1 * d2).ToString());

                        case "/": return(d2 == 0 ? "divByZero" : (d1 / d2).ToString());
                        }
                    }
                    return(ParametersInvalid($"The expression for expr is invalid: \"{p1}\""));

                case "len":
                    // returns the length of the parameter
                    return(p1.Length.ToString());

                case "substring":
                    // check param number: 1: substring, 2: p1, 3: pos, 4: length
                    if (!int.TryParse(m.Groups[3].Value, out var pos))
                    {
                        return(p1);
                    }

                    bool fromEnd = pos < 0;
                    pos = Math.Min(Math.Abs(pos), p1.Length);
                    if (string.IsNullOrEmpty(m.Groups[4].Value))
                    {
                        if (fromEnd)
                        {
                            return(p1.Substring(p1.Length - pos));
                        }
                        else
                        {
                            return(p1.Substring(pos));
                        }
                    }
                    else
                    {
                        int length = Math.Min(Convert.ToInt32(Convert.ToInt32(m.Groups[4].Value)), fromEnd ? pos : p1.Length - pos);
                        if (fromEnd)
                        {
                            return(p1.Substring(p1.Length - pos, length));
                        }
                        else
                        {
                            return(p1.Substring(pos, length));
                        }
                    }

                case "format":
                    // check param number: 1: format, 2: p1, 3: formatString

                    // only use last param
                    string formatString = m.Groups[3].Value;
                    if (!string.IsNullOrEmpty(formatString))
                    {
                        // convert to double
                        double value = Convert.ToDouble(p1);
                        // format it
                        return(value.ToString(formatString));
                    }
                    else
                    {
                        return(ParametersInvalid("No Format string given"));
                    }

                case "padleft":
                    // check param number: 1: padleft, 2: p1, 3: desired length, 4: padding char

                    int    padLen  = Convert.ToInt32(m.Groups[3].Value);
                    string padChar = m.Groups[4].Value;
                    if (!string.IsNullOrEmpty(padChar))
                    {
                        return(p1.PadLeft(padLen, padChar[0]));
                    }
                    else
                    {
                        ParametersInvalid($"No padding char given.");
                        return(p1);
                    }

                case "padright":
                    // check param number: 1: padright, 2: p1, 3: desired length, 4: padding char

                    padLen  = Convert.ToInt32(m.Groups[3].Value);
                    padChar = m.Groups[4].Value;
                    if (!string.IsNullOrEmpty(padChar))
                    {
                        return(p1.PadRight(padLen, padChar[0]));
                    }
                    else
                    {
                        return(ParametersInvalid($"No padding char given."));
                    }

                case "float_div":
                    // returns an float after dividing the parsed number
                    // parameter: 1: div, 2: number, 3: divided by 4: format string
                    double dividend = double.Parse(p1);
                    double divisor  = double.Parse(m.Groups[3].Value);
                    if (divisor > 0)
                    {
                        return(((dividend / divisor)).ToString(m.Groups[4].Value));
                    }
                    else
                    {
                        return(ParametersInvalid("Division by 0"));
                    }

                case "div":
                    // returns an integer after dividing the parsed number
                    // parameter: 1: div, 2: number, 3: divided by
                    double number = double.Parse(p1);
                    double div    = double.Parse(m.Groups[3].Value);
                    if (div > 0)
                    {
                        return(((int)(number / div)).ToString());
                    }
                    else
                    {
                        return(ParametersInvalid("Division by 0"));
                    }

                case "casing":
                    // parameter: 1: casing, 2: text, 3: U for UPPER, L for lower, T for Title
                    switch (m.Groups[3].Value.ToLower())
                    {
                    case "u": return(p1.ToUpperInvariant());

                    case "l": return(p1.ToLowerInvariant());

                    case "t": return(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(p1));
                    }
                    return(ParametersInvalid($"casing expects 'U', 'L' or 'T', given is '{m.Groups[3].Value}'"));

                case "replace":
                    // parameter: 1: replace, 2: text, 3: find, 4: replace
                    if (string.IsNullOrEmpty(p1) ||
                        string.IsNullOrEmpty(m.Groups[3].Value))
                    {
                        return(p1);
                    }
                    return(p1.Replace(m.Groups[3].Value.Replace("&nbsp;", " "), m.Groups[4].Value.Replace("&nbsp;", " ")));

                case "customreplace":
                    // parameter: 1: customreplace, 2: key, 3: return if key not available
                    if (customReplacings == null ||
                        string.IsNullOrEmpty(p1) ||
                        !customReplacings.ContainsKey(p1))
                    {
                        return(m.Groups[3].Value);
                    }
                    return(customReplacings[p1]);

                case "time":
                    // parameter: 1: time, 2: format
                    return(DateTime.Now.ToString(p1));

                case "color":
                    // parameter 1: region id (0,...,5), 2: if not empty, the color name instead of the numerical id is returned, 3: if not empty, the function will return also a value even if the color region is not used on that species.
                    if (!int.TryParse(p1, out int regionId) ||
                        regionId < 0 || regionId > 5)
                    {
                        return(ParametersInvalid("color region id has to be a number in the range 0 - 5"));
                    }

                    if (!creature.Species.EnabledColorRegions[regionId] &&
                        string.IsNullOrWhiteSpace(m.Groups[4].Value))
                    {
                        return(string.Empty);    // species does not use this region and user doesn't want it (param 3 is empty)
                    }
                    if (creature.colors == null)
                    {
                        return(string.Empty);                             // no color info
                    }
                    if (string.IsNullOrWhiteSpace(m.Groups[3].Value))
                    {
                        return(creature.colors[regionId].ToString());
                    }
                    return(CreatureColors.CreatureColorName(creature.colors[regionId]));

                case "indexof":
                    // parameter: 1: source string, 2: string to find
                    if (string.IsNullOrEmpty(p1) || string.IsNullOrEmpty(m.Groups[3].Value))
                    {
                        return(string.Empty);
                    }
                    int index = p1.IndexOf(m.Groups[3].Value);
                    return(index >= 0 ? index.ToString() : string.Empty);
                }
            }
            catch (Exception ex)
            {
                MessageBoxes.ExceptionMessageBox(ex, $"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored.", "Naming pattern function error");
            }
            return(string.Empty);

            string ParametersInvalid(string specificError)
            {
                if (displayError)
                {
                    MessageBoxes.ShowMessageBox($"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored."
                                                + (string.IsNullOrEmpty(specificError) ? string.Empty : $"\n\nSpecific error:\n{specificError}"),
                                                $"Naming pattern function error");
                }
                return(displayError ? m.Groups[2].Value : specificError);
            }
        }
Exemplo n.º 25
0
        /// <summary>
        /// Export info for a spreadsheet.
        /// </summary>
        /// <param name="creatures"></param>
        public static void ExportTable(IEnumerable <Creature> creatures)
        {
            var fields = Properties.Settings.Default.CreatureTableExportFields;

            if (fields == null)
            {
                fields = new[] { 0, 2, 3, 4, 5, 6, 16 };
            }

            if (!fields.Any())
            {
                return;
            }

            var output = new StringBuilder();

            // header
            foreach (TableExportFields f in fields)
            {
                switch (f)
                {
                case TableExportFields.WildLevels:
                    foreach (var si in Values.statsDisplayOrder)
                    {
                        output.Append(Utils.StatName(si, true) + "_w\t");
                    }
                    break;

                case TableExportFields.DomLevels:
                    foreach (var si in Values.statsDisplayOrder)
                    {
                        output.Append(Utils.StatName(si, true) + "_d\t");
                    }
                    break;

                case TableExportFields.BreedingValues:
                    foreach (var si in Values.statsDisplayOrder)
                    {
                        output.Append(Utils.StatName(si, true) + "_b\t");
                    }
                    break;

                case TableExportFields.CurrentValues:
                    foreach (var si in Values.statsDisplayOrder)
                    {
                        output.Append(Utils.StatName(si, true) + "_v\t");
                    }
                    break;

                case TableExportFields.ParentIds:
                    output.Append("MotherId\tFatherId\t");
                    break;

                case TableExportFields.ParentNames:
                    output.Append("MotherName\tFatherName\t");
                    break;

                case TableExportFields.ColorIds:
                    output.Append(string.Join("\t", Enumerable.Range(0, Species.ColorRegionCount).Select(i => $"c{i}")) + "\t");
                    break;

                case TableExportFields.ColorNames:
                    output.Append(string.Join("\t", Enumerable.Range(0, Species.ColorRegionCount).Select(i => $"c{i}_Name")) + "\t");
                    break;

                default:
                    output.Append($"{f}\t");
                    break;
                }
            }

            output.Length--; // remove last tab
            output.AppendLine();

            // creature rows
            foreach (var c in creatures)
            {
                foreach (TableExportFields f in fields)
                {
                    switch (f)
                    {
                    case TableExportFields.Species:
                        output.Append(c.Species.name + "\t");
                        break;

                    case TableExportFields.SpeciesLongName:
                        output.Append(c.Species.DescriptiveNameAndMod + "\t");
                        break;

                    case TableExportFields.Name:
                        output.Append(c.name + "\t");
                        break;

                    case TableExportFields.Sex:
                        output.Append(c.sex + "\t");
                        break;

                    case TableExportFields.Owner:
                        output.Append(c.owner + "\t");
                        break;

                    case TableExportFields.Tribe:
                        output.Append(c.tribe + "\t");
                        break;

                    case TableExportFields.WildLevels:
                        foreach (var si in Values.statsDisplayOrder)
                        {
                            output.Append($"{c.levelsWild[si]}\t");
                        }
                        break;

                    case TableExportFields.DomLevels:
                        foreach (var si in Values.statsDisplayOrder)
                        {
                            output.Append($"{c.levelsDom[si]}\t");
                        }
                        break;

                    case TableExportFields.BreedingValues:
                        foreach (var si in Values.statsDisplayOrder)
                        {
                            output.Append($"{c.valuesBreeding[si]}\t");
                        }
                        break;

                    case TableExportFields.CurrentValues:
                        foreach (var si in Values.statsDisplayOrder)
                        {
                            output.Append($"{c.valuesDom[si]}\t");
                        }
                        break;

                    case TableExportFields.IdInGame:
                        output.Append(c.ArkIdInGame + "\t");
                        break;

                    case TableExportFields.ParentIds:
                        output.Append((c.Mother?.ArkIdInGame ?? string.Empty) + "\t" + (c.Father?.ArkIdInGame ?? string.Empty) + "\t");
                        break;

                    case TableExportFields.ParentNames:
                        output.Append((c.Mother?.name ?? string.Empty) + "\t" + (c.Father?.name ?? string.Empty) + "\t");
                        break;

                    case TableExportFields.MutationCount:
                        output.Append(c.Mutations + "\t");
                        break;

                    case TableExportFields.Fertility:
                        output.Append((c.flags.HasFlag(CreatureFlags.Neutered) ? "neutered" : string.Empty) + "\t");
                        break;

                    case TableExportFields.Notes:
                        output.Append(c.note + "\t");
                        break;

                    case TableExportFields.ColorIds:
                        for (int ci = 0; ci < Species.ColorRegionCount; ci++)
                        {
                            output.Append($"{c.colors[ci]}\t");
                        }
                        break;

                    case TableExportFields.ColorNames:
                        for (int ci = 0; ci < Species.ColorRegionCount; ci++)
                        {
                            output.Append($"{CreatureColors.CreatureColorName(c.colors[ci])}\t");
                        }
                        break;

                    case TableExportFields.ServerName:
                        output.Append(c.server + "\t");
                        break;

                    case TableExportFields.AddedToLibrary:
                        output.Append((c.addedToLibrary?.ToString() ?? string.Empty) + "\t");
                        break;
                    }
                }
                output.Length--; // remove last tab
                output.AppendLine();
            }

            try
            {
                Clipboard.SetText(output.ToString());
            }
            catch (Exception ex)
            {
                MessageBoxes.ExceptionMessageBox(ex);
            }
        }
Exemplo n.º 26
0
        /// <summary>
        /// Creates an image with infos about the creature.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="cc">CreatureCollection for server settings.</param>
        /// <returns></returns>
        public static Bitmap InfoGraphic(this Creature creature, CreatureCollection cc)
        {
            if (creature == null)
            {
                return(null);
            }
            int maxGraphLevel = cc?.maxChartLevel ?? 0;

            if (maxGraphLevel < 1)
            {
                maxGraphLevel = 50;
            }

            int width  = Properties.Settings.Default.InfoGraphicWidth; // 330
            int height = width * 6 / 11;                               //180

            int fontSize       = Math.Max(1, height / 18);             // 10
            int fontSizeSmall  = Math.Max(1, height * 2 / 45);         // 8
            int fontSizeHeader = Math.Max(1, height / 15);             // 12
            int frameThickness = Math.Max(1, height / 180);

            int statLineHeight = height * 5 / 59; // 15

            var fontName = Properties.Settings.Default.InfoGraphicFontName;

            if (string.IsNullOrWhiteSpace(fontName))
            {
                fontName = "Arial";
                Properties.Settings.Default.InfoGraphicFontName = fontName;
            }

            var bmp = new Bitmap(width, height);

            using (var g = Graphics.FromImage(bmp))
                using (var font = new Font(fontName, fontSize))
                    using (var fontSmall = new Font(fontName, fontSizeSmall))
                        using (var fontHeader = new Font(fontName, fontSizeHeader, FontStyle.Bold))
                            using (var fontBrush = new SolidBrush(Properties.Settings.Default.InfoGraphicForeColor))
                                using (var borderAroundColors = new Pen(Utils.ForeColor(Properties.Settings.Default.InfoGraphicBackColor), 1))
                                    using (var stringFormatRight = new StringFormat {
                                        Alignment = StringAlignment.Far
                                    })
                                    {
                                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                                        int currentYPosition = frameThickness * 3;

                                        using (var backgroundBrush = new SolidBrush(Properties.Settings.Default.InfoGraphicBackColor))
                                            g.FillRectangle(backgroundBrush, 0, 0, width, height);

                                        g.DrawString(creature.Species.DescriptiveNameAndMod, fontHeader, fontBrush, 3, currentYPosition);
                                        currentYPosition += height * 19 / 180; //19
                                        string creatureInfos = $"{Loc.S("Level")} {creature.LevelHatched} | {Utils.SexSymbol(creature.sex) + (creature.flags.HasFlag(CreatureFlags.Neutered) ? $" ({Loc.S(creature.sex == Sex.Female ? "Spayed" : "Neutered")})" : string.Empty)}";
                                        if (Properties.Settings.Default.InfoGraphicDisplayMutations)
                                        {
                                            creatureInfos += $" | {creature.Mutations} {Loc.S("Mutations")}";
                                        }
                                        if (Properties.Settings.Default.InfoGraphicDisplayGeneration)
                                        {
                                            creatureInfos += $" | {Loc.S("generation")} {creature.generation}";
                                        }
                                        g.DrawString(creatureInfos, font, fontBrush, width * 4 / 165, currentYPosition);
                                        currentYPosition += height * 17 / 180; //17

                                        using (var p = new Pen(Color.FromArgb(50, Properties.Settings.Default.InfoGraphicForeColor), 1))
                                            g.DrawLine(p, 0, currentYPosition, width, currentYPosition);
                                        currentYPosition += 2;

                                        // levels
                                        double meanLetterWidth = fontSize * 7d / 10;
                                        int    xStatName       = (int)meanLetterWidth;
                                        // x position of level number. torpor is the largest level number.
                                        bool showDomLevel        = Properties.Settings.Default.InfoGraphicWithDomLevels;
                                        int  xRightLevelValue    = (int)(xStatName + ((showDomLevel ? 6 : 5) + creature.levelsWild[2].ToString().Length) * meanLetterWidth);
                                        int  xRightLevelDomValue = xRightLevelValue;
                                        if (showDomLevel)
                                        {
                                            xRightLevelDomValue += (int)((creature.levelsDom.Max().ToString().Length) * meanLetterWidth);
                                        }
                                        int xRightBrValue = (int)(xRightLevelDomValue + (2 + MaxCharLength(creature.valuesBreeding)) * meanLetterWidth);
                                        int maxBoxLength  = xRightBrValue - xStatName;
                                        int statBoxHeight = Math.Max(2, height / 90);
                                        g.DrawString(Loc.S("Levels"), font, fontBrush, xRightLevelDomValue, currentYPosition, stringFormatRight);
                                        g.DrawString(Loc.S("Values"), font, fontBrush, xRightBrValue, currentYPosition, stringFormatRight);
                                        int statDisplayIndex = 0;
                                        for (int si = 0; si < Values.STATS_COUNT; si++)
                                        {
                                            int statIndex = Values.statsDisplayOrder[si];
                                            if (statIndex == (int)StatNames.Torpidity || !creature.Species.UsesStat(statIndex))
                                            {
                                                continue;
                                            }

                                            int y = currentYPosition + (height / 9) + (statDisplayIndex++) * statLineHeight;

                                            // box
                                            // empty box to show the max possible length
                                            using (var b = new SolidBrush(Color.DarkGray))
                                                g.FillRectangle(b, xStatName, y + statLineHeight - 1, maxBoxLength, statBoxHeight);
                                            double levelFractionOfMax = Math.Min(1, (double)creature.levelsWild[statIndex] / maxGraphLevel);
                                            if (levelFractionOfMax < 0)
                                            {
                                                levelFractionOfMax = 0;
                                            }
                                            int levelPercentageOfMax = (int)(100 * levelFractionOfMax);
                                            int statBoxLength        = Math.Max((int)(maxBoxLength * levelFractionOfMax), 1);
                                            var statColor            = Utils.GetColorFromPercent(levelPercentageOfMax);
                                            using (var b = new SolidBrush(statColor))
                                                g.FillRectangle(b, xStatName, y + statLineHeight - 1, statBoxLength, statBoxHeight);
                                            using (var b = new SolidBrush(Color.FromArgb(10, statColor)))
                                            {
                                                for (int r = 4; r > 0; r--)
                                                {
                                                    g.FillRectangle(b, xStatName - r, y + statLineHeight - 2 - r, statBoxLength + 2 * r, statBoxHeight + 2 * r);
                                                }
                                            }
                                            using (var p = new Pen(Utils.GetColorFromPercent(levelPercentageOfMax, -0.5), 1))
                                                g.DrawRectangle(p, xStatName, y + statLineHeight - 1, statBoxLength, statBoxHeight);

                                            // stat name
                                            g.DrawString($"{Utils.StatName(statIndex, true, creature.Species.statNames)}",
                                                         font, fontBrush, xStatName, y);
                                            // stat level number
                                            g.DrawString($"{creature.levelsWild[statIndex]}{(showDomLevel ? " +" : string.Empty)}",
                                                         font, fontBrush, xRightLevelValue, y, stringFormatRight);
                                            // dom level number
                                            if (showDomLevel)
                                            {
                                                g.DrawString($"{creature.levelsDom[statIndex]}",
                                                             font, fontBrush, xRightLevelDomValue, y, stringFormatRight);
                                            }
                                            // stat breeding value
                                            double displayedValue = showDomLevel ? creature.valuesDom[statIndex] : creature.valuesBreeding[statIndex];
                                            string statValueRepresentation;
                                            if (Utils.Precision(statIndex) == 3)
                                            {
                                                statValueRepresentation = (100 * displayedValue).ToString("0.0");
                                                g.DrawString("%", font, fontBrush, xRightBrValue, y);
                                            }
                                            else
                                            {
                                                statValueRepresentation = displayedValue.ToString("0.0");
                                            }
                                            g.DrawString(statValueRepresentation, font, fontBrush, xRightBrValue, y, stringFormatRight);
                                        }

                                        // colors
                                        var enabledColorRegions = creature.Species.EnabledColorRegions;

                                        int xColor             = (int)(xRightBrValue + meanLetterWidth * 3.5);
                                        int circleDiameter     = height * 4 / 45;
                                        int colorRowHeight     = circleDiameter + 2;
                                        int maxColorNameLength = (int)((width - xColor - circleDiameter) / meanLetterWidth); // max char length for the color region name
                                        if (maxColorNameLength < 0)
                                        {
                                            maxColorNameLength = 0;
                                        }

                                        bool creatureImageShown = false;
                                        bool displayMaxWild     = Properties.Settings.Default.InfoGraphicShowMaxWildLevel;
                                        int  extraMarginBottom  = displayMaxWild ? fontSizeSmall : 0;
                                        int  imageSize          = (int)Math.Min(width - xColor - circleDiameter - 8 * meanLetterWidth - frameThickness * 4,
                                                                                height - currentYPosition - frameThickness * 4 - extraMarginBottom);
                                        if (imageSize > 5)
                                        {
                                            using (var crBmp =
                                                       CreatureColored.GetColoredCreature(creature.colors, creature.Species, enabledColorRegions,
                                                                                          imageSize, onlyImage: true, creatureSex: creature.sex))
                                            {
                                                if (crBmp != null)
                                                {
                                                    g.DrawImage(crBmp, width - imageSize - frameThickness * 4,
                                                                height - imageSize - frameThickness * 4 - extraMarginBottom, imageSize, imageSize);
                                                    creatureImageShown = true;
                                                }
                                            }
                                        }

                                        if (creature.colors != null)
                                        {
                                            g.DrawString(Loc.S("Colors"), font, fontBrush, xColor, currentYPosition);
                                            int colorRow = 0;
                                            for (int ci = 0; ci < Species.ColorRegionCount; ci++)
                                            {
                                                if (!enabledColorRegions[ci])
                                                {
                                                    continue;
                                                }

                                                int y = currentYPosition + (height / 9) + (colorRow++) * colorRowHeight;

                                                Color c = CreatureColors.CreatureColor(creature.colors[ci]);
                                                //Color fc = Utils.ForeColor(c);

                                                using (var b = new SolidBrush(c))
                                                    g.FillEllipse(b, xColor, y, circleDiameter, circleDiameter);
                                                g.DrawEllipse(borderAroundColors, xColor, y, circleDiameter, circleDiameter);

                                                string colorRegionName = null;
                                                //string colorName = CreatureColors.CreatureColorName(creature.colors[ci]);

                                                if (!creatureImageShown)
                                                {
                                                    colorRegionName = creature.Species.colors[ci].name;
                                                    int totalColorLength = colorRegionName.Length + 11;
                                                    if (totalColorLength > maxColorNameLength)
                                                    {
                                                        // shorten color region name
                                                        int lengthForRegionName =
                                                            colorRegionName.Length - (totalColorLength - maxColorNameLength);
                                                        colorRegionName = lengthForRegionName < 2
                                    ? string.Empty
                                    : colorRegionName.Substring(0, lengthForRegionName - 1) + "…";
                                                    }

                                                    if (!string.IsNullOrEmpty(colorRegionName))
                                                    {
                                                        colorRegionName = " (" + colorRegionName + ")";
                                                    }
                                                }

                                                g.DrawString($"{creature.colors[ci]} - [{ci}]{colorRegionName}",
                                                             fontSmall, fontBrush, xColor + circleDiameter + 4, y);
                                            }
                                        }

                                        // imprinting
                                        if (showDomLevel)
                                        {
                                            g.DrawString($"Imp: {creature.imprintingBonus * 100:0.0} %", font, fontBrush, xColor + (int)((Loc.S("Colors").Length + 3) * meanLetterWidth), currentYPosition);
                                        }

                                        // max wild level on server
                                        if (cc != null && displayMaxWild)
                                        {
                                            g.DrawString($"{Loc.S("max wild level")}: {cc.maxWildLevel}",
                                                         fontSmall, fontBrush, width - 2 * frameThickness, height - fontSizeSmall - 4 * frameThickness, stringFormatRight);
                                        }

                                        // frame
                                        using (var p = new Pen(Properties.Settings.Default.InfoGraphicBorderColor, frameThickness))
                                            g.DrawRectangle(p, 0, 0, width - frameThickness, height - frameThickness);
                                    }

            return(bmp);
        }
Exemplo n.º 27
0
        /// <summary>
        /// Returns a bitmap image that represents the given colors. If a species color file is available, that is used, else a pic-chart like representation.
        /// </summary>
        /// <param name="colorIds"></param>
        /// <param name="species"></param>
        /// <param name="enabledColorRegions"></param>
        /// <param name="size"></param>
        /// <param name="pieSize"></param>
        /// <param name="onlyColors">Only return a pie-chart like color representation.</param>
        /// <param name="onlyImage">Only return an image of the colored creature. If that's not possible, return null.</param>
        /// <returns></returns>
        public static Bitmap GetColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool onlyImage = false, Library.Sex creatureSex = Sex.Unknown)
        {
            if (colorIds == null)
            {
                return(null);
            }
            //float[][] hsl = new float[Species.ColorRegionCount][];
            int[][] rgb = new int[Species.ColorRegionCount][];
            for (int c = 0; c < Species.ColorRegionCount; c++)
            {
                Color cl = CreatureColors.CreatureColor(colorIds[c]);
                rgb[c] = new int[] { cl.R, cl.G, cl.B };
            }

            string imgFolder   = Path.Combine(FileService.GetPath(), imageFolderName);
            string cacheFolder = Path.Combine(FileService.GetPath(), imageFolderName, cacheFolderName);
            string speciesName = species?.name ?? string.Empty;

            // check if there are sex specific images
            if (creatureSex != Sex.Unknown)
            {
                string speciesNameWithSex = null;
                switch (creatureSex)
                {
                case Sex.Female:
                    speciesNameWithSex = speciesName + "F";
                    if (File.Exists(Path.Combine(imgFolder, speciesNameWithSex + extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;

                case Sex.Male:
                    speciesNameWithSex = speciesName + "M";
                    if (File.Exists(Path.Combine(imgFolder, speciesNameWithSex + extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;
                }
            }

            string speciesBackgroundFilePath = Path.Combine(imgFolder, speciesName + extension);
            string cacheFileName             = Path.Combine(cacheFolder, speciesName.Substring(0, Math.Min(speciesName.Length, 5)) + "_" + (speciesName + string.Join(".", colorIds.Select(i => i.ToString()))).GetHashCode().ToString("X8") + extension);
            string speciesColorMaskFilePath  = Path.Combine(imgFolder, speciesName + "_m" + extension);

            if (!onlyColors && File.Exists(speciesBackgroundFilePath) && File.Exists(speciesColorMaskFilePath) && !File.Exists(cacheFileName))
            {
                using (Bitmap bmpBackground = new Bitmap(speciesBackgroundFilePath))
                    using (Bitmap bmpCreature = new Bitmap(bmpBackground.Width, bmpBackground.Height, PixelFormat.Format32bppArgb))
                        using (Graphics graph = Graphics.FromImage(bmpCreature))
                        {
                            bool imageFine = false;
                            graph.SmoothingMode = SmoothingMode.AntiAlias;
                            const int defaultSizeOfTemplates = 256;

                            using (Bitmap bmpMask = new Bitmap(defaultSizeOfTemplates, defaultSizeOfTemplates))
                            {
                                using (var g = Graphics.FromImage(bmpMask))
                                    using (var bmpMaskOriginal = new Bitmap(speciesColorMaskFilePath))
                                        g.DrawImage(bmpMaskOriginal, 0, 0,
                                                    defaultSizeOfTemplates, defaultSizeOfTemplates);
                                float o = 0;
                                try
                                {
                                    // shadow
                                    using (var b = new SolidBrush(Color.FromArgb(12, 0, 0, 0)))
                                    {
                                        int    scx          = defaultSizeOfTemplates / 2;
                                        int    scy          = (int)(scx * 1.6);
                                        int    factor       = 25;
                                        int    sr           = scx - 2 * factor;
                                        double heightFactor = 0.3;

                                        for (int i = 2; i >= 0; i--)
                                        {
                                            int radius = sr + i * factor;
                                            graph.FillEllipse(b, scx - radius, scy - (int)(heightFactor * .7 * radius), 2 * radius,
                                                              (int)(2 * heightFactor * radius));
                                        }
                                    }

                                    graph.DrawImage(bmpBackground, 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);

                                    for (int i = 0; i < bmpBackground.Width; i++)
                                    {
                                        for (int j = 0; j < bmpBackground.Height; j++)
                                        {
                                            Color bc = bmpBackground.GetPixel(i, j);
                                            if (bc.A > 0)
                                            {
                                                var cl = bmpMask.GetPixel(i, j);
                                                int r  = cl.R;
                                                int g  = cl.G;
                                                int b  = cl.B;
                                                for (int m = 0; m < Species.ColorRegionCount; m++)
                                                {
                                                    if (!enabledColorRegions[m] || colorIds[m] == 0)
                                                    {
                                                        continue;
                                                    }
                                                    switch (m)
                                                    {
                                                    case 0:
                                                        o = Math.Max(0, r - g - b) / 255f;
                                                        break;

                                                    case 1:
                                                        o = Math.Max(0, g - r - b) / 255f;
                                                        break;

                                                    case 2:
                                                        o = Math.Max(0, b - r - g) / 255f;
                                                        break;

                                                    case 3:
                                                        o = Math.Min(g, b) / 255f;
                                                        break;

                                                    case 4:
                                                        o = Math.Min(r, g) / 255f;
                                                        break;

                                                    case 5:
                                                        o = Math.Min(r, b) / 255f;
                                                        break;
                                                    }

                                                    if (o == 0)
                                                    {
                                                        continue;
                                                    }
                                                    // using "grain merge", e.g. see https://docs.gimp.org/en/gimp-concepts-layer-modes.html
                                                    int rMix = bc.R + rgb[m][0] - 128;
                                                    if (rMix < 0)
                                                    {
                                                        rMix = 0;
                                                    }
                                                    else if (rMix > 255)
                                                    {
                                                        rMix = 255;
                                                    }
                                                    int gMix = bc.G + rgb[m][1] - 128;
                                                    if (gMix < 0)
                                                    {
                                                        gMix = 0;
                                                    }
                                                    else if (gMix > 255)
                                                    {
                                                        gMix = 255;
                                                    }
                                                    int bMix = bc.B + rgb[m][2] - 128;
                                                    if (bMix < 0)
                                                    {
                                                        bMix = 0;
                                                    }
                                                    else if (bMix > 255)
                                                    {
                                                        bMix = 255;
                                                    }
                                                    Color c = Color.FromArgb(rMix, gMix, bMix);
                                                    bc = Color.FromArgb(bc.A, (int)(o * c.R + (1 - o) * bc.R),
                                                                        (int)(o * c.G + (1 - o) * bc.G), (int)(o * c.B + (1 - o) * bc.B));
                                                }

                                                bmpCreature.SetPixel(i, j, bc);
                                            }
                                        }
                                    }

                                    imageFine = true;
                                }
                                catch
                                {
                                    // error during drawing, maybe mask is smaller than image
                                }
                            }
                            if (imageFine)
                            {
                                if (!Directory.Exists(cacheFolder))
                                {
                                    Directory.CreateDirectory(cacheFolder);
                                }
                                bmpCreature.Save(cacheFileName); // safe in cache}
                            }
                        }
            }

            bool cacheFileExists = File.Exists(cacheFileName);

            if (onlyImage && !cacheFileExists)
            {
                return(null);
            }

            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                if (cacheFileExists)
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cacheFileName), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions.Count(c => c);
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < Species.ColorRegionCount; c++)
                    {
                        if (enabledColorRegions[c])
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize,
                                                  pieNr * pieAngle + 270, pieAngle);
                                }
                            }

                            pieNr++;
                        }
                    }

                    using (var pen = new Pen(Color.Gray))
                        graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }

            return(bm);
        }