@Override
  protected boolean thinkActive() {
    NpcInstance actor = getActor();
    if (actor == null || actor.isDead()) return true;

    if (_def_think) {
      doTask();
      return true;
    }

    if (diedTeredor < 3 || currentPoint >= MOVE_LOC.length - 1) {
      List<Creature> list =
          World.getAroundCharacters(
              getActor(), getActor().getAggroRange(), getActor().getAggroRange());
      for (Creature target : list) {
        if (target != null
            && !target.isDead()
            && ArrayUtils.contains(ATTACK_IDS, target.getNpcId())) {
          Skill sk = SkillTable.getInstance().getInfo(SKILL_ID, 1);
          if (lastCastTime + sk.getHitTime() + sk.getReuseDelay() <= System.currentTimeMillis()) {
            lastCastTime = System.currentTimeMillis();
            clearTasks();
            addTaskCast(target, sk);
            return true;
          }
          return false;
        }
      }
    } else if (diedTeredor >= 3 && currentPoint < MOVE_LOC.length - 1) {
      if (loc == null || getActor().getDistance(loc) <= 100) {
        currentPoint++;
        loc =
            new Location(
                MOVE_LOC[currentPoint].getX() + Rnd.get(50) - Rnd.get(50),
                MOVE_LOC[currentPoint].getY() + Rnd.get(50) - Rnd.get(50),
                MOVE_LOC[currentPoint].getZ() + Rnd.get(50) - Rnd.get(50));
        if (currentPoint == 0) {
          Reflection r = getActor().getReflection();
          if (r instanceof MemoryOfDisaster) {
            ((MemoryOfDisaster) r).spawnTransparentTeredor();
          }
        }
      }
      actor.setWalking();
      clearTasks();
      addTaskMove(loc, true);
      doTask();
      return true;
    }
    return false;
  }
 @Override
 protected void onEvtThink() {
   super.onEvtThink();
   if (!getActor().getAggroList().isEmpty()) {
     List<Creature> chars = World.getAroundCharacters(getActor());
     CollectionUtils.eqSort(chars, _nearestTargetComparator);
     for (Creature cha : chars) {
       if (getActor().getAggroList().get(cha) != null && checkAggression(cha)) {
         Skill sk = SkillTable.getInstance().getInfo(SKILL_ID, 1);
         if (lastCastTime + sk.getHitTime() + sk.getReuseDelay() <= System.currentTimeMillis()) {
           lastCastTime = System.currentTimeMillis();
           addTaskCast(cha, sk);
         }
       }
     }
   }
 }
public class ResidenceFunction {
  private static final Logger _log = LoggerFactory.getLogger(ResidenceFunction.class);

  // residence functions
  public static final int TELEPORT = 1;
  public static final int ITEM_CREATE = 2;
  public static final int RESTORE_HP = 3;
  public static final int RESTORE_MP = 4;
  public static final int RESTORE_EXP = 5;
  public static final int SUPPORT = 6;
  public static final int CURTAIN = 7;
  public static final int PLATFORM = 8;

  private int _id;
  private int _type;
  private int _level;
  private Calendar _endDate;
  private boolean _inDebt;
  private boolean _active;

  private Map<Integer, Integer> _leases = new ConcurrentSkipListMap<Integer, Integer>();
  private Map<Integer, TeleportLocation[]> _teleports =
      new ConcurrentSkipListMap<Integer, TeleportLocation[]>();
  private Map<Integer, int[]> _buylists = new ConcurrentSkipListMap<Integer, int[]>();
  private Map<Integer, Object[][]> _buffs = new ConcurrentSkipListMap<Integer, Object[][]>();

  public ResidenceFunction(int id, int type) {
    _id = id;
    _type = type;
    _endDate = Calendar.getInstance();
  }

  public int getResidenceId() {
    return _id;
  }

  public int getType() {
    return _type;
  }

  public int getLevel() {
    return _level;
  }

