Exemple #1
0
 /***********************************************************************************************
 * ToHtml / 2014-08-01 / Wethospu                                                               *
 *                                                                                              *
 * Converts this effect object to html representration.                                         *
 *                                                                                              *
 * Returns representation.                                                                      *
 * path: Name of current path. Needed for enemy links.                                          *
 * enemies: List of enemies in the path. Needed for enemy links.                                *
 * indent: Base indent for the HTML.                                                            *
 *                                                                                              *
 ***********************************************************************************************/
 public string ToHtml(string path, double coefficient, string weapon, List<Enemy> enemies, Enemy baseEnemy, int indent)
 {
     var htmlBuilder = new StringBuilder();
       _type = LinkGenerator.CreateEnemyLinks(HandleEffect(_type, 0, weapon, 1, 0, 0, baseEnemy), path, enemies);
       // Replace end dot with double dot if the effect has sub effects (visually looks better). / 2015-10-01 / Wethospu
       if (_type[_type.Length - 1] == '.' && SubEffects.Count > 0)
     _type = _type.Substring(0, _type.Length - 1) + ':';
       htmlBuilder.Append(Gw2Helper.AddTab(indent)).Append("<p>").Append(_type).Append("</p>").Append(Constants.LineEnding);
       htmlBuilder.Append(Gw2Helper.AddTab(indent)).Append("<ul>").Append(Constants.LineEnding);
       foreach (var subEffect in SubEffects)
       {
     htmlBuilder.Append(Gw2Helper.AddTab(indent + 1)).Append("<li>");
     htmlBuilder.Append(LinkGenerator.CreateEnemyLinks(HandleEffect(subEffect, coefficient, weapon, HitCount, HitLength, HitFrequency, baseEnemy), path, enemies));
     htmlBuilder.Append("</li>").Append(Constants.LineEnding);
       }
       htmlBuilder.Append(Gw2Helper.AddTab(indent)).Append("</ul>").Append(Constants.LineEnding);
       return htmlBuilder.ToString();
 }
Exemple #2
0
 /// <summary>
 /// Generates the HTML representation.
 /// </summary>
 public string ToHtml(Attack owner, Enemy attackOwner, int baseIndent)
 {
     var htmlBuilder = new StringBuilder();
       Type = EffectHandler.HandleEffect(Type, this, owner, attackOwner);
       // Replace end dot with a double dot if the effect has sub effects (visually looks better).
       if (Type[Type.Length - 1] == '.' && SubEffects.Count > 0)
     Type = Type.Substring(0, Type.Length - 1) + ':';
       htmlBuilder.Append(Gw2Helper.AddTab(baseIndent)).Append("<p>").Append(Helper.ToUpper(Type)).Append("</p>").Append(Constants.LineEnding);
       htmlBuilder.Append(Gw2Helper.AddTab(baseIndent)).Append("<ul>").Append(Constants.LineEnding);
       foreach (var subEffect in SubEffects)
       {
     htmlBuilder.Append(Gw2Helper.AddTab(baseIndent + 1)).Append("<li>");
     var str = EffectHandler.HandleEffect(subEffect, this, owner, attackOwner);
     htmlBuilder.Append(Helper.ToUpper(str.Replace("\\:", ":")));
     htmlBuilder.Append("</li>").Append(Constants.LineEnding);
       }
       htmlBuilder.Append(Gw2Helper.AddTab(baseIndent)).Append("</ul>").Append(Constants.LineEnding);
       return htmlBuilder.ToString();
 }
 private static SubEffectInformation ExtractInformation(SubEffectInformation effect, SubEffect subEffect, TagData text, Attack baseAttack, Enemy baseEnemy)
 {
     var effectType = subEffect.Name;
       var effectData = text.Data.Split(':');
       effect.name = text.Tag.ToLower();
       effect.amount = -1;
       effect.duration = 0.0;
       effect.stacks = 1;
       effect.buff = "";
       effect.icon = effect.name;
       effect.suffix = "damage";
       if (effectType == EffectType.Damage || effectType == EffectType.DamageFixed || effectType == EffectType.DamagePercent)
       {
     if (effectData[0].Equals("-"))
       effect.amount = baseAttack.Coefficient;
     else if (effectData[0].Equals("?"))
       effect.amount = -1;
     else
       effect.amount = Helper.ParseD(effectData[0]);
     effect.icon = "damage";
     effect.stacks = 1;
       }
       else if (effectType == EffectType.Healing || effectType == EffectType.HealingPercent)
       {
     if (effectData[0].Equals("-"))
       effect.amount = baseAttack.Coefficient;
     else if (effectData[0].Equals("?"))
       effect.amount = -1;
     else
       effect.amount = Helper.ParseD(effectData[0]);
     effect.suffix = "healing";
     effect.icon = "healing";
     effect.stacks = 1;
       }
       if (effectType == EffectType.Boon || effectType == EffectType.Condition || effectType == EffectType.Control)
       {
     baseEnemy.Tags.Add(effect.name);
       }
       if (effectType == EffectType.Agony || effectType == EffectType.Boon || effectType == EffectType.Condition)
       {
     if (effectData[0].Equals("-"))
       effect.duration = baseAttack.Coefficient;
     else if (effectData[0].Equals("?"))
       effect.duration = -1;
     else
       effect.duration = Helper.ParseD(effectData[0]);
     if (effectType == EffectType.Agony || effect.name.Equals("bleeding") || effect.name.Equals("torment") || effect.name.Equals("burning")
       || effect.name.Equals("poison") || effect.name.Equals("confusion") || effect.name.Equals("regeneration") || effect.name.Equals("might"))
       effect.amount = effect.duration;
     if (effectData.Length > 1)
       effect.stacks = Helper.ParseI(effectData[1]);
     if (subEffect.StacksDuration || effectType == EffectType.Boon)
       effect.suffix = "seconds";
     if (effect.name.Equals("regeneration"))
       effect.suffix = "healing";
     if (effect.name.Equals("retaliation"))
       effect.suffix = "damage per hit";
     if (effect.name.Equals("might"))
       effect.suffix = "more damage";
     if (effect.name.Equals("retaliation") || effect.name.Equals("might"))
       effect.amount = 1;
       }
       if (effectType == EffectType.Control)
       {
     if (effectData[0].Equals("?"))
       effect.duration = 0;
     else
       effect.duration = Helper.ParseD(effectData[0]);
     if (effectData.Length > 1)
       effect.stacks = Helper.ParseI(effectData[1]);
       }
       if (effectType == EffectType.Buff)
       {
     effect.buff = effectData[0];
     effect.icon = effect.buff;
     if (effectData.Length > 1 && effectData[1].Length > 0)
       effect.duration = Helper.ParseD(effectData[1]);
     if (effectData.Length > 2 && effectData[2].Length > 0)
       effect.stacks = Helper.ParseI(effectData[2]);
     if (effectData.Length > 3 && effectData[3].Length > 0)
       effect.icon = effectData[3];
     if (effectData.Length > 4)
       subEffect.StacksDuration = Helper.ParseI(effectData[4]) > 0 ? true : false;
       }
       return effect;
 }
