Package com.l2jfrozen.gameserver.model.actor.instance

Source Code of com.l2jfrozen.gameserver.model.actor.instance.L2TamedBeastInstance$CheckDuration

/*
* 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.model.actor.instance;

import static com.l2jfrozen.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;

import java.util.concurrent.Future;

import com.l2jfrozen.gameserver.ai.CtrlIntention;
import com.l2jfrozen.gameserver.datatables.SkillTable;
import com.l2jfrozen.gameserver.model.L2Character;
import com.l2jfrozen.gameserver.model.L2Object;
import com.l2jfrozen.gameserver.model.L2Skill;
import com.l2jfrozen.gameserver.network.serverpackets.NpcInfo;
import com.l2jfrozen.gameserver.network.serverpackets.StopMove;
import com.l2jfrozen.gameserver.templates.L2NpcTemplate;
import com.l2jfrozen.gameserver.thread.ThreadPoolManager;
import com.l2jfrozen.util.Point3D;
import com.l2jfrozen.util.random.Rnd;

// While a tamed beast behaves a lot like a pet (ingame) and does have
// an owner, in all other aspects, it acts like a mob.
// In addition, it can be fed in order to increase its duration.
// This class handles the running tasks, AI, and feed of the mob.
// The (mostly optional) AI on feeding the spawn is handled by the datapack ai script
/**
* The Class L2TamedBeastInstance.
*/
public final class L2TamedBeastInstance extends L2FeedableBeastInstance
{
 
  /** The _food skill id. */
  private int _foodSkillId;
 
  /** The Constant MAX_DISTANCE_FROM_HOME. */
  private static final int MAX_DISTANCE_FROM_HOME = 30000;
 
  /** The Constant MAX_DISTANCE_FROM_OWNER. */
  private static final int MAX_DISTANCE_FROM_OWNER = 2000;
 
  /** The Constant MAX_DURATION. */
  private static final int MAX_DURATION = 1200000; // 20 minutes
 
  /** The Constant DURATION_CHECK_INTERVAL. */
  private static final int DURATION_CHECK_INTERVAL = 60000; // 1 minute
 
  /** The Constant DURATION_INCREASE_INTERVAL. */
  private static final int DURATION_INCREASE_INTERVAL = 20000; // 20 secs (gained upon feeding)
 
  /** The Constant BUFF_INTERVAL. */
  private static final int BUFF_INTERVAL = 5000; // 5 seconds
 
  /** The _remaining time. */
  private int _remainingTime = MAX_DURATION;
 
  /** The _home z. */
  private int _homeX, _homeY, _homeZ;
 
  /** The _owner. */
  private L2PcInstance _owner;
 
  /** The _buff task. */
  private Future<?> _buffTask = null;
 
  /** The _duration check task. */
  private Future<?> _durationCheckTask = null;

  /**
   * Instantiates a new l2 tamed beast instance.
   *
   * @param objectId the object id
   * @param template the template
   */
  public L2TamedBeastInstance(int objectId, L2NpcTemplate template)
  {
    super(objectId, template);
    setHome(this);
  }

  /**
   * Instantiates a new l2 tamed beast instance.
   *
   * @param objectId the object id
   * @param template the template
   * @param owner the owner
   * @param foodSkillId the food skill id
   * @param x the x
   * @param y the y
   * @param z the z
   */
  public L2TamedBeastInstance(int objectId, L2NpcTemplate template, L2PcInstance owner, int foodSkillId, int x, int y, int z)
  {
    super(objectId, template);

    setCurrentHp(getMaxHp());
    setCurrentMp(getMaxMp());
    setOwner(owner);
    setFoodType(foodSkillId);
    setHome(x, y, z);
    this.spawnMe(x, y, z);
  }

  /**
   * On receive food.
   */
  public void onReceiveFood()
  {
    // Eating food extends the duration by 20secs, to a max of 20minutes
    _remainingTime = _remainingTime + DURATION_INCREASE_INTERVAL;
    if(_remainingTime > MAX_DURATION)
    {
      _remainingTime = MAX_DURATION;
    }
  }

  /**
   * Gets the home.
   *
   * @return the home
   */
  public Point3D getHome()
  {
    return new Point3D(_homeX, _homeY, _homeZ);
  }

