Package com.l2jfrozen.gameserver.datatables.xml

Source Code of com.l2jfrozen.gameserver.datatables.xml.AugmentationData

/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*/
package com.l2jfrozen.gameserver.datatables.xml;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilderFactory;

import javolution.util.FastList;
import javolution.util.FastMap;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.datatables.SkillTable;
import com.l2jfrozen.gameserver.model.L2Augmentation;
import com.l2jfrozen.gameserver.model.L2Skill;
import com.l2jfrozen.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jfrozen.gameserver.skills.Stats;
import com.l2jfrozen.util.random.Rnd;

/**
* This class manages the augmentation data and can also create new augmentations.
*
* @author programmos & Incognito, sword dev
*/
public class AugmentationData
{
  private static final Logger _log = Logger.getLogger(AugmentationData.class.getName());

  // =========================================================
  private static AugmentationData _instance;

  public static final AugmentationData getInstance()
  {
    if(_instance == null)
    {
      _instance = new AugmentationData();
    }

    return _instance;
  }

  // =========================================================
  // Data Field

  // stats
  private static final int STAT_START = 1;
  private static final int STAT_END = 14560;
  private static final int STAT_BLOCKSIZE = 3640;
  //private static final int STAT_NUMBEROF_BLOCKS = 4;
  private static final int STAT_SUBBLOCKSIZE = 91;
  //private static final int STAT_NUMBEROF_SUBBLOCKS = 40;

  // skills
  private static final int BLUE_START = 14561;
  //private static final int PURPLE_START = 14578;
  //private static final int RED_START = 14685;
  private static final int SKILLS_BLOCKSIZE = 178;

  // basestats
  private static final int BASESTAT_STR = 16341;
  private static final int BASESTAT_CON = 16342;
  private static final int BASESTAT_INT = 16343;
  private static final int BASESTAT_MEN = 16344;

  private FastList<augmentationStat> _augmentationStats[];
  private Map<Integer, FastList<augmentationSkill>> _blueSkills;
  private Map<Integer, FastList<augmentationSkill>> _purpleSkills;
  private Map<Integer, FastList<augmentationSkill>> _redSkills;

  // =========================================================
  // Constructor
  @SuppressWarnings("unchecked")
  private AugmentationData()
  {
    _log.info("Initializing AugmentationData.");

    _augmentationStats = new FastList[4];
    _augmentationStats[0] = new FastList<augmentationStat>();
    _augmentationStats[1] = new FastList<augmentationStat>();
    _augmentationStats[2] = new FastList<augmentationStat>();
    _augmentationStats[3] = new FastList<augmentationStat>();

    _blueSkills = new FastMap<Integer, FastList<augmentationSkill>>();
    _purpleSkills = new FastMap<Integer, FastList<augmentationSkill>>();
    _redSkills = new FastMap<Integer, FastList<augmentationSkill>>();
    for(int i = 1; i <= 10; i++)
    {
      _blueSkills.put(i, new FastList<augmentationSkill>());
      _purpleSkills.put(i, new FastList<augmentationSkill>());
      _redSkills.put(i, new FastList<augmentationSkill>());
    }

    load();

    // Use size*4: since theres 4 blocks of stat-data with equivalent size
    _log.info("AugmentationData: Loaded: " + _augmentationStats[0].size() * 4 + " augmentation stats.");

    if(Config.DEBUG)
    {
      for(int i = 1; i <= 10; i++)
      {
        _log.info("AugmentationData: Loaded: " + _blueSkills.get(i).size() + " blue, " + _purpleSkills.get(i).size() + " purple and " + _redSkills.get(i).size() + " red skills for lifeStoneLevel " + i);
      }
    }

  }
 
  public static void reload(){
    _instance = null;
    getInstance();
  }

  // =========================================================
  // Nested Class

  public class augmentationSkill
  {
    private int _skillId;
    private int _maxSkillLevel;
    private int _augmentationSkillId;

    public augmentationSkill(int skillId, int maxSkillLevel, int augmentationSkillId)
    {
      _skillId = skillId;
      _maxSkillLevel = maxSkillLevel;
      _augmentationSkillId = augmentationSkillId;
    }