Exemple #4
0
        /***********************************************************************************************
        * AttackToHTML / 2015-09-15 / Wethospu                                                         *
        *                                                                                              *
        * Converts this attack object to html representration.                                         *
        *                                                                                              *
        * Returns representation.                                                                      *
        * path: Name of current path. Needed for enemy links.                                          *
        * enemies: List of enemies in the path. Needed for enemy links.                                *
        * indent: Base indent for the HTML.                                                            *
        *                                                                                              *
        ***********************************************************************************************/
        public string AttackToHTML(string path, List<Enemy> enemies, Enemy baseEnemy, int indent)
        {
            if (_name.Equals(""))
            Helper.ShowWarningMessage("Enemy " + baseEnemy.Name + " has no attack name.");
              var htmlBuilder = new StringBuilder();
              // Add attack name.
              htmlBuilder.Append(Gw2Helper.AddTab(indent + 1)).Append("<p class=\"enemy-attack\"><span class=\"enemy-attack-name\">").Append(Helper.ConvertSpecial(Helper.ToUpperAll(LinkGenerator.CreateEnemyLinks(_name, path, enemies))));

              htmlBuilder.Append("</span>").Append(" ");
              // Add other data.
              if (!Animation.Equals(""))
            htmlBuilder.Append("<span class=\"animation-unit\"><i>").Append(Helper.ConvertSpecial(Helper.ToUpper(LinkGenerator.CreateEnemyLinks(Animation, path, enemies)))).Append("</i>. </span>");
              if (Cooldown > -1 || _internalCooldown > -1)
              {
            htmlBuilder.Append("<span class=\"cooldown-unit\" title=\"Skill cooldown\"><span class=\"cooldown\"");
            if (Cooldown > -1)
              htmlBuilder.Append(" data-amount=\"").Append(Cooldown).Append("\"");
            if (_internalCooldown > -1)
              htmlBuilder.Append(" data-internal=\"").Append(_internalCooldown / 1000).Append("\"");
            htmlBuilder.Append("></span>").Append(Constants.Space).Append("<span class=").Append(Constants.IconClass).Append(" data-src=\"cooldown\">Cooldown</span> </span>");
              }
              if (_minimumRange > -1 || _maximumRange > -1)
              {
            htmlBuilder.Append("<span class=\"range-unit\" title=\"Activation range\">");
            htmlBuilder.Append(_minimumRange > -1 ? "" + _minimumRange : "?").Append("-").Append(_maximumRange > -1 ? "" + _maximumRange : "?");
            htmlBuilder.Append(Constants.Space).Append("<span class=").Append(Constants.IconClass).Append(" data-src=\"range\">Range</span> </span>");
              }
              htmlBuilder.Append("</p>").Append(Constants.LineEnding);
              htmlBuilder.Append(Gw2Helper.AddTab(indent + 1)).Append("<div class=\"enemy-attack-effect\">").Append(Constants.LineEnding);
              // Add attack effects.
              foreach (var effect in Effects)
            htmlBuilder.Append(effect.ToHtml(path, _coefficient, _weapon, enemies, baseEnemy, indent + 2));
              htmlBuilder.Append(Gw2Helper.AddTab(indent + 1)).Append("</div>").Append(Constants.LineEnding);

              return htmlBuilder.ToString();
        }
 private static void VerifyEnemy(Enemy currentEnemy)
 {
     if (currentEnemy == null)
     return;
       if (currentEnemy.Paths.Count == 0)
     ErrorHandler.ShowWarning("Path not set for previous enemy " + currentEnemy.Name + ".");
       if (currentEnemy.Rank.Length == 0)
     ErrorHandler.ShowWarning("Rank not set for previous enemy " + currentEnemy.Name + ".");
 }
 /// <summary>
 /// Adds alternative names to a given enemy. These are used for the site search and enemy linking.
 /// </summary>
 private static void HandleAlternativeNames(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"alt='alt1'|'alt2'|'altN'\"!");
       if (data.Contains('_'))
     ErrorHandler.ShowWarning("Alt names " + data + "  containts '_'. Replace them with ' '!");
       var altNames = data.Split('|');
       currentEnemy.AltNames.Clear();
       foreach (var altName in altNames)
     currentEnemy.AddAlternativeName(altName);
 }
        /***********************************************************************************************
         * EnemyLoop / 2014-08-01 / Wethospu                                                           *
         *                                                                                             *
         * Main process loop for enemies.                                                              *
         *                                                                                             *
         * tag: Tag of the line.                                                                       *
         * data: Data of the line.                                                                     *
         * enemies: Output. List of processed enemies.                                                 *
         *                                                                                             *
         ***********************************************************************************************/
        private static int EnemyLoop(string tag, string data, List<Enemy> enemies, Dictionary<string, EnemyAttributes> enemyAttributes)
        {
            if (!tag.Equals("name") && !tag.Equals("id") && _currentEnemy != null & _currentEnemy.IsNameCopied)
            Helper.ShowWarning("ID or name not explicitly set for a copied enemy.");
              if (tag.Equals("copy"))
              {
            if (_currentEnemy != null)
              enemies.Add(_currentEnemy);
            var found = FindEnemy(data, enemies);
            if (found != null)
            {
              _currentEnemy = Helper.CloneJson(found);
              _currentEnemy.IsNameCopied = true;
              _currentEnemy.AreAnimationsCopied = true;
            }
            else
              Helper.ShowWarning("Copying failed. Enemy not found!");
              }
              else if (tag.Equals("name"))
              {
            if (data.Length > 0)
            {
              if (_currentEnemy != null && !_currentEnemy.IsNameCopied)
              {
            enemies.Add(_currentEnemy);
            if (_currentEnemy.Paths.Count == 0)
              Helper.ShowWarning("Path not set for enemy " + _currentEnemy.Name);
              }
              if (data.Contains('_'))
            Helper.ShowWarning("Enemy name " + data + "  containts '_'. Replace them with ' '!");
              // For copies only set the name. / 2015-10-05 / Wethospu
              if (_currentEnemy != null && _currentEnemy.IsNameCopied)
            _currentEnemy.Name = data;
              else
            _currentEnemy = new Enemy(data);
              _currentEnemy.IsNameCopied = false;
              _currentAttack = null;
              _currentEffect = null;
            }
            else
              Helper.ShowWarning("Missing info. Use \"name='name'\"!");
              }
              else if (tag.Equals("id"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              _currentEnemy.IsNameCopied = false;
              var ids = data.Split('|');
              // Enemies can have multiple genders if there are model variations. / 2015 - 09 - 28 / Wethospu
              // Each model has a different id so store old ones to get all added. / 2015-09-28 / Wethospu
              var oldGenders = "";
              foreach (var id in ids)
              {
            _currentEnemy.InternalIds.Add(Helper.ParseI(id));
            if (enemyAttributes.ContainsKey(id))
            {
              _currentEnemy.Attributes = enemyAttributes[id];
              if (oldGenders.Length > 0)
              {
                var genders = oldGenders.Split('|');
                // If the sex is already there it can be ignored. / 2015-09-28 / Wethospu
                if (genders.Contains(_currentEnemy.Attributes.Gender))
                  _currentEnemy.Attributes.Gender = oldGenders;
                else
                  _currentEnemy.Attributes.Gender = oldGenders + "|" + _currentEnemy.Attributes.Gender;
              }
              _currentEnemy.Rank = _currentEnemy.Attributes.GetRank();
              oldGenders = _currentEnemy.Attributes.Gender;
            }
            else
              Helper.ShowWarning("Id " + data + " not found in enemy attributes.");
              }
            }
            else
              Helper.ShowWarning("Missing info. Use \"id='id'\"!");
              }
              else if (tag.Equals("path"))
              {
            if (data.Length == 0)
              Helper.ShowWarning("Missing info. Use \"path='path1'|'path2'|'pathN'\"!");
            if (data.Contains(" "))
            {
              Helper.ShowWarning("' ' found. Use syntax \"path='path1'|'path2'|'pathN'\"");
              data = data.Replace(' ', '|');
            }
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else
              _currentEnemy.Paths = new List<string>(data.ToLower().Split('|'));
              }
              else if (tag.Equals("rank"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              _currentEnemy.Rank = data.ToLower();
              if (!LinkGenerator.EnemyCategories.Contains(_currentEnemy.Rank))
            Helper.ShowWarning("Rank " + _currentEnemy.Rank + " not recognized. Check syntax for correct categories.");
            }
            else
              Helper.ShowWarning("Missing info. Use \"rank='rank'\"!");
              }
              else if (tag.Equals("alt"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              if (data.Contains('_'))
            Helper.ShowWarning("Alt names " + data + "  containts '_'. Replace them with ' '!");
              var altNames = data.Split('|');
              _currentEnemy.AltNames.Clear();
              foreach (var altName in altNames)
            _currentEnemy.AddAlt(altName);
            }
            else
              Helper.ShowWarning("Missing info. Use \"alt='alt1'|'alt2'|'altN'\"!");
              }
              else if (tag.Equals("image"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              if (_currentEnemy.AreAnimationsCopied)
              {
            _currentEnemy.Medias.Clear();
            _currentEnemy.AreAnimationsCopied = false;
              }
              _currentEnemy.Medias.Add(new Media(data));
            }
            else
              Helper.ShowWarning("Missing info. Use \"image='imagelink'\"!");
              }
              else if (tag.Equals("level"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              _currentEnemy.Level = Helper.ParseI(data);
            }
            else
              Helper.ShowWarning("Missing info. Use \"level='amount'\"");
              }
              else if (tag.Equals("scaling"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (data.Length > 0)
            {
              var scalingSplit = data.Split('|');
              _currentEnemy.ScalingType = scalingSplit[0];
              if (scalingSplit.Length > 1)
              {
            int result;
            if (int.TryParse(scalingSplit[1], out result))
              _currentEnemy.ScalingFractal = result;
            else
              Helper.ShowWarning("Fractal scale " + scalingSplit[1] + " is not an integer!");
            if (scalingSplit.Length > 2)
            {
              if (int.TryParse(scalingSplit[2], out result))
                _currentEnemy.ScalingLevel = result;
              else
                Helper.ShowWarning("Enemy level " + scalingSplit[2] + " is not an integer!");

            }
              }
            }

            else
              Helper.ShowWarning("Missing info. Use \"scaling='type'|'fractal scale'|'enemy level'\"!");
              }
              else if (tag.Equals("attack"))
              {
            if (_currentEnemy == null)
              Helper.ShowWarning("Enemy not initialized with name.");
            else if (_currentEnemy.Rank.Length == 0)
              Helper.ShowWarningMessage("Rank not set for enemy " + _currentEnemy.Name + ". Please fix!");
            return 1;
              }
              else if (tag.Equals("tactic"))
              {
            // Set validity to over max so custom tactics never get overridden. / 2015-08-09 / Wethospu
            _currentEnemy.TacticValidity = 2.0;
            if (data.Length > 0)
              _currentEnemy.Tactics.AddTactics(data);
            else
              Helper.ShowWarning("Missing info. Use \"tactic='tactic1'|'tactic2'|'tacticN'\".");
              }
              else if (tag.Equals("health"))
              {
            if (data.Length > 0)
            {
              _currentEnemy.Attributes.Multipliers.HealthMultiplier = Helper.ParseD(data);
              // If vitality is not set, initialize it with something sensible so the page can calculate something. / 2015-09-10 / Wethospu
              if (_currentEnemy.Attributes.Multipliers.Vitality < 0.1)
            _currentEnemy.Attributes.Multipliers.Vitality = 1;
              if (Helper.ParseD(data) > 1000)
            Helper.ShowWarning("Health values should be multipliers. Calculate the multiplier.");
            }
            else
              Helper.ShowWarning("Missing info. Use \"health='amount'.");
              }
              else if (tag.Equals("toughness"))
              {
            if (data.Length > 0)
            {
              _currentEnemy.Attributes.Multipliers.Toughness = Helper.ParseD(data);
              if (Helper.ParseD(data) > 100)
            Helper.ShowWarning("Toughness values should be multipliers. Calculate the multiplier.");
            }
            else
              Helper.ShowWarning("Missing info. Use \"toughness='amount'.");
              }
              else if (tag.Equals("armor"))
              {
            Helper.ShowWarning("Armor values shouldn't be used. Calculate the toughness multiplier.");
              }
              else if (tag.Equals("condition"))
              {
            if (data.Length > 0)
            {
              _currentEnemy.Attributes.Multipliers.ConditionDamage = Helper.ParseD(data);
              if (Helper.ParseD(data) > 100)
            Helper.ShowWarning("Condition damage values should be multipliers. Calculate the multiplier.");
            }
            else
              Helper.ShowWarning("Missing info. Use \"condition='amount'.");
              }
              else if (tag.Equals("race"))
              {
            if (data.Length > 0)
            {
              _currentEnemy.Attributes.Family.Name = data;
            }
            else
              Helper.ShowWarning("Missing info. Use \"race='value'.");
              }
              else if (tag.Equals("tag"))
              {
            if (data.Length > 0)
            {
              var split = data.Split('|');
              foreach (var str in split)
            _currentEnemy.Tags.Add(str.ToLower());
            }
            else
              Helper.ShowWarning("Missing info. Use \"tag='tactic1'|'tactic2'|'tacticN'\"!");
              }
              // Normal content.
              else if (tag.Equals(""))
              {
            // Preprocess the line to avoid doing same stuff 25+ times.
            _currentEnemy.Tactics.AddLine(LinkGenerator.CreatePageLinks(LinkGenerator.CheckLinkSyntax(data)));
              }
              else if (tag.Equals("type") || tag.Equals("effect") || tag.Equals("cooldown") || tag.Equals("additional") || tag.Equals("animation"))
            Helper.ShowWarning("Missing attack name (\"attack='name'\")!");
              else
            Helper.ShowWarning("Unrecognized tag: " + tag);
              return 0;
        }
Exemple #8
0
        /// <summary>
        /// Generates the HTML representation.
        /// </summary>
        public string ToHTML(Enemy attackOwner, int baseIndent)
        {
            if (Name.Equals(""))
            ErrorHandler.ShowWarningMessage("Enemy " + attackOwner.Name + " has no attack name.");
              var htmlBuilder = new StringBuilder();
              // Add attack name.
              htmlBuilder.Append(Gw2Helper.AddTab(baseIndent + 1)).Append("<p class=\"enemy-attack\"><span class=\"enemy-attack-name\">").Append(Helper.ConvertSpecial(Helper.ToUpperAll(Name)));

              htmlBuilder.Append("</span>").Append(" ");
              // Add other data.
              if (!Animation.Equals(""))
            htmlBuilder.Append("<span class=\"animation-unit\"><i>").Append(Helper.ConvertSpecial(Helper.ToUpper(Animation))).Append("</i>. </span>");
              if (Cooldown > -1 || InternalCooldown > -1)
              {
            htmlBuilder.Append("<span class=\"cooldown-unit\" title=\"Skill cooldown\"><span class=\"cooldown\"");
            if (Cooldown > -1)
              htmlBuilder.Append(" data-amount=\"").Append(Cooldown).Append("\"");
            if (InternalCooldown > -1)
              htmlBuilder.Append(" data-internal=\"").Append(InternalCooldown / 1000).Append("\"");
            htmlBuilder.Append("></span>").Append(Constants.Space).Append("<span class=").Append(Constants.IconClass).Append(" data-src=\"cooldown\">Cooldown</span> </span>");
              }
              if (MinimumRange > -1 || MaximumRange > -1)
              {
            htmlBuilder.Append("<span class=\"range-unit\" title=\"Activation range\">");
            htmlBuilder.Append(MinimumRange > -1 ? "" + MinimumRange : "?").Append("-").Append(MaximumRange > -1 ? "" + MaximumRange : "?");
            htmlBuilder.Append(Constants.Space).Append("<span class=").Append(Constants.IconClass).Append(" data-src=\"range\">Range</span> </span>");
              }
              htmlBuilder.Append("</p>").Append(Constants.LineEnding);
              htmlBuilder.Append(Gw2Helper.AddTab(baseIndent + 1)).Append("<div class=\"enemy-attack-effect\">").Append(Constants.LineEnding);
              // Add effects.
              foreach (var effect in Effects)
            htmlBuilder.Append(effect.ToHtml(this, attackOwner, baseIndent + 2));
              htmlBuilder.Append(Gw2Helper.AddTab(baseIndent + 1)).Append("</div>").Append(Constants.LineEnding);

              return htmlBuilder.ToString();
        }
 /// <summary>
 /// Adds a media file to a given enemy.
 /// </summary>
 private static void HandleMedia(string data, Enemy currentEnemy)
 {
     if (currentEnemy.AreAnimationsCopied)
       {
     currentEnemy.Medias.Clear();
     currentEnemy.AreAnimationsCopied = false;
       }
       currentEnemy.HandleMedia(data, Constants.EnemyMediaFolder);
 }
 /// <summary>
 /// Sets a custom level for a given enemy. By default, this is calculated from the path base level.
 /// </summary>
 private static void HandleLevel(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"level='amount'\"");
       currentEnemy.Level = Helper.ParseI(data);
 }
 /// <summary>
 /// Sets datamined id to a given enemy. Automatically loads datamined data.
 /// </summary>
 private static void HandleId(string data, Enemy currentEnemy, Dictionary<string, EnemyAttributes> enemyAttributes)
 {
     if (data.Length == 0)
       {
     ErrorHandler.ShowWarning("Missing info. Use \"id='id'\"!");
     return;
       }
       currentEnemy.IsNameCopied = false;
       var ids = data.Split('|');
       // Enemies can have multiple genders if there are model variations.
       // Each model has a different id so store old ones to get all added.
       var oldGenders = "";
       foreach (var id in ids)
       {
     currentEnemy.InternalIds.Add(Helper.ParseI(id));
     if (enemyAttributes.ContainsKey(id))
     {
       // Different enemies may share attributes (for exampled allied enemies).
       currentEnemy.Attributes = enemyAttributes[id];
       if (oldGenders.Length > 0)
       {
     var genders = oldGenders.Split('|');
     if (genders.Contains(currentEnemy.Attributes.Gender))
       currentEnemy.Attributes.Gender = oldGenders;
     else
       currentEnemy.Attributes.Gender = oldGenders + "|" + currentEnemy.Attributes.Gender;
       }
     }
     else
       ErrorHandler.ShowWarning("Id " + data + " not found in enemy attributes.");
       }
 }
 /// <summary>
 /// Most health values are acquired automatically from datamined data. This is used for special cases.
 /// </summary>
 private static void HandleHealth(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"health='amount'.");
       currentEnemy.Attributes.Multipliers.HealthMultiplier = Helper.ParseD(data);
       // If vitality is not set, initialize it with something sensible so the page can calculate something.
       if (currentEnemy.Attributes.Multipliers.Vitality < 0.0001)
     currentEnemy.Attributes.Multipliers.Vitality = 1;
       if (currentEnemy.Attributes.Multipliers.HealthMultiplier > 1000)
     ErrorHandler.ShowWarning("Health values should be multipliers. Calculate the multiplier.");
 }
 /// <summary>
 /// Copies an enemy to a given enemy.
 /// </summary>
 private static Enemy HandleCopy(Enemy foundEnemy)
 {
     if (foundEnemy == null)
       {
     ErrorHandler.ShowWarning("Copying failed. Enemy not found!");
     return null;
       }
       var currentEnemy = Helper.CloneJson(foundEnemy);
       currentEnemy.IsNameCopied = true;
       currentEnemy.AreAnimationsCopied = true;
       return currentEnemy;
 }
 /// <summary>
 /// Most condition damage values are acquired automatically from datamined data. This is used for special cases.
 /// </summary>
 private static void HandleCondition(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"condition='amount'.");
       currentEnemy.Attributes.Multipliers.ConditionDamage = Helper.ParseD(data);
       if (currentEnemy.Attributes.Multipliers.ConditionDamage > 100)
     ErrorHandler.ShowWarning("Condition damage values should be multipliers. Calculate the multiplier.");
 }
 private static void HandleAttackId(string data, Attack currentAttack, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"id=number\".");
       currentAttack.LoadAttributes(Helper.ParseI(data), currentEnemy.Attributes);
 }