  /**
   * Sets the home.
   *
   * @param x the x
   * @param y the y
   * @param z the z
   */
  public void setHome(int x, int y, int z)
  {
    _homeX = x;
    _homeY = y;
    _homeZ = z;
  }

  /**
   * Sets the home.
   *
   * @param c the new home
   */
  public void setHome(L2Character c)
  {
    setHome(c.getX(), c.getY(), c.getZ());
  }

  /**
   * Gets the remaining time.
   *
   * @return the remaining time
   */
  public int getRemainingTime()
  {
    return _remainingTime;
  }

  /**
   * Sets the remaining time.
   *
   * @param duration the new remaining time
   */
  public void setRemainingTime(int duration)
  {
    _remainingTime = duration;
  }

  /**
   * Gets the food type.
   *
   * @return the food type
   */
  public int getFoodType()
  {
    return _foodSkillId;
  }

  /**
   * Sets the food type.
   *
   * @param foodItemId the new food type
   */
  public void setFoodType(int foodItemId)
  {
    if(foodItemId > 0)
    {
      _foodSkillId = foodItemId;

      // start the duration checks
      // start the buff tasks
      if(_durationCheckTask != null)
      {
        _durationCheckTask.cancel(true);
      }

      _durationCheckTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckDuration(this), DURATION_CHECK_INTERVAL, DURATION_CHECK_INTERVAL);
    }
  }

  /* (non-Javadoc)
   * @see com.l2jfrozen.gameserver.model.actor.instance.L2MonsterInstance#doDie(com.l2jfrozen.gameserver.model.L2Character)
   */
  @Override
  public boolean doDie(L2Character killer)
  {
    if(!super.doDie(killer))
      return false;

    getAI().stopFollow();
    cleanTasks();
   
    return true;
  }
 
  /**
   * Clean tasks.
   */
  private synchronized void cleanTasks(){
   
    if(_buffTask != null){
      _buffTask.cancel(true);
      _buffTask = null;
    }
   
    if(_durationCheckTask!=null){
      _durationCheckTask.cancel(true);
      _durationCheckTask = null;
    }
   
    // clean up variables
    if(_owner != null)
    {
      _owner.setTrainedBeast(null);
      _owner = null;
    }

    _foodSkillId = 0;
    _remainingTime = 0;
   
  }

  /**
   * Gets the owner.
   *
   * @return the owner
   */
  public L2PcInstance getOwner()
  {
    return _owner;
  }

  /**
   * Sets the owner.
   *
   * @param owner the new owner
   */
  public void setOwner(L2PcInstance owner)
  {
    if(owner != null)
    {
      _owner = owner;
      setTitle(owner.getName());
      // broadcast the new title
      broadcastPacket(new NpcInfo(this, owner));

      owner.setTrainedBeast(this);

      // always and automatically follow the owner.
      getAI().startFollow(_owner, 100);

      // instead of calculating this value each time, let's get this now and pass it on
      int totalBuffsAvailable = 0;
      for(L2Skill skill : getTemplate().getSkills().values())
      {
        // if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
        if(skill.getSkillType() == L2Skill.SkillType.BUFF)
        {
          totalBuffsAvailable++;
        }
      }

      // start the buff tasks
      if(_buffTask != null)
      {
        _buffTask.cancel(true);
      }
      _buffTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckOwnerBuffs(this, totalBuffsAvailable), BUFF_INTERVAL, BUFF_INTERVAL);
    }
    else
    {
      doDespawn(); // despawn if no owner
    }
  }

  /**
   * Checks if is too far from home.
   *
   * @return true, if is too far from home
   */
  public boolean isTooFarFromHome()
  {
    return !this.isInsideRadius(_homeX, _homeY, _homeZ, MAX_DISTANCE_FROM_HOME, true, true);
  }

  /**
   * Do despawn.
   */
  public void doDespawn()
  {
    // stop running tasks
    getAI().stopFollow();
    stopHpMpRegeneration();
    setTarget(null);
    cleanTasks();
    onDecay();
  }

  // notification triggered by the owner when the owner is attacked.
  // tamed mobs will heal/recharge or debuff the enemy according to their skills
  /**
   * On owner got attacked.
   *
   * @param attacker the attacker
   */
  public void onOwnerGotAttacked(L2Character attacker)
  {
    // check if the owner is no longer around...if so, despawn
    if(_owner == null || _owner.isOnline() == 0)
    {
      doDespawn();
      return;
    }

    // if the owner is too far away, stop anything else and immediately run towards the owner.
    if(!_owner.isInsideRadius(this, MAX_DISTANCE_FROM_OWNER, true, true))
    {
      getAI().startFollow(_owner);
      return;
    }

    // if the owner is dead, do nothing...
    if(_owner.isDead())
      return;

    // if the tamed beast is currently in the middle of casting, let it complete its skill...
    if(isCastingNow())
      return;

    float HPRatio = (float) _owner.getCurrentHp() / _owner.getMaxHp();

    // if the owner has a lot of HP, then debuff the enemy with a random debuff among the available skills
    // use of more than one debuff at this moment is acceptable
    if(HPRatio >= 0.8)
    {
      for(L2Skill skill : getTemplate().getSkills().values())
      {
        // if the skill is a debuff, check if the attacker has it already [  attacker.getEffect(L2Skill skill) ]
        if(skill.getSkillType() == L2Skill.SkillType.DEBUFF && Rnd.get(3) < 1 && attacker.getFirstEffect(skill) != null)
        {
          sitCastAndFollow(skill, attacker);
        }
      }
    }
    // for HP levels between 80% and 50%, do not react to attack events (so that MP can regenerate a bit)
    // for lower HP ranges, heal or recharge the owner with 1 skill use per attack.
    else if(HPRatio < 0.5)
    {
      int chance = 1;
      if(HPRatio < 0.25)
      {
        chance = 2;
      }

      // if the owner has a lot of HP, then debuff the enemy with a random debuff among the available skills
      for(L2Skill skill : getTemplate().getSkills().values())
      {
        // if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
        if(Rnd.get(5) < chance && (skill.getSkillType() == L2Skill.SkillType.HEAL || skill.getSkillType() == L2Skill.SkillType.HOT || skill.getSkillType() == L2Skill.SkillType.BALANCE_LIFE || skill.getSkillType() == L2Skill.SkillType.HEAL_PERCENT || skill.getSkillType() == L2Skill.SkillType.HEAL_STATIC || skill.getSkillType() == L2Skill.SkillType.COMBATPOINTHEAL || skill.getSkillType() == L2Skill.SkillType.COMBATPOINTPERCENTHEAL || skill.getSkillType() == L2Skill.SkillType.CPHOT || skill.getSkillType() == L2Skill.SkillType.MANAHEAL || skill.getSkillType() == L2Skill.SkillType.MANA_BY_LEVEL || skill.getSkillType() == L2Skill.SkillType.MANAHEAL_PERCENT || skill.getSkillType() == L2Skill.SkillType.MANARECHARGE || skill.getSkillType() == L2Skill.SkillType.MPHOT))
        {
          sitCastAndFollow(skill, _owner);
          return;
        }
      }
    }
  }

  /**
   * Prepare and cast a skill: First smoothly prepare the beast for casting, by abandoning other actions Next, call
   * super.doCast(skill) in order to actually cast the spell Finally, return to auto-following the owner.
   *
   * @param skill the skill
   * @param target the target
   * @see com.l2jfrozen.gameserver.model.L2Character#doCast(com.l2jfrozen.gameserver.model.L2Skill)
   */
  protected void sitCastAndFollow(L2Skill skill, L2Character target)
  {
    stopMove(null);
    broadcastPacket(new StopMove(this));
    getAI().setIntention(AI_INTENTION_IDLE);

    setTarget(target);
    doCast(skill);
    getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, _owner);
  }

  /**
   * The Class CheckDuration.
   */
  private class CheckDuration implements Runnable
  {
   
    /** The _tamed beast. */
    private L2TamedBeastInstance _tamedBeast;

    /**
     * Instantiates a new check duration.
     *
     * @param tamedBeast the tamed beast
     */
    CheckDuration(L2TamedBeastInstance tamedBeast)
    {
      _tamedBeast = tamedBeast;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
      int foodTypeSkillId = _tamedBeast.getFoodType();
      L2PcInstance owner = _tamedBeast.getOwner();
      _tamedBeast.setRemainingTime(_tamedBeast.getRemainingTime() - DURATION_CHECK_INTERVAL);

      // I tried to avoid this as much as possible...but it seems I can't avoid hardcoding
      // ids further, except by carrying an additional variable just for these two lines...
      // Find which food item needs to be consumed.
      L2ItemInstance item = null;

      if(foodTypeSkillId == 2188)
      {
        item = owner.getInventory().getItemByItemId(6643);
      }
      else if(foodTypeSkillId == 2189)
      {
        item = owner.getInventory().getItemByItemId(6644);
      }

      // if the owner has enough food, call the item handler (use the food and triffer all necessary actions)
      if(item != null && item.getCount() >= 1)
      {
        L2Object oldTarget = owner.getTarget();
        owner.setTarget(_tamedBeast);
        L2Object[] targets =
        {
          _tamedBeast
        };

        // emulate a call to the owner using food, but bypass all checks for range, etc
        // this also causes a call to the AI tasks handling feeding, which may call onReceiveFood as required.
        owner.callSkill(SkillTable.getInstance().getInfo(foodTypeSkillId, 1), targets);
        owner.setTarget(oldTarget);
        oldTarget = null;
        targets = null;
      }
      else
      {
        // if the owner has no food, the beast immediately despawns, except when it was only
        // newly spawned.  Newly spawned beasts can last up to 5 minutes
        if(_tamedBeast.getRemainingTime() < MAX_DURATION - 300000)
        {
          _tamedBeast.setRemainingTime(-1);
        }
      }

      /* There are too many conflicting reports about whether distance from home should
       * be taken into consideration.  Disabled for now.
       *
      if (_tamedBeast.isTooFarFromHome())
        _tamedBeast.setRemainingTime(-1);
      */

      if(_tamedBeast.getRemainingTime() <= 0)
      {
        _tamedBeast.doDespawn();
      }

      item = null;
    }
  }

  /**
   * The Class CheckOwnerBuffs.
   */
  private class CheckOwnerBuffs implements Runnable
  {
   
    /** The _tamed beast. */
    private L2TamedBeastInstance _tamedBeast;
   
    /** The _num buffs. */
    private int _numBuffs;

    /**
     * Instantiates a new check owner buffs.
     *
     * @param tamedBeast the tamed beast
     * @param numBuffs the num buffs
     */
    CheckOwnerBuffs(L2TamedBeastInstance tamedBeast, int numBuffs)
    {
      _tamedBeast = tamedBeast;
      _numBuffs = numBuffs;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
      L2PcInstance owner = _tamedBeast.getOwner();

      // check if the owner is no longer around...if so, despawn
      if(owner == null || owner.isOnline() == 0)
      {
        doDespawn();
        return;
      }

      // if the owner is too far away, stop anything else and immediately run towards the owner.
      if(!isInsideRadius(owner, MAX_DISTANCE_FROM_OWNER, true, true))
      {
        getAI().startFollow(owner);
        return;
      }

      // if the owner is dead, do nothing...
      if(owner.isDead())
        return;

      // if the tamed beast is currently casting a spell, do not interfere (do not attempt to cast anything new yet).
      if(isCastingNow())
        return;

      int totalBuffsOnOwner = 0;
      int i = 0;
      int rand = Rnd.get(_numBuffs);
      L2Skill buffToGive = null;

      // get this npc's skills:  getSkills()
      for(L2Skill skill : _tamedBeast.getTemplate().getSkills().values())
      {
        // if the skill is a buff, check if the owner has it already [  owner.getEffect(L2Skill skill) ]
        if(skill.getSkillType() == L2Skill.SkillType.BUFF)
        {
          if(i == rand)
          {
            buffToGive = skill;
          }
          i++;
          if(owner.getFirstEffect(skill) != null)
          {
            totalBuffsOnOwner++;
          }
        }
      }
      // if the owner has less than 60% of this beast's available buff, cast a random buff
      if(_numBuffs * 2 / 3 > totalBuffsOnOwner)
      {
        _tamedBeast.sitCastAndFollow(buffToGive, owner);
      }
      getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, _tamedBeast.getOwner());
      buffToGive = null;
    }
  }
}
TOP

Related Classes of com.l2jfrozen.gameserver.model.actor.instance.L2TamedBeastInstance$CheckDuration

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.