Package com.l2jfrozen.gameserver.model.entity

Source Code of com.l2jfrozen.gameserver.model.entity.Duel

/*
* 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.entity;

import java.util.Calendar;
import java.util.logging.Logger;

import javolution.util.FastList;

import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.ai.CtrlIntention;
import com.l2jfrozen.gameserver.managers.DuelManager;
import com.l2jfrozen.gameserver.managers.OlympiadStadiaManager;
import com.l2jfrozen.gameserver.model.L2Character;
import com.l2jfrozen.gameserver.model.L2Effect;
import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
import com.l2jfrozen.gameserver.model.entity.olympiad.Olympiad;
import com.l2jfrozen.gameserver.network.SystemMessageId;
import com.l2jfrozen.gameserver.network.serverpackets.ActionFailed;
import com.l2jfrozen.gameserver.network.serverpackets.ExDuelEnd;
import com.l2jfrozen.gameserver.network.serverpackets.ExDuelReady;
import com.l2jfrozen.gameserver.network.serverpackets.ExDuelStart;
import com.l2jfrozen.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
import com.l2jfrozen.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jfrozen.gameserver.network.serverpackets.PlaySound;
import com.l2jfrozen.gameserver.network.serverpackets.SocialAction;
import com.l2jfrozen.gameserver.network.serverpackets.SystemMessage;
import com.l2jfrozen.gameserver.thread.ThreadPoolManager;

/**
* The Class Duel.
*/
public class Duel
{
 
  /** The Constant _log. */
  protected static final Logger _log = Logger.getLogger(Duel.class.getName());

  /** The Constant DUELSTATE_NODUEL. */
  public static final int DUELSTATE_NODUEL = 0;
 
  /** The Constant DUELSTATE_DUELLING. */
  public static final int DUELSTATE_DUELLING = 1;
 
  /** The Constant DUELSTATE_DEAD. */
  public static final int DUELSTATE_DEAD = 2;
 
  /** The Constant DUELSTATE_WINNER. */
  public static final int DUELSTATE_WINNER = 3;
 
  /** The Constant DUELSTATE_INTERRUPTED. */
  public static final int DUELSTATE_INTERRUPTED = 4;

  // =========================================================
  // Data Field
  /** The _duel id. */
  private int _duelId;
 
  /** The _player a. */
  private L2PcInstance _playerA;
 
  /** The _player b. */
  private L2PcInstance _playerB;
 
  /** The _party duel. */
  protected boolean _partyDuel;
 
  /** The _duel end time. */
  private Calendar _duelEndTime;
 
  /** The _surrender request. */
  private int _surrenderRequest = 0;
 
  /** The _countdown. */
  private int _countdown = 4;
 
  /** The _finished. */
  private boolean _finished = false;

  /** The _player conditions. */
  private FastList<PlayerCondition> _playerConditions;

  /**
   * The Enum DuelResultEnum.
   */
  public static enum DuelResultEnum
  {
   
    /** The Continue. */
    Continue,
   
    /** The Team1 win. */
    Team1Win,
   
    /** The Team2 win. */
    Team2Win,
   
    /** The Team1 surrender. */
    Team1Surrender,
   
    /** The Team2 surrender. */
    Team2Surrender,
   
    /** The Canceled. */
    Canceled,
   
    /** The Timeout. */
    Timeout
  }