Exemple #16
0
        /// <summary>
        /// Converts raw effect data to html outpout.
        /// </summary>
        /// <param name="effectStr">Effect information-</param>
        /// <param name="baseEffect">Base effect.</param>
        /// <param name="baseAttack">Base attack for the base effect.</param>
        /// <param name="baseEnemy">Base enemy for the base attack.</param>
        /// <returns>Converted data.</returns>
        public static string HandleEffect(string effectStr, Effect baseEffect, Attack baseAttack, Enemy baseEnemy)
        {
            /* What is wanted:
              * Damage: <span>(count*stack*amount)</span> over time (<span>amount</span> per hit).
              * Swiftness: (count*stack*amount) over time (amount per hit).
              * count*stack stability: for amount over time (stack per hit)
              * count*stack might: <span>count*stack</span>% more damage for amount over time (<span>stack</span>% more damage per hit)
              */
              // Note: Listing per hit for might/stability may not make sense if there is only stack.

              // Keep the original string for error logging purposes.
              var original = string.Copy(effectStr);
              // Copy values from the base effect to avoid changing it. If this ever gets refactored feel free to use them directly.
              SubEffectInformation information = new SubEffectInformation();
              information.hitCount = baseEffect.HitCount;
              information.hitLength = baseEffect.HitLength;
              information.hitFrequency = baseEffect.HitFrequency;
              information.variableHitCount = false;
              var split = effectStr.Split('|');
              effectStr = split[0];
              // Some effects get applied randomly. Don't add total damage/effect in those cases. Refactor this if possible.
              var effectChance = "";
              if (split.Length > 1)
            effectChance = split[1];
              if (effectChance.Length > 0)
            information.hitCount = 1;
              if (information.hitCount < 0)
              {
            information.variableHitCount = true;
            information.hitCount = 1;
              }
              // First effect type determines the icon.
              var firstType = "";
              var firstStacks = 0;
              var startIcon = "";
              var index = 0;
              while (true)
              {
            TagData text = TagData.FromString(effectStr, ':', ref index, new[] { ' ', '|', '(' }, new[] { ' ', '|', ')' });
            if (text == null)
              break;
            // Ignore other stuff like enemies.
            if (text.Tag.Contains("="))
              continue;
            if (text.Tag.Length == 0 || text.Data.Length == 0)
            {
              ErrorHandler.ShowWarningMessage("Enemy " + baseEnemy.Name + ": Something wrong with line '" + original + "'. Note: Use '\\:' instead of ':' in the text!");
              effectStr = effectStr.Remove(index, 1);
              continue;
            }
            if (!SubEffect.EffectTypes.ContainsKey(text.Tag.ToLower()))
            {
              ErrorHandler.ShowWarningMessage("Skipping an effect. Effect " + text.Tag + " not recognized.");
              continue;
            }
            var subEffect = SubEffect.EffectTypes[text.Tag.ToLower()];
            var effectType = subEffect.Name;
            // Effect info format varies based on tag (separated by :).
            information = ExtractInformation(information, subEffect, text, baseAttack, baseEnemy);
            var tag = SubEffect.GetTag(effectType);
            if (tag.Length > 0)
              baseEnemy.Tags.Add(tag);
            information = HandleStackingRules(information, subEffect);
            StringBuilder replace = GenerateReplace(information, subEffect, baseAttack);
            var toReplace = text.Tag + ":" + text.Data;
            effectStr = effectStr.Replace(toReplace, replace.ToString());
            index = index - toReplace.Length + replace.Length;
            // Get the first subeffect type to display an icon.
            if (firstType.Equals(""))
            {
              if (information.icon.Equals("-") && effectType == EffectType.Buff)
            startIcon = "Buff";
              else
            startIcon = "<span class=" + Constants.IconClass + " data-src=\"" + information.icon.ToLower() + "\" title=\"" + Helper.ToUpper(information.name.Replace('_', ' ')) + "\">" + Helper.ToUpper(information.name.Replace('_', ' ')) + "</span>";
              firstType = information.name;
              firstStacks = information.stacks;
            }
              }
              return BuildHTML(firstType, startIcon, firstStacks, effectStr, effectChance).ToString();
        }