    public L2Skill getSkill(int level)
    {
      if(level > _maxSkillLevel)
        return SkillTable.getInstance().getInfo(_skillId, _maxSkillLevel);

      return SkillTable.getInstance().getInfo(_skillId, level);
    }

    public int getAugmentationSkillId()
    {
      return _augmentationSkillId;
    }
  }

  public class augmentationStat
  {
    private Stats _stat;
    private int _singleSize;
    private int _combinedSize;
    private float _singleValues[];
    private float _combinedValues[];

    public augmentationStat(Stats stat, float sValues[], float cValues[])
    {
      _stat = stat;
      _singleSize = sValues.length;
      _singleValues = sValues;
      _combinedSize = cValues.length;
      _combinedValues = cValues;
    }

    public int getSingleStatSize()
    {
      return _singleSize;
    }

    public int getCombinedStatSize()
    {
      return _combinedSize;
    }

    public float getSingleStatValue(int i)
    {
      if(i >= _singleSize || i < 0)
        return _singleValues[_singleSize - 1];

      return _singleValues[i];
    }

    public float getCombinedStatValue(int i)
    {
      if(i >= _combinedSize || i < 0)
        return _combinedValues[_combinedSize - 1];

      return _combinedValues[i];
    }

    public Stats getStat()
    {
      return _stat;
    }
  }

  // =========================================================
  // Method - Private