  // =========================================================
  // Constructor
  /**
   * Instantiates a new duel.
   *
   * @param playerA the player a
   * @param playerB the player b
   * @param partyDuel the party duel
   * @param duelId the duel id
   */
  public Duel(L2PcInstance playerA, L2PcInstance playerB, int partyDuel, int duelId)
  {
    _duelId = duelId;
    _playerA = playerA;
    _playerB = playerB;
    _partyDuel = partyDuel == 1 ? true : false;

    _duelEndTime = Calendar.getInstance();

    if(_partyDuel)
    {
      _duelEndTime.add(Calendar.SECOND, 300);
    }
    else
    {
      _duelEndTime.add(Calendar.SECOND, 120);
    }

    _playerConditions = new FastList<PlayerCondition>();

    setFinished(false);

    if(_partyDuel)
    {
      // increase countdown so that start task can teleport players
      _countdown++;
      // inform players that they will be portet shortly
      SystemMessage sm = new SystemMessage(SystemMessageId.IN_A_MOMENT_YOU_WILL_BE_TRANSPORTED_TO_THE_SITE_WHERE_THE_DUEL_WILL_TAKE_PLACE);
      broadcastToTeam1(sm);
      broadcastToTeam2(sm);
      sm = null;
    }
    // Schedule duel start
    ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartDuelTask(this), 3000);
  }

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

  /**
   * The Class PlayerCondition.
   */
  public class PlayerCondition
  {
   
    /** The _player. */
    private L2PcInstance _player;
   
    /** The _hp. */
    private double _hp;
   
    /** The _mp. */
    private double _mp;
   
    /** The _cp. */
    private double _cp;
   
    /** The _pa duel. */
    private boolean _paDuel;
   
    /** The _z. */
    private int _x, _y, _z;
   
    /** The _debuffs. */
    private FastList<L2Effect> _debuffs;

    /**
     * Instantiates a new player condition.
     *
     * @param player the player
     * @param partyDuel the party duel
     */
    public PlayerCondition(L2PcInstance player, boolean partyDuel)
    {
      if(player == null)
        return;

      _player = player;
      _hp = _player.getCurrentHp();
      _mp = _player.getCurrentMp();
      _cp = _player.getCurrentCp();
      _paDuel = partyDuel;

      if(_paDuel)
      {
        _x = _player.getX();
        _y = _player.getY();
        _z = _player.getZ();
      }
    }

    /**
     * Restore condition.
     */
    public synchronized void restoreCondition()
    {
      if(_player == null)
        return;

      _player.setCurrentHp(_hp);
      _player.setCurrentMp(_mp);
      _player.setCurrentCp(_cp);

      if(_paDuel)
      {
        teleportBack();
      }

      if(_debuffs != null) // Debuff removal
      {
        for(L2Effect temp : _debuffs)
          if(temp != null)
          {
            temp.exit(false);
          }
      }
    }

    /**
     * Register debuff.
     *
     * @param debuff the debuff
     */
    public void registerDebuff(L2Effect debuff)
    {
      if(_debuffs == null)
      {
        _debuffs = new FastList<L2Effect>();
      }

      _debuffs.add(debuff);
    }

    /**
     * Teleport back.
     */
    public void teleportBack()
    {
      if(_paDuel)
      {
        _player.teleToLocation(_x, _y, _z);
      }
    }

    /**
     * Gets the player.
     *
     * @return the player
     */
    public L2PcInstance getPlayer()
    {
      return _player;
    }
  }

  // ===============================================================
  // Schedule task
  /**
   * The Class ScheduleDuelTask.
   */
  public class ScheduleDuelTask implements Runnable
  {
   
    /** The _duel. */
    private Duel _duel;

    /**
     * Instantiates a new schedule duel task.
     *
     * @param duel the duel
     */
    public ScheduleDuelTask(Duel duel)
    {
      _duel = duel;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
      try
      {
        DuelResultEnum status = _duel.checkEndDuelCondition();

        if(status == DuelResultEnum.Canceled)
        {
          // do not schedule duel end if it was interrupted
          setFinished(true);
          _duel.endDuel(status);
        }
        else if(status != DuelResultEnum.Continue)
        {
          setFinished(true);
          playKneelAnimation();
          ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEndDuelTask(_duel, status), 5000);
        }
        else
        {
          ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
        }

        status = null;
      }
      catch(Throwable t)
      {
        t.printStackTrace();
      }
    }
  }

  /**
   * The Class ScheduleStartDuelTask.
   */
  public class ScheduleStartDuelTask implements Runnable
  {
   
    /** The _duel. */
    private Duel _duel;

    /**
     * Instantiates a new schedule start duel task.
     *
     * @param duel the duel
     */
    public ScheduleStartDuelTask(Duel duel)
    {
      _duel = duel;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
      try
      {
        // start/continue countdown
        int count = _duel.countdown();

        if(!_partyDuel || count == 4){
          // Save player Conditions
          savePlayerConditions();
        }
       
        if(count == 4)
        {
          // players need to be teleportet first
          //TODO: stadia manager needs a function to return an unused stadium for duels
         
          // currently if oly in competition period
            //and defined location is into a stadium
            //just use Gludin Arena as location
          if(Olympiad.getInstance().inCompPeriod()
              && OlympiadStadiaManager.getInstance().getStadiumByLoc(Config.DUEL_SPAWN_X, Config.DUEL_SPAWN_Y, Config.DUEL_SPAWN_Z)!=null)
            _duel.teleportPlayers(-87912, 142221, -3645);
          else
            _duel.teleportPlayers(Config.DUEL_SPAWN_X, Config.DUEL_SPAWN_Y, Config.DUEL_SPAWN_Z);
         
          // give players 20 seconds to complete teleport and get ready (its ought to be 30 on offical..)
          ThreadPoolManager.getInstance().scheduleGeneral(this, 20000);
        }
        else if(count > 0) // duel not started yet - continue countdown
        {
          ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
        }
        else
        {
          _duel.startDuel();
        }
      }
      catch(Throwable t)
      {
        t.printStackTrace();
      }
    }
  }

  /**
   * The Class ScheduleEndDuelTask.
   */
  public static class ScheduleEndDuelTask implements Runnable
  {
   
    /** The _duel. */
    private Duel _duel;
   
    /** The _result. */
    private DuelResultEnum _result;

    /**
     * Instantiates a new schedule end duel task.
     *
     * @param duel the duel
     * @param result the result
     */
    public ScheduleEndDuelTask(Duel duel, DuelResultEnum result)
    {
      _duel = duel;
      _result = result;
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
      try
      {
        _duel.endDuel(_result);
      }
      catch(Throwable t)
      {
        t.printStackTrace();
      }
    }
  }

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

  /**
   * Stops all players from attacking. Used for duel timeout / interrupt.
   */
  private void stopFighting()
  {
    ActionFailed af = ActionFailed.STATIC_PACKET;
    if(_partyDuel)
    {
      for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
      {
        temp.abortCast();
        temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
        temp.setTarget(null);
        temp.sendPacket(af);
      }

      for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
      {
        temp.abortCast();
        temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
        temp.setTarget(null);
        temp.sendPacket(af);
      }
    }
    else
    {
      _playerA.abortCast();
      _playerB.abortCast();
      _playerA.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
      _playerA.setTarget(null);
      _playerB.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
      _playerB.setTarget(null);
      _playerA.sendPacket(af);
      _playerB.sendPacket(af);
    }

    af = null;
  }

  // ========================================================
  // Method - Public

  /**
   * Check if a player engaged in pvp combat (only for 1on1 duels).
   *
   * @param sendMessage the send message
   * @return returns true if a duelist is engaged in Pvp combat
   */
  public boolean isDuelistInPvp(boolean sendMessage)
  {
    if(_partyDuel)
      // Party duels take place in arenas - should be no other players there
      return false;
    else if(_playerA.getPvpFlag() != 0 || _playerB.getPvpFlag() != 0)
    {
      if(sendMessage)
      {
        String engagedInPvP = "The duel was canceled because a duelist engaged in PvP combat.";
        _playerA.sendMessage(engagedInPvP);
        _playerB.sendMessage(engagedInPvP);
      }

      return true;
    }

    return false;
  }

  /**
   * Starts the duel.
   */
  public void startDuel()
  {
    // Save player Conditions
    //savePlayerConditions();

    if(_playerA == null || _playerB == null || _playerA.isInDuel() || _playerB.isInDuel() ||  Olympiad.getInstance().isRegisteredInComp(_playerA) ||  Olympiad.getInstance().isRegisteredInComp(_playerB) || Olympiad.getInstance().isRegistered(_playerA) || Olympiad.getInstance().isRegistered(_playerB))
    {
      // clean up
      _playerConditions.clear();
      _playerConditions = null;
      DuelManager.getInstance().removeDuel(this);
      return;
    }

    if(_partyDuel)
    {
      // set isInDuel() state
      // cancel all active trades, just in case? xD
      for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
      {
        temp.cancelActiveTrade();
        temp.setIsInDuel(_duelId);
        temp.setTeam(1);
        //temp.broadcastStatusUpdate();
        temp.broadcastUserInfo();
        broadcastToTeam2(new ExDuelUpdateUserInfo(temp));
      }
      for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
      {
        temp.cancelActiveTrade();
        temp.setIsInDuel(_duelId);
        temp.setTeam(2);
        //temp.broadcastStatusUpdate();
        temp.broadcastUserInfo();
        broadcastToTeam1(new ExDuelUpdateUserInfo(temp));
      }

      // Send duel Start packets
      ExDuelReady ready = new ExDuelReady(1);
      ExDuelStart start = new ExDuelStart(1);

      broadcastToTeam1(ready);
      broadcastToTeam2(ready);
      broadcastToTeam1(start);
      broadcastToTeam2(start);

      ready = null;
      start = null;
    }
    else
    {
      // set isInDuel() state
      _playerA.setIsInDuel(_duelId);
      _playerA.setTeam(1);
      _playerB.setIsInDuel(_duelId);
      _playerB.setTeam(2);

      // Send duel Start packets
      ExDuelReady ready = new ExDuelReady(0);
      ExDuelStart start = new ExDuelStart(0);

      broadcastToTeam1(ready);
      broadcastToTeam2(ready);
      broadcastToTeam1(start);
      broadcastToTeam2(start);

      broadcastToTeam1(new ExDuelUpdateUserInfo(_playerB));
      broadcastToTeam2(new ExDuelUpdateUserInfo(_playerA));
      //_playerA.broadcastStatusUpdate();
      //_playerB.broadcastStatusUpdate();
      _playerA.broadcastUserInfo();
      _playerB.broadcastUserInfo();

      ready = null;
      start = null;
    }

    // play sound
    PlaySound ps = new PlaySound(1, "B04_S01", 0, 0, 0, 0, 0);
    broadcastToTeam1(ps);
    broadcastToTeam2(ps);

    ps = null;

    // start duelling task
    ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleDuelTask(this), 1000);
  }

  /**
   * Save the current player condition: hp, mp, cp, location.
   */
  public void savePlayerConditions()
  {
   
    if(_partyDuel)
    {
      for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
      {
        _playerConditions.add(new PlayerCondition(temp, _partyDuel));
      }

      for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
      {
        _playerConditions.add(new PlayerCondition(temp, _partyDuel));
      }
    }
    else
    {
      _playerConditions.add(new PlayerCondition(_playerA, _partyDuel));
      _playerConditions.add(new PlayerCondition(_playerB, _partyDuel));
    }
   
  }

  /**
   * Restore player conditions.
   *
   * @param abnormalDuelEnd the abnormal duel end
   */
  private synchronized void restorePlayerConditions(boolean abnormalDuelEnd)
  {
   
    // update isInDuel() state for all players
    if(_partyDuel)
    {
      for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
      {
        temp.setIsInDuel(0);
        temp.setTeam(0);
        temp.broadcastUserInfo();
      }

      for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
      {
        temp.setIsInDuel(0);
        temp.setTeam(0);
        temp.broadcastUserInfo();
      }
    }
    else
    {
      _playerA.setIsInDuel(0);
      _playerA.setTeam(0);
      _playerA.broadcastUserInfo();
      _playerB.setIsInDuel(0);
      _playerB.setTeam(0);
      _playerB.broadcastUserInfo();
    }

    // if it is an abnormal DuelEnd do not restore hp, mp, cp
    if(abnormalDuelEnd)
      return;

    // restore player conditions
    for(FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
    {
      e.getValue().restoreCondition();
    }
  }

  /**
   * Get the duel id.
   *
   * @return id
   */
  public int getId()
  {
    return _duelId;
  }

  /**
   * Returns the remaining time.
   *
   * @return remaining time
   */
  public int getRemainingTime()
  {
    return (int) (_duelEndTime.getTimeInMillis() - Calendar.getInstance().getTimeInMillis());
  }

  /**
   * Get the player that requestet the duel.
   *
   * @return duel requester
   */
  public L2PcInstance getPlayerA()
  {
    return _playerA;
  }

  /**
   * Get the player that was challenged.
   *
   * @return challenged player
   */
  public L2PcInstance getPlayerB()
  {
    return _playerB;
  }

  /**
   * Returns whether this is a party duel or not.
   *
   * @return is party duel
   */
  public boolean isPartyDuel()
  {
    return _partyDuel;
  }

  /**
   * Sets the finished.
   *
   * @param mode the new finished
   */
  public void setFinished(boolean mode)
  {
    _finished = mode;
  }

  /**
   * Gets the finished.
   *
   * @return the finished
   */
  public boolean getFinished()
  {
    return _finished;
  }

  /**
   * teleport all players to the given coordinates.
   *
   * @param x the x
   * @param y the y
   * @param z the z
   */
  public void teleportPlayers(int x, int y, int z)
  {
    //TODO: adjust the values if needed... or implement something better (especially using more then 1 arena)
    if(!_partyDuel)
      return;

    int offset = 0;

    for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
    {
      temp.teleToLocation(x + offset - 180, y - 150, z);
      offset += 40;
    }

    offset = 0;

    for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
    {
      temp.teleToLocation(x + offset - 180, y + 150, z);
      offset += 40;
    }
  }

  /**
   * Broadcast a packet to the challanger team.
   *
   * @param packet the packet
   */
  public void broadcastToTeam1(L2GameServerPacket packet)
  {
    if(_playerA == null)
      return;

    if(_partyDuel && _playerA.getParty() != null)
    {
      for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
      {
        temp.sendPacket(packet);
      }
    }
    else
    {
      _playerA.sendPacket(packet);
    }
  }

  /**
   * Broadcast a packet to the challenged team.
   *
   * @param packet the packet
   */
  public void broadcastToTeam2(L2GameServerPacket packet)
  {
    if(_playerB == null)
      return;

    if(_partyDuel && _playerB.getParty() != null)
    {
      for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
      {
        temp.sendPacket(packet);
      }
    }
    else
    {
      _playerB.sendPacket(packet);
    }
  }

  /**
   * Get the duel winner.
   *
   * @return winner
   */
  public L2PcInstance getWinner()
  {
    if(!getFinished() || _playerA == null || _playerB == null)
      return null;

    if(_playerA.getDuelState() == DUELSTATE_WINNER)
      return _playerA;

    if(_playerB.getDuelState() == DUELSTATE_WINNER)
      return _playerB;

    return null;
  }

  /**
   * Get the duel looser.
   *
   * @return looser
   */
  public L2PcInstance getLooser()
  {
    if(!getFinished() || _playerA == null || _playerB == null)
      return null;

    if(_playerA.getDuelState() == DUELSTATE_WINNER)
      return _playerB;
    else if (_playerB.getDuelState() == DUELSTATE_WINNER)
      return _playerA;

    return null;
  }

  /**
   * Playback the bow animation for all loosers.
   */
  public void playKneelAnimation()
  {
    L2PcInstance looser = getLooser();

    if(looser == null)
      return;

    if(_partyDuel && looser.getParty() != null)
    {
      for (L2PcInstance temp : looser.getParty().getPartyMembers())
        temp.broadcastPacket(new SocialAction(temp.getObjectId(), 7));
    }
    else
    {
      looser.broadcastPacket(new SocialAction(looser.getObjectId(), 7));
    }

    looser = null;
  }

  /**
   * Do the countdown and send message to players if necessary.
   *
   * @return current count
   */
  public int countdown()
  {
    _countdown--;

    if(_countdown > 3)
      return _countdown;

    // Broadcast countdown to duelists
    SystemMessage sm = null;
    if(_countdown > 0)
    {
      sm = new SystemMessage(SystemMessageId.THE_DUEL_WILL_BEGIN_IN_S1_SECONDS);
      sm.addNumber(_countdown);
    }
    else
    {
      sm = new SystemMessage(SystemMessageId.LET_THE_DUEL_BEGIN);
    }

    broadcastToTeam1(sm);
    broadcastToTeam2(sm);
    sm = null;

    return _countdown;
  }

  /**
   * The duel has reached a state in which it can no longer continue.
   *
   * @param result the result
   */
  public void endDuel(DuelResultEnum result)
  {
    if(_playerA == null || _playerB == null)
    {
      //clean up
      _playerConditions.clear();
      _playerConditions = null;
      DuelManager.getInstance().removeDuel(this);
      return;
    }

    // inform players of the result
    SystemMessage sm = null;
    switch(result)
    {
      case Team2Surrender:
      case Team1Win:
        restorePlayerConditions(false);

        // send SystemMessage
        if(_partyDuel)
        {
          sm = new SystemMessage(SystemMessageId.S1S_PARTY_HAS_WON_THE_DUEL);
        }
        else
        {
          sm = new SystemMessage(SystemMessageId.S1_HAS_WON_THE_DUEL);
        }

        sm.addString(_playerA.getName());

        broadcastToTeam1(sm);
        broadcastToTeam2(sm);
        break;
      case Team1Surrender:
      case Team2Win:
        restorePlayerConditions(false);
        // send SystemMessage
        if(_partyDuel)
        {
          sm = new SystemMessage(SystemMessageId.S1S_PARTY_HAS_WON_THE_DUEL);
        }
        else
        {
          sm = new SystemMessage(SystemMessageId.S1_HAS_WON_THE_DUEL);
        }
        sm.addString(_playerB.getName());

        broadcastToTeam1(sm);
        broadcastToTeam2(sm);
        break;
      case Canceled:
        stopFighting();

        // dont restore hp, mp, cp
        restorePlayerConditions(true);

        //TODO: is there no other message for a canceled duel?
        // send SystemMessage
        sm = new SystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);

        broadcastToTeam1(sm);
        broadcastToTeam2(sm);
        break;
      case Timeout:
        stopFighting();
        // hp,mp,cp seem to be restored in a timeout too...
        restorePlayerConditions(false);
        // send SystemMessage
        sm = new SystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);

        broadcastToTeam1(sm);
        broadcastToTeam2(sm);
        break;
    }

    // Send end duel packet
    ExDuelEnd duelEnd = null;
    if(_partyDuel)
    {
      duelEnd = new ExDuelEnd(1);
    }
    else
    {
      duelEnd = new ExDuelEnd(0);
    }

    broadcastToTeam1(duelEnd);
    broadcastToTeam2(duelEnd);

    //clean up
    _playerConditions.clear();
    _playerConditions = null;
    DuelManager.getInstance().removeDuel(this);

    sm = null;
    duelEnd = null;
  }

  /**
   * Did a situation occur in which the duel has to be ended?.
   *
   * @return DuelResultEnum duel status
   */
  public DuelResultEnum checkEndDuelCondition()
  {
    // one of the players might leave during duel
    if(_playerA == null || _playerB == null)
      return DuelResultEnum.Canceled;

    // got a duel surrender request?
    if(_surrenderRequest != 0)
    {
      if(_surrenderRequest == 1)
        return DuelResultEnum.Team1Surrender;
      return DuelResultEnum.Team2Surrender;
    }
    // duel timed out
    else if(getRemainingTime() <= 0)
      return DuelResultEnum.Timeout;
    else if(_playerA.getDuelState() == DUELSTATE_WINNER)
    {
      // If there is a Winner already there should be no more fighting going on
      stopFighting();
      return DuelResultEnum.Team1Win;
    }
    else if(_playerB.getDuelState() == DUELSTATE_WINNER)
    {
      // If there is a Winner already there should be no more fighting going on
      stopFighting();
      return DuelResultEnum.Team2Win;
    }

    // More end duel conditions for 1on1 duels
    else if(!_partyDuel)
    {
      // Duel was interrupted e.g.: player was attacked by mobs / other players
      if(_playerA.getDuelState() == DUELSTATE_INTERRUPTED || _playerB.getDuelState() == DUELSTATE_INTERRUPTED)
        return DuelResultEnum.Canceled;

      // Are the players too far apart?
      if(!_playerA.isInsideRadius(_playerB, 1600, false, false))
        return DuelResultEnum.Canceled;

      // Did one of the players engage in PvP combat?
      if(isDuelistInPvp(true))
        return DuelResultEnum.Canceled;

      // is one of the players in a Siege, Peace or PvP zone?
      if(_playerA.isInsideZone(L2Character.ZONE_PEACE) || _playerB.isInsideZone(L2Character.ZONE_PEACE) || _playerA.isInsideZone(L2Character.ZONE_SIEGE) || _playerB.isInsideZone(L2Character.ZONE_SIEGE) || _playerA.isInsideZone(L2Character.ZONE_PVP) || _playerB.isInsideZone(L2Character.ZONE_PVP))
        return DuelResultEnum.Canceled;
    }

    return DuelResultEnum.Continue;
  }

  /**
   * Register a surrender request.
   *
   * @param player the player
   */
  public void doSurrender(L2PcInstance player)
  {
    // already recived a surrender request
    if(_surrenderRequest != 0)
      return;

    // stop the fight
    stopFighting();

    // TODO: Can every party member cancel a party duel? or only the party leaders?
    if(_partyDuel)
    {
      if(_playerA.getParty().getPartyMembers().contains(player))
      {
        _surrenderRequest = 1;

        for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
        {
          temp.setDuelState(DUELSTATE_DEAD);
        }

        for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
        {
          temp.setDuelState(DUELSTATE_WINNER);
        }
      }
      else if(_playerB.getParty().getPartyMembers().contains(player))
      {
        _surrenderRequest = 2;

        for(L2PcInstance temp : _playerB.getParty().getPartyMembers())
        {
          temp.setDuelState(DUELSTATE_DEAD);
        }

        for(L2PcInstance temp : _playerA.getParty().getPartyMembers())
        {
          temp.setDuelState(DUELSTATE_WINNER);
        }

      }
    }
    else
    {
      if(player == _playerA)
      {
        _surrenderRequest = 1;
        _playerA.setDuelState(DUELSTATE_DEAD);
        _playerB.setDuelState(DUELSTATE_WINNER);
      }
      else if(player == _playerB)
      {
        _surrenderRequest = 2;
        _playerB.setDuelState(DUELSTATE_DEAD);
        _playerA.setDuelState(DUELSTATE_WINNER);
      }
    }
  }

  /**
   * This function is called whenever a player was defeated in a duel.
   *
   * @param player the player
   */
  public void onPlayerDefeat(L2PcInstance player)
  {
    // Set player as defeated
    player.setDuelState(DUELSTATE_DEAD);

    if(_partyDuel)
    {
      boolean teamdefeated = true;

      for(L2PcInstance temp : player.getParty().getPartyMembers())
      {
        if(temp.getDuelState() == DUELSTATE_DUELLING)
        {
          teamdefeated = false;
          break;
        }
      }

      if(teamdefeated)
      {
        L2PcInstance winner = _playerA;

        if(_playerA.getParty().getPartyMembers().contains(player))
        {
          winner = _playerB;
        }

        for(L2PcInstance temp : winner.getParty().getPartyMembers())
        {
          temp.setDuelState(DUELSTATE_WINNER);
        }

        winner = null;
      }
    }
    else
    {
      if(player != _playerA && player != _playerB)
      {
        _log.warning("Error in onPlayerDefeat(): player is not part of this 1vs1 duel");
      }

      if(_playerA == player)
      {
        _playerB.setDuelState(DUELSTATE_WINNER);
      }
      else
      {
        _playerA.setDuelState(DUELSTATE_WINNER);
      }
    }
  }

  /**
   * This function is called whenever a player leaves a party.
   *
   * @param player the player
   */
  public void onRemoveFromParty(L2PcInstance player)
  {
    // if it isnt a party duel ignore this
    if(!_partyDuel)
      return;

    // this player is leaving his party during party duel
    // if hes either playerA or playerB cancel the duel and port the players back
    if(player == _playerA || player == _playerB)
    {
      for(FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
      {
        e.getValue().teleportBack();
        e.getValue().getPlayer().setIsInDuel(0);
      }

      _playerA = null;
      _playerB = null;
    }
    else
    // teleport the player back & delete his PlayerCondition record
    {
      for(FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
      {
        if(e.getValue().getPlayer() == player)
        {
          e.getValue().teleportBack();
          _playerConditions.remove(e.getValue());
          break;
        }
      }
      player.setIsInDuel(0);
    }
  }

  /**
   * On buff.
   *
   * @param player the player
   * @param debuff the debuff
   */
  public void onBuff(L2PcInstance player, L2Effect debuff)
  {
    for(FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
    {
      if(e.getValue().getPlayer() == player)
      {
        e.getValue().registerDebuff(debuff);
        return;
      }
    }
  }
}
TOP

Related Classes of com.l2jfrozen.gameserver.model.entity.Duel

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.