Exemple #17
0
        /***********************************************************************************************
        * HandleEffect / 2015-04-02 / Wethospu                                                         *
        *                                                                                              *
        * Converts raw effect data to final html output.                                               *
        * Returns the converted output.                                                                *
        *                                                                                              *
        * effectStr: Raw effect data.                                                                  *
        * weapon: Weapon slot for this skill.                                                          *
        * hitCount: How many times the attack part hits.                                               *
        * hitLength: How long it takes for all hits to hit.                                            *
        * hitFrequency: How often the effect tics. Only relevant for auras.                            *
        * baseEnemy: Enemy which owns this effect. Needed to add tags to the enemy.                    *
        *                                                                                              *
        ***********************************************************************************************/
        private string HandleEffect(string effectStr, double coefficient, string weapon, int hitCount, double hitLength, double hitFrequency, Enemy baseEnemy)
        {
            /* What is wanted:
              * Damage: <span>(count*stack*amount)</span> over time (<span>amount</span> per hit).
              * Swiftness: (count*stack*amount) over time (amount per hit).
              * count*stack stability: for amount over time (stack per hit)
              * count*stack might: <span>count*stack</span>% more damage for amount over time (<span>stack</span>% more damage per hit)
              */
              // Note: Listing per hit for might/stability may not make sense if there is only stack. / 2015-09-27 / Wethospu
              var original = string.Copy(effectStr);
              effectStr = Helper.ToUpper(LinkGenerator.CreatePageLinks(effectStr));
              var split = effectStr.Split('|');
              effectStr = split[0];
              // Some effects get applied randomly. Don't add total damage/effect in those cases. / 2015-09-15 / Wethospu
              var effectChance = "";
              if (split.Length > 1)
            effectChance = split[1];
              if (effectChance.Length > 0)
            hitCount = 1;
              bool variableHitCount = false;
              if (hitCount < 0)
              {
            variableHitCount = true;
            hitCount = 1;
              }
              // First effect type determines the icon. / 2015-09-05 / Wethospu
              var firstType = "";
              // The icon gets stack numbers. / 2015-09-05 / Wethospu
              var firstStacks = 0;
              var startIcon = "";
              for (var index = Helper.FirstIndexOf(effectStr, new[] { ':' }); index < effectStr.Length && index > 0; index = Helper.FirstIndexOf(effectStr, new[] { ':' }, index + 1))
              {
            // Effect format is 'tag':'info'. / 2015-08-09 / Wethospu
            var tagIndex = Helper.LastIndexOf(effectStr, new[] { ' ', '|', '(' }, index);
            var tag = effectStr.Substring(tagIndex + 1, index - tagIndex - 1);
            // Ignore other stuff like enemies. / 2015-08-09 / Wethospu
            if (tag.Contains("="))
              continue;
            var effectIndex = Helper.FirstIndexOf(effectStr, new[] { ' ', '|', ')' }, index);
            // Check for valid ending characters. / 2015-08-09 / Wethospu
            if (effectStr[effectIndex - 1] == '!' || effectStr[effectIndex - 1] == ',' || effectStr[effectIndex - 1] == '.' || effectStr[effectIndex - 1] == ':')
              effectIndex--;
            if (effectIndex - index - 1 < 1)
            {
              Helper.ShowWarningMessage("Enemy " + baseEnemy.Name + ": Something wrong with line '" + original + "'. Note: ':' can't be used in text!");
              effectStr = effectStr.Remove(index, 1);
              continue;
            }

            var effect = effectStr.Substring(index + 1, effectIndex - index - 1);
            // Effect info format varies based on tag (separated by :). / 2015-08-09 / Wethospu
            var effectData = effect.Split(':');
            var effectType = GetEffectType(tag);

            var category = tag.ToLower();
            var amount = 0.0;
            var duration = 0.0;
            var stacks = 1;
            var buff = "";
            var icon = category;
            var stacksAdditively = true;
            var suffix = "damage";
            if (effectType == EffectType.Damage || effectType == EffectType.DamageFixed || effectType == EffectType.DamagePercent)
            {
              if (effectData[0].Equals("-"))
            amount = coefficient;
              else
            amount = Helper.ParseD(effectData[0]);
              icon = "damage";
              stacks = 1;
            }
            else if (effectType == EffectType.Healing || effectType == EffectType.HealingPercent)
            {
              amount = Helper.ParseD(effectData[0]);
              suffix = "healing";
              icon = "healing";
              stacks = 1;
            }
            if (effectType == EffectType.Boon|| effectType == EffectType.Condition  || effectType == EffectType.Control)
            {
              baseEnemy.Tags.Add(category);
            }
            if (effectType == EffectType.Agony || effectType == EffectType.Boon || effectType == EffectType.Condition)
            {
              duration = Helper.ParseD(effectData[0]);
              if (effectType == EffectType.Agony || category.Equals("bleeding") || category.Equals("torment") || category.Equals("burning")
            || category.Equals("poison") || category.Equals("confusion") || category.Equals("regeneration") || category.Equals("might"))
            amount = duration;
              if (effectData.Length > 1)
            stacks = Helper.ParseI(effectData[1]);
              stacksAdditively = EffectStacksDuration(category);
              if (stacksAdditively || effectType == EffectType.Boon)
            suffix = "seconds";
              if (category.Equals("regeneration"))
            suffix = "healing";
              if (category.Equals("retaliation"))
            suffix = "damage per hit";
              if(category.Equals("might"))
            suffix = "more damage";
              if (category.Equals("retaliation") || category.Equals("might"))
            amount = 1;
            }
            if (effectType == EffectType.Control)
            {
              stacksAdditively = false;
              duration = Helper.ParseD(effectData[0]);
              if (effectData.Length > 1)
            stacks = Helper.ParseI(effectData[1]);
            }
            if (effectType == EffectType.Buff)
            {
              buff = effectData[0];
              icon = buff;
              if (effectData.Length > 1 && effectData[1].Length > 0)
            duration = Helper.ParseD(effectData[1]);
              if (effectData.Length > 2 && effectData[2].Length > 0)
            stacks = Helper.ParseI(effectData[2]);
              if (effectData.Length > 3 && effectData[3].Length > 0)
            icon = effectData[3];
              if (effectData.Length > 4)
            stacksAdditively = Helper.ParseI(effectData[4]) > 0 ? true : false;
            }

            var totalAmount = 0.0;
            var totalLength = 0.0;
            var totalDuration = 0.0;
            if (stacksAdditively)
            {
              totalAmount = hitCount * amount * stacks;
              totalDuration = hitCount * duration * stacks;
              totalLength = hitLength;
              // 3 different values makes the effect very confusing so just remove the hit length. / 2015-10-11 / Wethospu
              if (totalAmount > 0 && totalDuration > 0)
            totalLength = 0;
              stacks = 0;
            }
            else
            {
              amount = amount * stacks;
              totalAmount = hitCount * amount;
              totalDuration = 0;
              // Without damage don't do "over X seconds". Instead, just add the duration (makes control work properly). / 2015-10-01 / Wethospu
              if (amount == 0)
              {
            totalDuration = duration;
            duration = 0;
              }
              totalLength = hitLength + duration;
              stacks = hitCount * stacks;
            }

            AddTagsFromEffectType(effectType, baseEnemy);
            // Syntax: <span class="TAGValue">VALUE</span>
            var replace = new StringBuilder();
            //// Put both total and damage per hit. / 2015-09-08 / Wethospu
            if (amount > 0)
            {
              // All amounts need clientside formatting. / 2015-09-27 / Wethospu
              // Add information as data values so it can be recalculated in the browser when enemy level changes. / 2015 - 09 - 27 / Wethospu
              replace.Append("<span class=\"").Append(EffectTypeToClass(effectType)).Append("\" data-effect=\"").Append(category);
              if (category.Equals("confusion"))
            replace.Append("1");
              replace.Append("\" data-amount=\"").Append(totalAmount).Append("\" data-weapon=\"").Append(weapon).Append("\"></span>");
              replace.Append(" ").Append(suffix);
            }
            if (totalDuration > 0)
            {
              if (amount > 0)
            replace.Append(" over ");
              replace.Append(totalDuration).Append(" second");
              if (totalDuration != 1.0)
            replace.Append("s");
            }
            replace.Append(HitLengthStr(totalLength));
            if (hitCount > 1 && (amount > 0 || duration > 0))
            {
              // Same as above but for a single hit. / 2015-09-27 / Wethospu
              replace.Append("<span class=\"secondary-info\"> (");
              if (amount > 0)
              {
            // All amounts need clientside formatting. / 2015-09-27 / Wethospu
            // Add information as data values so it can be recalculated in the browser when enemy level changes. / 2015 - 09 - 27 / Wethospu
            replace.Append("<span class=\"").Append(EffectTypeToClass(effectType)).Append("\" data-effect=\"").Append(category);
            if (category.Equals("confusion"))
              replace.Append("1");
            replace.Append("\" data-amount=\"").Append(amount).Append("\"></span>");
            replace.Append(" ").Append(suffix);
              }
              if (duration > 0)
              {
            if (amount > 0)
              replace.Append(" over ");
            replace.Append(duration).Append(" second");
            if (totalDuration != 1.0)
              replace.Append("s");
              }
              replace.Append(" per hit)</span>");
            }
            if (category.Equals("confusion"))
            {
              suffix = "damage per skill usage";
              replace.Append(". ");
              if (amount > 0)
              {
            replace.Append("<span class=\"").Append(EffectTypeToClass(effectType)).Append("\" data-effect=\"").Append(category).Append("2");
            replace.Append("\" data-amount=\"").Append(totalAmount).Append("\"></span>");
            replace.Append(" ").Append(suffix);
              }
              if (duration > 0)
              {
            if (amount > 0)
              replace.Append(" over ");
            replace.Append(totalLength).Append(" second");
            if (totalLength != 1.0)
              replace.Append("s");
              }
              replace.Append(HitLengthStr(hitLength));
              if (hitCount > 1)
              {
            replace.Append("<span class=\"secondary-info\"> (");
            if (amount > 0)
            {
              replace.Append("<span class=\"").Append(EffectTypeToClass(effectType)).Append("\" data-effect=\"").Append(category).Append("2");
              if (category.Equals("confusion"))
                replace.Append("1");
              replace.Append("\" data-amount=\"").Append(amount).Append("\"></span>");
              replace.Append(" ").Append(suffix);
            }
            if (duration > 0)
            {
              if (amount > 0)
                replace.Append(" over ");
              replace.Append(duration).Append(" second");
              if (duration != 1.0)
                replace.Append("s");
            }
            replace.Append(" per hit)</span>");
              }
            }
            // Some effects can have variable or unknown hit count. Just add " per hit" in those cases. / 2015-09-29 / Wethospu
            if (variableHitCount)
              replace.Append(" per hit");
            if (hitFrequency > 0.01)
            {
              replace.Append(" every ").Append(hitFrequency).Append(" second");
              if (hitFrequency != 1.0)
            replace.Append("s");
            }
            if (effectType == EffectType.Buff)
            {
              // Add the buff name (people probably won't recognize all icons). / 2015-09-23 / Wethospu
              replace.Append(" (").Append(buff.Replace('_', ' ')).Append(")");
            }

            var toReplace = tag + ":" + effect;
            effectStr = effectStr.Replace(toReplace, replace.ToString());
            // Get the first subeffect type to display an icon. / 2015-09-09 / Wethospu
            if (firstType.Equals(""))
            {
              if (icon.Equals("-") && effectType == EffectType.Buff)
            startIcon = "Buff";
              else
            startIcon = "<span class=" + Constants.IconClass + " data-src=\"" + icon.ToLower() + "\" title=\"" + Helper.ToUpper(category.Replace('_', ' ')) + "\">" + Helper.ToUpper(category.Replace('_', ' ')) + "</span>";
              firstType = category;
              firstStacks = stacks;
            }
              }
              // Syntax: <li>'stacks'<span class="icon" title="effectType'"></span>: 'effect'</li>
              var effectBuilder = new StringBuilder();
              if (!firstType.Equals(""))
              {

            effectBuilder.Append(startIcon);
            if (firstStacks > 1)
              effectBuilder.Append("x").Append(firstStacks);
            if (effectStr.Length > 0)
             effectBuilder.Append(": ");
              }
              if (effectStr.Length > 0)
              {
            effectBuilder.Append(effectStr);
            if (effectBuilder.Length > 0 && effectBuilder[effectBuilder.Length - 1] != '.')
              effectBuilder.Append(".");
            if (firstType.Equals("torment"))
              effectBuilder.Append("<span class=\"secondary-info\"> Double damage when moving.</span>");
            if (effectChance.Length > 0)
              effectBuilder.Append(" ").Append(effectChance).Append(" chance per hit.");
              }
              return effectBuilder.ToString();
        }
 /// <summary>
 /// Sets fractal scaling type for a given enemy. See GW2Helper.ScalingTypeToString for accepted values.
 /// </summary>
 private static void HandleScaling(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"scaling='type'!");
       currentEnemy.ScalingType = data;
 }