  public void setLvl(int lvl) {
    _level = lvl;
  }

  public long getEndTimeInMillis() {
    return _endDate.getTimeInMillis();
  }

  public void setEndTimeInMillis(long time) {
    _endDate.setTimeInMillis(time);
  }

  public void setInDebt(boolean inDebt) {
    _inDebt = inDebt;
  }

  public boolean isInDebt() {
    return _inDebt;
  }

  public void setActive(boolean active) {
    _active = active;
  }

  public boolean isActive() {
    return _active;
  }

  public void updateRentTime(boolean inDebt) {
    setEndTimeInMillis(System.currentTimeMillis() + 86400000);

    Connection con = null;
    PreparedStatement statement = null;
    try {
      con = DatabaseFactory.getInstance().getConnection();
      statement =
          con.prepareStatement(
              "UPDATE residence_functions SET endTime=?, inDebt=? WHERE type=? AND id=?");
      statement.setInt(1, (int) (getEndTimeInMillis() / 1000));
      statement.setInt(2, inDebt ? 1 : 0);
      statement.setInt(3, getType());
      statement.setInt(4, getResidenceId());
      statement.executeUpdate();
    } catch (Exception e) {
      _log.error("", e);
    } finally {
      DbUtils.closeQuietly(con, statement);
    }
  }

  public TeleportLocation[] getTeleports() {
    return getTeleports(_level);
  }

  public TeleportLocation[] getTeleports(int level) {
    return _teleports.get(level);
  }

  public void addTeleports(int level, TeleportLocation[] teleports) {
    _teleports.put(level, teleports);
  }

  public int getLease() {
    if (_level == 0) return 0;
    return getLease(_level);
  }

  public int getLease(int level) {
    return _leases.get(level);
  }

  public void addLease(int level, int lease) {
    _leases.put(level, lease);
  }

  public int[] getBuylist() {
    return getBuylist(_level);
  }

  public int[] getBuylist(int level) {
    return _buylists.get(level);
  }

  public void addBuylist(int level, int[] buylist) {
    _buylists.put(level, buylist);
  }

  public Object[][] getBuffs() {
    return getBuffs(_level);
  }

  public Object[][] getBuffs(int level) {
    return _buffs.get(level);
  }

  public void addBuffs(int level) {
    _buffs.put(level, buffs_template[level]);
  }

  public Set<Integer> getLevels() {
    return _leases.keySet();
  }

  public static final String A = "";
  public static final String W = "W";
  public static final String M = "M";