  private final void load()
  {
    // Load the skillmap
    // Note: the skillmap data is only used when generating new augmentations
    // the client expects a different id in order to display the skill in the
    // items description...
    try
    {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setValidating(false);
      factory.setIgnoringComments(true);

      int badAugmantData = 0;

      File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_skillmap.xml");
      if(!file.exists())
      {
        if(Config.DEBUG)
        {
          System.out.println("The augmentation skillmap file is missing.");
        }
        return;
      }

      Document doc = factory.newDocumentBuilder().parse(file);

      for(Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
      {
        if("list".equalsIgnoreCase(n.getNodeName()))
        {
          for(Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
          {
            if("augmentation".equalsIgnoreCase(d.getNodeName()))
            {
              NamedNodeMap attrs = d.getAttributes();
              int skillId = 0, augmentationId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
              String type = "blue";
              int skillLvL = 0;

              for(Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
              {
                if("skillId".equalsIgnoreCase(cd.getNodeName()))
                {
                  attrs = cd.getAttributes();
                  skillId = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
                }
                else if("skillLevel".equalsIgnoreCase(cd.getNodeName()))
                {
                  attrs = cd.getAttributes();
                  skillLvL = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
                }
                else if("type".equalsIgnoreCase(cd.getNodeName()))
                {
                  attrs = cd.getAttributes();
                  type = attrs.getNamedItem("val").getNodeValue();
                }
              }

              if(skillId == 0)
              {
                if(Config.DEBUG)
                {
                  _log.log(Level.SEVERE, "Bad skillId in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
                }
                badAugmantData++;
                continue;
              }
              else if(skillLvL == 0)
              {
                if(Config.DEBUG)
                {
                  _log.log(Level.SEVERE, "Bad skillLevel in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
                }
                badAugmantData++;
                continue;
              }

              int k = 1;
              while(augmentationId - k * SKILLS_BLOCKSIZE >= BLUE_START)
              {
                k++;
              }

              if(type.equalsIgnoreCase("blue"))
              {
                _blueSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
              }
              else if(type.equalsIgnoreCase("purple"))
              {
                _purpleSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
              }
              else
              {
                _redSkills.get(k).add(new augmentationSkill(skillId, skillLvL, augmentationId));
              }

              attrs = null;
            }
          }
        }
      }

      if(badAugmantData != 0)
      {
        _log.info("AugmentationData: " + badAugmantData + " bad skill(s) were skipped.");
      }

      doc = null;
      file = null;
    }
    catch(Exception e)
    {
      if(Config.ENABLE_ALL_EXCEPTIONS)
        e.printStackTrace();
     
      _log.log(Level.SEVERE, "Error parsing augmentation_skillmap.xml.", e);

      return;
    }

    // Load the stats from xml
    for(int i = 1; i < 5; i++)
    {
      try
      {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(false);
        factory.setIgnoringComments(true);

        File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_stats" + i + ".xml");

        if(!file.exists())
        {
          if(Config.DEBUG)
          {
            System.out.println("The augmentation stat data file " + i + " is missing.");
          }

          return;
        }

        Document doc = factory.newDocumentBuilder().parse(file);

        for(Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
        {
          if("list".equalsIgnoreCase(n.getNodeName()))
          {
            for(Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
            {
              if("stat".equalsIgnoreCase(d.getNodeName()))
              {
                NamedNodeMap attrs = d.getAttributes();
                String statName = attrs.getNamedItem("name").getNodeValue();

                float soloValues[] = null, combinedValues[] = null;

                for(Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
                {
                  if("table".equalsIgnoreCase(cd.getNodeName()))
                  {
                    attrs = cd.getAttributes();
                    String tableName = attrs.getNamedItem("name").getNodeValue();

                    StringTokenizer data = new StringTokenizer(cd.getFirstChild().getNodeValue());
                    List<Float> array = new FastList<Float>();

                    while(data.hasMoreTokens())
                    {
                      array.add(Float.parseFloat(data.nextToken()));
                    }

                    if(tableName.equalsIgnoreCase("#soloValues"))
                    {
                      soloValues = new float[array.size()];
                      int x = 0;

                      for(float value : array)
                      {
                        soloValues[x++] = value;
                      }
                    }
                    else
                    {
                      combinedValues = new float[array.size()];
                      int x = 0;

                      for(float value : array)
                      {
                        combinedValues[x++] = value;
                      }
                    }

                    tableName = null;
                  }
                }

                // store this stat
                _augmentationStats[(i - 1)].add(new augmentationStat(Stats.valueOfXml(statName), soloValues, combinedValues));

                statName = null;
                attrs = null;
              }
            }
          }
        }

        doc = null;
        file = null;
        factory = null;
      }
      catch(Exception e)
      {
        if(Config.ENABLE_ALL_EXCEPTIONS)
          e.printStackTrace();
       
        _log.log(Level.SEVERE, "Error parsing augmentation_stats" + i + ".xml.", e);
        return;
      }
    }
  }

  // =========================================================
  // Properties - Public

  /**
   * Generate a new random augmentation
   *
   * @param item
   * @param lifeStoneLevel
   * @param lifeStoneGrade
   * @return L2Augmentation
   */
  public L2Augmentation generateRandomAugmentation(L2ItemInstance item, int lifeStoneLevel, int lifeStoneGrade)
  {
    // Note that stat12 stands for stat 1 AND 2 (same for stat34 ;p )
    // this is because a value can contain up to 2 stat modifications
    // (there are two short values packed in one integer value, meaning 4 stat modifications at max)
    // for more info take a look at getAugStatsById(...)

    // Note: lifeStoneGrade: (0 means low grade, 3 top grade)
    // First: determine whether we will add a skill/baseStatModifier or not because this determine which color could be the result
    int skill_Chance = 0;
    int stat34 = 0;
    boolean generateSkill = false;
    int resultColor = 0;
    boolean generateGlow = false;

    switch(lifeStoneGrade)
    {
      case 0:
        skill_Chance = Config.AUGMENTATION_NG_SKILL_CHANCE;

        if(Rnd.get(1, 100) <= Config.AUGMENTATION_NG_GLOW_CHANCE)
        {
          generateGlow = true;
        }
        break;

      case 1:
        skill_Chance = Config.AUGMENTATION_MID_SKILL_CHANCE;

        if(Rnd.get(1, 100) <= Config.AUGMENTATION_MID_GLOW_CHANCE)
        {
          generateGlow = true;
        }
        break;

      case 2:
        skill_Chance = Config.AUGMENTATION_HIGH_SKILL_CHANCE;

        if(Rnd.get(1, 100) <= Config.AUGMENTATION_HIGH_GLOW_CHANCE)
        {
          generateGlow = true;
        }
        break;

      case 3:
        skill_Chance = Config.AUGMENTATION_TOP_SKILL_CHANCE;

        if(Rnd.get(1, 100) <= Config.AUGMENTATION_TOP_GLOW_CHANCE)
        {
          generateGlow = true;
        }
    }

    if(Rnd.get(1, 100) <= skill_Chance)
    {
      generateSkill = true;
    }
    else if(Rnd.get(1, 100) <= Config.AUGMENTATION_BASESTAT_CHANCE)
    {
      stat34 = Rnd.get(BASESTAT_STR, BASESTAT_MEN);
    }

    // Second: decide which grade the augmentation result is going to have:
    // 0:yellow, 1:blue, 2:purple, 3:red
    // The chances used here are most likely custom,
    // whats known is: u can also get a red result from a normal grade lifeStone
    // however I will make it so that a higher grade lifeStone will more likely result in a
    // higher grade augmentation... and the augmentation result will at least have the grade
    // of the life stone
    // Second: Calculate the subblock offset for the choosen color,
    // and the level of the lifeStone
    // whats known is: you cant have yellow with skill(or baseStatModifier)
    // noGrade stone can not have glow, mid only with skill, high has a chance(custom), top allways glow
    if(stat34 == 0 && !generateSkill)
    {
      resultColor = Rnd.get(0, 100);

      if(resultColor <= 15 * lifeStoneGrade + 40)
      {
        resultColor = 1;
      }
      else
      {
        resultColor = 0;
      }
    }
    else
    {
      resultColor = Rnd.get(0, 100);

      if(resultColor <= 10 * lifeStoneGrade + 5 || stat34 != 0)
      {
        resultColor = 3;
      }
      else if(resultColor <= 10 * lifeStoneGrade + 10)
      {
        resultColor = 1;
      }
      else
      {
        resultColor = 2;
      }
    }

    // is neither a skill nor basestat used for stat34? then generate a normal stat
    int stat12 = 0;

    if(stat34 == 0 && !generateSkill)
    {
      int temp = Rnd.get(2, 3);
      int colorOffset = resultColor * 10 * STAT_SUBBLOCKSIZE + temp * STAT_BLOCKSIZE + 1;
      int offset = (lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE + colorOffset;

      stat34 = Rnd.get(offset, offset + STAT_SUBBLOCKSIZE - 1);

      if(generateGlow && lifeStoneGrade >= 2)
      {
        offset = (lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE + (temp - 2) * STAT_BLOCKSIZE + lifeStoneGrade * 10 * STAT_SUBBLOCKSIZE + 1;
      }
      else
      {
        offset = (lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE + (temp - 2) * STAT_BLOCKSIZE + Rnd.get(0, 1) * 10 * STAT_SUBBLOCKSIZE + 1;
      }
      stat12 = Rnd.get(offset, offset + STAT_SUBBLOCKSIZE - 1);
    }
    else
    {
      int offset;

      if(!generateGlow)
      {
        offset = (lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE + Rnd.get(0, 1) * STAT_BLOCKSIZE + 1;
      }
      else
      {
        offset = (lifeStoneLevel - 1) * STAT_SUBBLOCKSIZE + Rnd.get(0, 1) * STAT_BLOCKSIZE + (lifeStoneGrade + resultColor) / 2 * 10 * STAT_SUBBLOCKSIZE + 1;
      }
      stat12 = Rnd.get(offset, offset + STAT_SUBBLOCKSIZE - 1);
    }

    // generate a skill if neccessary
    L2Skill skill = null;
    if(generateSkill)
    {
      augmentationSkill temp = null;
      switch(resultColor)
      {
        case 1: // blue skill
          temp = _blueSkills.get(lifeStoneLevel).get(Rnd.get(0, _blueSkills.get(lifeStoneLevel).size() - 1));
          skill = temp.getSkill(lifeStoneLevel);
          stat34 = temp.getAugmentationSkillId();
          break;
        case 2: // purple skill
          temp = _purpleSkills.get(lifeStoneLevel).get(Rnd.get(0, _purpleSkills.get(lifeStoneLevel).size() - 1));
          skill = temp.getSkill(lifeStoneLevel);
          stat34 = temp.getAugmentationSkillId();
          break;
        case 3: // red skill
          temp = _redSkills.get(lifeStoneLevel).get(Rnd.get(0, _redSkills.get(lifeStoneLevel).size() - 1));
          skill = temp.getSkill(lifeStoneLevel);
          stat34 = temp.getAugmentationSkillId();
          break;
      }
    }
    if(Config.DEBUG)
    {
      _log.info("Augmentation success: stat12=" + stat12 + "; stat34=" + stat34 + "; resultColor=" + resultColor + "; level=" + lifeStoneLevel + "; grade=" + lifeStoneGrade);
    }

    return new L2Augmentation(item, ((stat34 << 16) + stat12), skill, true);
  }

  public class AugStat
  {
    private Stats _stat;
    private float _value;

    public AugStat(Stats stat, float value)
    {
      _stat = stat;
      _value = value;
    }

    public Stats getStat()
    {
      return _stat;
    }

    public float getValue()
    {
      return _value;
    }
  }

  /**
   * Returns the stat and basestat boni for a given augmentation id
   *
   * @param augmentationId
   * @return
   */
  public FastList<AugStat> getAugStatsById(int augmentationId)
  {
    FastList<AugStat> temp = new FastList<AugStat>();
    // An augmentation id contains 2 short vaues so we gotta seperate them here
    // both values contain a number from 1-16380, the first 14560 values are stats
    // the 14560 stats are devided into 4 blocks each holding 3640 values
    // each block contains 40 subblocks holding 91 stat values
    // the first 13 values are so called Solo-stats and they have the highest stat increase possible
    // after the 13 Solo-stats come 78 combined stats (thats every possible combination of the 13 solo stats)
    // the first 12 combined stats (14-26) is the stat 1 combined with stat 2-13
    // the next 11 combined stats then are stat 2 combined with stat 3-13 and so on...
    // to get the idea have a look @ optiondata_client-e.dat - thats where the data came from :)
    int stats[] = new int[2];
    stats[0] = 0x0000FFFF & augmentationId;
    stats[1] = augmentationId >> 16;

    for(int i = 0; i < 2; i++)
    {
      // its a stat
      if(stats[i] >= STAT_START && stats[i] <= STAT_END)
      {
        int block = 0;

        while(stats[i] > STAT_BLOCKSIZE)
        {
          stats[i] -= STAT_BLOCKSIZE;
          block++;
        }

        int subblock = 0;

        while(stats[i] > STAT_SUBBLOCKSIZE)
        {
          stats[i] -= STAT_SUBBLOCKSIZE;
          subblock++;
        }

        if(stats[i] < 14) // solo stat
        {
          augmentationStat as = _augmentationStats[block].get((stats[i] - 1));
          temp.add(new AugStat(as.getStat(), as.getSingleStatValue(subblock)));
        }
        else
        // twin stat
        {
          stats[i] -= 13; // rescale to 0 (if first of first combined block)

          int x = 12; // next combi block has 12 stats
          int rescales = 0; // number of rescales done

          while(stats[i] > x)
          {
            stats[i] -= x;
            x--;
            rescales++;
          }

          // get first stat
          augmentationStat as = _augmentationStats[block].get(rescales);
          if(rescales == 0)
          {
            temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock)));
          }
          else
          {
            temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock * 2 + 1)));
          }

          // get 2nd stat
          as = _augmentationStats[block].get(rescales + stats[i]);
          if(as.getStat() == Stats.CRITICAL_DAMAGE)
          {
            temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock)));
          }
          else
          {
            temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(subblock * 2)));
          }

          as = null;
        }
      }
      // its a base stat
      else if(stats[i] >= BASESTAT_STR && stats[i] <= BASESTAT_MEN)
      {
        switch(stats[i])
        {
          case BASESTAT_STR:
            temp.add(new AugStat(Stats.STAT_STR, 1.0f));
            break;
          case BASESTAT_CON:
            temp.add(new AugStat(Stats.STAT_CON, 1.0f));
            break;
          case BASESTAT_INT:
            temp.add(new AugStat(Stats.STAT_INT, 1.0f));
            break;
          case BASESTAT_MEN:
            temp.add(new AugStat(Stats.STAT_MEN, 1.0f));
            break;
        }
      }
    }

    return temp;
  }
}
TOP

Related Classes of com.l2jfrozen.gameserver.datatables.xml.AugmentationData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.