Exemple #19
0
 /***********************************************************************************************
 * AddTagsFromEffectType / 2015-06-09 / Wethospu                                                *
 *                                                                                              *
 * Adds necessary tags to given enemy based on effect type (used for search).                   *
 * Displays a warning message if the effect type is not implemented.                            *
 *                                                                                              *
 * type: Effect type which affects added tags.                                                  *
 *                                                                                              *
 ***********************************************************************************************/
 private void AddTagsFromEffectType(EffectType type, Enemy baseEnemy)
 {
     if (type == EffectType.Agony)
     baseEnemy.Tags.Add("agony");
       else if (type == EffectType.Boon)
     baseEnemy.Tags.Add("boon");
       else if (type == EffectType.Buff)
     baseEnemy.Tags.Add("buff");
       else if (type == EffectType.Condition)
     baseEnemy.Tags.Add("condition");
       else if (type == EffectType.Control)
     baseEnemy.Tags.Add("control");
       else if (type == EffectType.Damage)
     baseEnemy.Tags.Add("damage");
       else if (type == EffectType.DamageFixed)
     baseEnemy.Tags.Add("fixed damage");
       else if (type == EffectType.DamagePercent)
     baseEnemy.Tags.Add("percent damage");
       else if (type == EffectType.Healing || type == EffectType.HealingPercent)
     baseEnemy.Tags.Add("healing");
       else if (type != EffectType.None)
     Helper.ShowWarningMessage("Internal error. Effect type not implemented.");
 }
 /// <summary>
 /// Similar to encounter tactics. Activates tactics for a given enemy. Activated tactics are able to receive content lines.
 /// </summary>
 private static void HandleTactic(string data, Enemy currentEnemy)
 {
     // Set validity to over max so custom tactics never get overridden by encounter tactics.
       currentEnemy.TacticValidity = 2.0;
       currentEnemy.HandleTactic(data, null);
 }
 /// <summary>
 /// Adds custom search tags to a given enemy. Not really in use because most tags are handled automatically.
 /// </summary>
 private static void HandleTag(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"tag='tag1'|'tag2'|'tag3'\"!");
       var split = data.Split('|');
       foreach (var str in split)
     currentEnemy.Tags.Add(str.ToLower());
 }
 /// <summary>
 /// Most toughness values are acquired automatically from datamined data. This is used for special cases.
 /// </summary>
 private static void HandleToughness(string data, Enemy currentEnemy)
 {
     if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"toughness='amount'.");
       currentEnemy.Attributes.Multipliers.Toughness = Helper.ParseD(data);
       if (currentEnemy.Attributes.Multipliers.Toughness > 100)
     ErrorHandler.ShowWarning("Toughness values should be multipliers. Calculate the multiplier.");
 }
 /***********************************************************************************************
 * GenerateEnemies / 2014-08-01 / Wethospu                                                      *
 *                                                                                              *
 * Generates enemies for one dungeon.                                                           *
 *                                                                                              *
 * Returns list of generated enemies.                                                           *
 * enemyAttributes: Datamined enemy attributes and other info.                                  *
 *                                                                                              *
 ***********************************************************************************************/
 public static List<Enemy> GenerateEnemies(Dictionary<string, EnemyAttributes> enemyAttributes)
 {
     var enemyData = new List<Enemy>();
       if (!Directory.Exists(Constants.DataEnemyRaw))
       {
     Helper.ShowWarning("Directory " + Constants.DataEnemyRaw + " doesn't exist.");
     return enemyData;
       }
       var enemyFiles = Directory.GetFiles(Constants.DataEnemyRaw);
       foreach (var file in enemyFiles)
       {
     if (Path.GetExtension(file) != ".txt")
       continue;
     string[] lines;
     if (File.Exists(file))
       lines = File.ReadAllLines(file, Constants.Encoding);
     else
     {
       Helper.ShowWarningMessage("File " + file + " doesn't exist!");
       return null;
     }
     Helper.CurrentFile = file;
     for (var row = 0; row < lines.Length; row++)
     {
       Helper.InitializeWarningSystem(row + 1, lines[row]);
       HandleLine(lines[row], enemyData, enemyAttributes);
     }
       }
       // Add the last enemy.
       if (_currentEffect != null && _currentAttack != null)
     _currentAttack.Effects.Add(_currentEffect);
       if (_currentAttack != null && _currentEnemy != null)
     _currentEnemy.Attacks.Add(_currentAttack);
       if (_currentEnemy != null)
     enemyData.Add(_currentEnemy);
       // Reset internal state.
       Helper.InitializeWarningSystem(-1, "");
       _currentEnemy = null;
       _currentAttack = null;
       _currentEffect = null;
       // Sort for consistency (also allows see enemies without proper ids). / 2015-10-05 / Wethospu
       enemyData.Sort();
       // Set up internal indexes. / 2015-10-05 / Wethospu
       for (var i = 0; i < enemyData.Count; i++)
     enemyData[i].Index = i;
       return enemyData;
 }
 private static void HandleAdditional(string data, Attack currentAttack, Enemy currentEnemy)
 {
     // Treat additional information as an effect for a simpler UI.
       if (data.Length == 0)
     ErrorHandler.ShowWarning("Missing info. Use \"additional='text'\".");
       var lower = data.ToLower();
       if (lower.Contains("can't be blocked") || lower.Contains("can't block"))
       {
     currentEnemy.Tags.Add("can't block");
     currentAttack.CantBeBlocked = true;
       }
       if (lower.Contains("can't be evaded") || lower.Contains("can't evade"))
     currentEnemy.Tags.Add("can't evade");
       currentAttack.Effects.Add(new Effect(LinkGenerator.CheckLinkSyntax(data)));
 }