  private static final Object[][][] buffs_template = {
    {
      // level 0 - no buff
    },
    {
      // level 1
      {SkillTable.getInstance().getInfo(4342, 1), A},
      {SkillTable.getInstance().getInfo(4343, 1), A},
      {SkillTable.getInstance().getInfo(4344, 1), A},
      {SkillTable.getInstance().getInfo(4346, 1), A},
      {SkillTable.getInstance().getInfo(4345, 1), W},
    },
    {
      // level 2
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
    },
    {
      // level 3
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
    },
    {
      // level 4
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
      {SkillTable.getInstance().getInfo(4347, 2), A},
      {SkillTable.getInstance().getInfo(4349, 1), A},
      {SkillTable.getInstance().getInfo(4350, 1), W},
      {SkillTable.getInstance().getInfo(4348, 2), A},
    },
    {
      // level 5
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
      {SkillTable.getInstance().getInfo(4347, 2), A},
      {SkillTable.getInstance().getInfo(4349, 1), A},
      {SkillTable.getInstance().getInfo(4350, 1), W},
      {SkillTable.getInstance().getInfo(4348, 2), A},
      {SkillTable.getInstance().getInfo(4351, 2), M},
      {SkillTable.getInstance().getInfo(4352, 1), A},
      {SkillTable.getInstance().getInfo(4353, 2), W},
      {SkillTable.getInstance().getInfo(4358, 1), W},
      {SkillTable.getInstance().getInfo(4354, 1), W},
    },
    {
      // level 6 - unused
    },
    {
      // level 7
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
      {SkillTable.getInstance().getInfo(4347, 6), A},
      {SkillTable.getInstance().getInfo(4349, 2), A},
      {SkillTable.getInstance().getInfo(4350, 4), W},
      {SkillTable.getInstance().getInfo(4348, 6), A},
      {SkillTable.getInstance().getInfo(4351, 6), M},
      {SkillTable.getInstance().getInfo(4352, 2), A},
      {SkillTable.getInstance().getInfo(4353, 6), W},
      {SkillTable.getInstance().getInfo(4358, 3), W},
      {SkillTable.getInstance().getInfo(4354, 4), W},
    },
    {
      // level 8
      {SkillTable.getInstance().getInfo(4342, 2), A},
      {SkillTable.getInstance().getInfo(4343, 3), A},
      {SkillTable.getInstance().getInfo(4344, 3), A},
      {SkillTable.getInstance().getInfo(4346, 4), A},
      {SkillTable.getInstance().getInfo(4345, 3), W},
      {SkillTable.getInstance().getInfo(4347, 6), A},
      {SkillTable.getInstance().getInfo(4349, 2), A},
      {SkillTable.getInstance().getInfo(4350, 4), W},
      {SkillTable.getInstance().getInfo(4348, 6), A},
      {SkillTable.getInstance().getInfo(4351, 6), M},
      {SkillTable.getInstance().getInfo(4352, 2), A},
      {SkillTable.getInstance().getInfo(4353, 6), W},
      {SkillTable.getInstance().getInfo(4358, 3), W},
      {SkillTable.getInstance().getInfo(4354, 4), W},
      {SkillTable.getInstance().getInfo(4355, 1), M},
      {SkillTable.getInstance().getInfo(4356, 1), M},
      {SkillTable.getInstance().getInfo(4357, 1), W},
      {SkillTable.getInstance().getInfo(4359, 1), W},
      {SkillTable.getInstance().getInfo(4360, 1), W},
    },
    {
      // level 9 - unused
    },
    {
      // level 10 - unused
    },
    {
      // level 11
      {SkillTable.getInstance().getInfo(4342, 3), A},
      {SkillTable.getInstance().getInfo(4343, 4), A},
      {SkillTable.getInstance().getInfo(4344, 4), A},
      {SkillTable.getInstance().getInfo(4346, 5), A},
      {SkillTable.getInstance().getInfo(4345, 4), W},
    },
    {
      // level 12
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
    },
    {
      // level 13
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
    },
    {
      // level 14
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
      {SkillTable.getInstance().getInfo(4347, 8), A},
      {SkillTable.getInstance().getInfo(4349, 3), A},
      {SkillTable.getInstance().getInfo(4350, 5), W},
      {SkillTable.getInstance().getInfo(4348, 8), A},
    },
    {
      // level 15
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
      {SkillTable.getInstance().getInfo(4347, 8), A},
      {SkillTable.getInstance().getInfo(4349, 3), A},
      {SkillTable.getInstance().getInfo(4350, 5), W},
      {SkillTable.getInstance().getInfo(4348, 8), A},
      {SkillTable.getInstance().getInfo(4351, 8), M},
      {SkillTable.getInstance().getInfo(4352, 3), A},
      {SkillTable.getInstance().getInfo(4353, 8), W},
      {SkillTable.getInstance().getInfo(4358, 4), W},
      {SkillTable.getInstance().getInfo(4354, 5), W},
    },
    {
      // level 16 - unused
    },
    {
      // level 17
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
      {SkillTable.getInstance().getInfo(4347, 12), A},
      {SkillTable.getInstance().getInfo(4349, 4), A},
      {SkillTable.getInstance().getInfo(4350, 8), W},
      {SkillTable.getInstance().getInfo(4348, 12), A},
      {SkillTable.getInstance().getInfo(4351, 12), M},
      {SkillTable.getInstance().getInfo(4352, 4), A},
      {SkillTable.getInstance().getInfo(4353, 12), W},
      {SkillTable.getInstance().getInfo(4358, 6), W},
      {SkillTable.getInstance().getInfo(4354, 8), W},
    },
    {
      // level 18
      {SkillTable.getInstance().getInfo(4342, 4), A},
      {SkillTable.getInstance().getInfo(4343, 6), A},
      {SkillTable.getInstance().getInfo(4344, 6), A},
      {SkillTable.getInstance().getInfo(4346, 8), A},
      {SkillTable.getInstance().getInfo(4345, 6), W},
      {SkillTable.getInstance().getInfo(4347, 12), A},
      {SkillTable.getInstance().getInfo(4349, 4), A},
      {SkillTable.getInstance().getInfo(4350, 8), W},
      {SkillTable.getInstance().getInfo(4348, 12), A},
      {SkillTable.getInstance().getInfo(4351, 12), M},
      {SkillTable.getInstance().getInfo(4352, 4), A},
      {SkillTable.getInstance().getInfo(4353, 12), W},
      {SkillTable.getInstance().getInfo(4358, 6), W},
      {SkillTable.getInstance().getInfo(4354, 8), W},
      {SkillTable.getInstance().getInfo(4355, 4), M},
      {SkillTable.getInstance().getInfo(4356, 4), M},
      {SkillTable.getInstance().getInfo(4357, 3), W},
      {SkillTable.getInstance().getInfo(4359, 4), W},
      {SkillTable.getInstance().getInfo(4360, 4), W},
    },
  };
}
  @Override
  protected void readData(org.dom4j.Element rootElement) throws Exception {
    for (Iterator<org.dom4j.Element> itemIterator = rootElement.elementIterator();
        itemIterator.hasNext(); ) {
      org.dom4j.Element itemElement = itemIterator.next();
      StatsSet set = new StatsSet();
      set.set("item_id", itemElement.attributeValue("id"));
      set.set("name", itemElement.attributeValue("name"));
      set.set("add_name", itemElement.attributeValue("add_name", StringUtils.EMPTY));

      int slot = 0;
      for (Iterator<org.dom4j.Element> subIterator = itemElement.elementIterator();
          subIterator.hasNext(); ) {
        org.dom4j.Element subElement = subIterator.next();
        String subName = subElement.getName();
        if (subName.equalsIgnoreCase("set"))
          set.set(subElement.attributeValue("name"), subElement.attributeValue("value"));
        else if (subName.equalsIgnoreCase("equip"))
          for (Iterator<org.dom4j.Element> slotIterator = subElement.elementIterator();
              slotIterator.hasNext(); ) {
            org.dom4j.Element slotElement = slotIterator.next();
            Bodypart bodypart = Bodypart.valueOf(slotElement.attributeValue("id"));
            if (bodypart.getReal() != null) slot = bodypart.mask();
            else slot |= bodypart.mask();
          }
      }

      set.set("bodypart", slot);

      ItemTemplate template = null;
      try {
        if (itemElement.getName().equalsIgnoreCase("weapon")) {
          if (!set.containsKey("class"))
            if ((slot & ItemTemplate.SLOT_L_HAND) > 0) // щиты
            set.set("class", ItemTemplate.ItemClass.ARMOR);
            else set.set("class", ItemTemplate.ItemClass.WEAPON);
          template = new WeaponTemplate(set);
        }
      } catch (Exception e) {
        // for(Map.Entry<String, Object> entry : set.entrySet())
        // {
        //	info("set " + entry.getKey() + ":" + entry.getValue());
        // }
        warn("Fail create item: " + set.get("item_id"), e);
        continue;
      }

      for (Iterator<org.dom4j.Element> subIterator = itemElement.elementIterator();
          subIterator.hasNext(); ) {
        org.dom4j.Element subElement = subIterator.next();
        String subName = subElement.getName();
        if (subName.equalsIgnoreCase("for")) parseFor(subElement, template);
        else if (subName.equalsIgnoreCase("triggers")) parseTriggers(subElement, template);
        else if (subName.equalsIgnoreCase("skills"))
          for (Iterator<org.dom4j.Element> nextIterator = subElement.elementIterator();
              nextIterator.hasNext(); ) {
            org.dom4j.Element nextElement = nextIterator.next();
            int id = Integer.parseInt(nextElement.attributeValue("id"));
            int level = Integer.parseInt(nextElement.attributeValue("level"));

            Skill skill = SkillTable.getInstance().getInfo(id, level);

            if (skill != null) template.attachSkill(skill);
            else
              info(
                  "Skill not found("
                      + id
                      + ","
                      + level
                      + ") for item:"
                      + set.getObject("item_id")
                      + "; file:"
                      + getCurrentFileName());
          }
        else if (subName.equalsIgnoreCase("enchant4_skill")) {
          int id = Integer.parseInt(subElement.attributeValue("id"));
          int level = Integer.parseInt(subElement.attributeValue("level"));

          Skill skill = SkillTable.getInstance().getInfo(id, level);
          if (skill != null) template.setEnchant4Skill(skill);
        } else if (subName.equalsIgnoreCase("cond")) {
          Condition condition = parseFirstCond(subElement);
          if (condition != null) {
            int msgId = parseNumber(subElement.attributeValue("msgId")).intValue();
            condition.setSystemMsg(msgId);

            template.setCondition(condition);
          }
        } else if (subName.equalsIgnoreCase("attributes")) {
          int[] attributes = new int[6];
          for (Iterator<org.dom4j.Element> nextIterator = subElement.elementIterator();
              nextIterator.hasNext(); ) {
            org.dom4j.Element nextElement = nextIterator.next();
            Element element;
            if (nextElement.getName().equalsIgnoreCase("attribute")) {
              element = Element.getElementByName(nextElement.attributeValue("element"));
              attributes[element.getId()] = Integer.parseInt(nextElement.attributeValue("value"));
            }
          }
          template.setBaseAtributeElements(attributes);
        } else if (subName.equalsIgnoreCase("enchant_options"))
          for (Iterator<org.dom4j.Element> nextIterator = subElement.elementIterator();
              nextIterator.hasNext(); ) {
            org.dom4j.Element nextElement = nextIterator.next();

            if (nextElement.getName().equalsIgnoreCase("level")) {
              int val = Integer.parseInt(nextElement.attributeValue("val"));

              int i = 0;
              int[] options = new int[3];
              for (org.dom4j.Element optionElement : nextElement.elements()) {
                OptionDataTemplate optionData =
                    OptionDataHolder.getInstance()
                        .getTemplate(Integer.parseInt(optionElement.attributeValue("id")));
                if (optionData == null) {
                  error(
                      "Not found option_data for id: "
                          + optionElement.attributeValue("id")
                          + "; item_id: "
                          + set.get("item_id"));
                  continue;
                }
                options[i++] = optionData.getId();
              }
              template.addEnchantOptions(val, options);
            }
          }
        else if (subName.equalsIgnoreCase("crystallization_info")) {
          for (Iterator<org.dom4j.Element> nextIterator = subElement.elementIterator();
              nextIterator.hasNext(); ) {
            org.dom4j.Element nextElement = nextIterator.next();
            if (nextElement.getName().equalsIgnoreCase("crystallization_item")) {
              int item_id = Integer.parseInt(nextElement.attributeValue("id"));
              int count = Integer.parseInt(nextElement.attributeValue("count"));
              double chance = Double.parseDouble(nextElement.attributeValue("chance"));
              template
                  .getCrystallizationInfo()
                  .addItem(new CrystallizationInfo.CrystallizationItem(item_id, count, chance));
            }
          }
        }
      }
      getHolder().addItem(template);
    }
  }