1063 lines
25 KiB
Java
1063 lines
25 KiB
Java
/*
|
|
* Copyright (C) 2004-2014 L2J Server
|
|
*
|
|
* This file is part of L2J Server.
|
|
*
|
|
* L2J Server 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* L2J Server 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.l2jserver.gameserver.model.entity;
|
|
|
|
import java.util.Calendar;
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javolution.util.FastList;
|
|
|
|
import com.l2jserver.gameserver.ThreadPoolManager;
|
|
import com.l2jserver.gameserver.ai.CtrlIntention;
|
|
import com.l2jserver.gameserver.enums.DuelResult;
|
|
import com.l2jserver.gameserver.enums.Team;
|
|
import com.l2jserver.gameserver.instancemanager.DuelManager;
|
|
import com.l2jserver.gameserver.model.Location;
|
|
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
|
|
import com.l2jserver.gameserver.model.skills.Skill;
|
|
import com.l2jserver.gameserver.model.zone.ZoneId;
|
|
import com.l2jserver.gameserver.network.SystemMessageId;
|
|
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
|
|
import com.l2jserver.gameserver.network.serverpackets.ExDuelEnd;
|
|
import com.l2jserver.gameserver.network.serverpackets.ExDuelReady;
|
|
import com.l2jserver.gameserver.network.serverpackets.ExDuelStart;
|
|
import com.l2jserver.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
|
|
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
|
|
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
|
|
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
|
|
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
|
|
|
|
public class Duel
|
|
{
|
|
protected static final Logger _log = Logger.getLogger(Duel.class.getName());
|
|
|
|
public static final int DUELSTATE_NODUEL = 0;
|
|
public static final int DUELSTATE_DUELLING = 1;
|
|
public static final int DUELSTATE_DEAD = 2;
|
|
public static final int DUELSTATE_WINNER = 3;
|
|
public static final int DUELSTATE_INTERRUPTED = 4;
|
|
|
|
private final int _duelId;
|
|
private L2PcInstance _playerA;
|
|
private L2PcInstance _playerB;
|
|
private final boolean _partyDuel;
|
|
private final Calendar _duelEndTime;
|
|
private int _surrenderRequest = 0;
|
|
private int _countdown = 4;
|
|
private boolean _finished = false;
|
|
|
|
private List<PlayerCondition> _playerConditions;
|
|
|
|
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<>();
|
|
|
|
setFinished(false);
|
|
|
|
if (_partyDuel)
|
|
{
|
|
// increase countdown so that start task can teleport players
|
|
_countdown++;
|
|
// inform players that they will be portet shortly
|
|
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.IN_A_MOMENT_YOU_WILL_BE_TRANSPORTED_TO_THE_SITE_WHERE_THE_DUEL_WILL_TAKE_PLACE);
|
|
broadcastToTeam1(sm);
|
|
broadcastToTeam2(sm);
|
|
}
|
|
// Schedule duel start
|
|
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartDuelTask(this), 3000);
|
|
}
|
|
|
|
public static class PlayerCondition
|
|
{
|
|
private L2PcInstance _player;
|
|
private double _hp;
|
|
private double _mp;
|
|
private double _cp;
|
|
private boolean _paDuel;
|
|
private int _x, _y, _z;
|
|
private FastList<Skill> _debuffs;
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
public void restoreCondition()
|
|
{
|
|
if (_player == null)
|
|
{
|
|
return;
|
|
}
|
|
_player.setCurrentHp(_hp);
|
|
_player.setCurrentMp(_mp);
|
|
_player.setCurrentCp(_cp);
|
|
|
|
if (_paDuel)
|
|
{
|
|
teleportBack();
|
|
}
|
|
if (_debuffs != null) // Debuff removal
|
|
{
|
|
for (Skill skill : _debuffs)
|
|
{
|
|
if (skill != null)
|
|
{
|
|
_player.stopSkillEffects(true, skill.getId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void registerDebuff(Skill debuff)
|
|
{
|
|
if (_debuffs == null)
|
|
{
|
|
_debuffs = new FastList<>();
|
|
}
|
|
|
|
_debuffs.add(debuff);
|
|
}
|
|
|
|
public void teleportBack()
|
|
{
|
|
if (_paDuel)
|
|
{
|
|
_player.teleToLocation(new Location(_x, _y, _z));
|
|
}
|
|
}
|
|
|
|
public L2PcInstance getPlayer()
|
|
{
|
|
return _player;
|
|
}
|
|
}
|
|
|
|
public class ScheduleDuelTask implements Runnable
|
|
{
|
|
private final Duel _duel;
|
|
|
|
public ScheduleDuelTask(Duel duel)
|
|
{
|
|
_duel = duel;
|
|
}
|
|
|
|
@Override
|
|
public void run()
|
|
{
|
|
try
|
|
{
|
|
DuelResult status = _duel.checkEndDuelCondition();
|
|
|
|
if (status == DuelResult.Canceled)
|
|
{
|
|
// do not schedule duel end if it was interrupted
|
|
setFinished(true);
|
|
_duel.endDuel(status);
|
|
}
|
|
else if (status != DuelResult.Continue)
|
|
{
|
|
setFinished(true);
|
|
playKneelAnimation();
|
|
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEndDuelTask(_duel, status), 5000);
|
|
}
|
|
else
|
|
{
|
|
ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.SEVERE, "", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class ScheduleStartDuelTask implements Runnable
|
|
{
|
|
private final Duel _duel;
|
|
|
|
public ScheduleStartDuelTask(Duel duel)
|
|
{
|
|
_duel = duel;
|
|
}
|
|
|
|
@Override
|
|
public void run()
|
|
{
|
|
try
|
|
{
|
|
// start/continue countdown
|
|
int count = _duel.countdown();
|
|
|
|
if (count == 4)
|
|
{
|
|
// players need to be teleportet first
|
|
// TODO: stadia manager needs a function to return an unused stadium for duels
|
|
// currently only teleports to the same stadium
|
|
_duel.teleportPlayers(-83760, -238825, -3331);
|
|
|
|
// 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 (Exception e)
|
|
{
|
|
_log.log(Level.SEVERE, "", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class ScheduleEndDuelTask implements Runnable
|
|
{
|
|
private final Duel _duel;
|
|
private final DuelResult _result;
|
|
|
|
public ScheduleEndDuelTask(Duel duel, DuelResult result)
|
|
{
|
|
_duel = duel;
|
|
_result = result;
|
|
}
|
|
|
|
@Override
|
|
public void run()
|
|
{
|
|
try
|
|
{
|
|
_duel.endDuel(_result);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_log.log(Level.SEVERE, "", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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().getMembers())
|
|
{
|
|
temp.abortCast();
|
|
temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
|
|
temp.setTarget(null);
|
|
temp.sendPacket(af);
|
|
}
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a player engaged in pvp combat (only for 1on1 duels)
|
|
* @param sendMessage
|
|
* @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())
|
|
{
|
|
// 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().getMembers())
|
|
{
|
|
temp.cancelActiveTrade();
|
|
temp.setIsInDuel(_duelId);
|
|
temp.setTeam(Team.BLUE);
|
|
temp.broadcastUserInfo();
|
|
broadcastToTeam2(new ExDuelUpdateUserInfo(temp));
|
|
}
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
temp.cancelActiveTrade();
|
|
temp.setIsInDuel(_duelId);
|
|
temp.setTeam(Team.RED);
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
// set isInDuel() state
|
|
_playerA.setIsInDuel(_duelId);
|
|
_playerA.setTeam(Team.BLUE);
|
|
_playerB.setIsInDuel(_duelId);
|
|
_playerB.setTeam(Team.RED);
|
|
|
|
// 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.broadcastUserInfo();
|
|
_playerB.broadcastUserInfo();
|
|
}
|
|
|
|
// play sound
|
|
PlaySound ps = new PlaySound(1, "B04_S01", 0, 0, 0, 0, 0);
|
|
broadcastToTeam1(ps);
|
|
broadcastToTeam2(ps);
|
|
|
|
// 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().getMembers())
|
|
{
|
|
_playerConditions.add(new PlayerCondition(temp, _partyDuel));
|
|
}
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
_playerConditions.add(new PlayerCondition(temp, _partyDuel));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_playerConditions.add(new PlayerCondition(_playerA, _partyDuel));
|
|
_playerConditions.add(new PlayerCondition(_playerB, _partyDuel));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restore player conditions
|
|
* @param abnormalDuelEnd true if the duel was the duel canceled
|
|
*/
|
|
public void restorePlayerConditions(boolean abnormalDuelEnd)
|
|
{
|
|
// update isInDuel() state for all players
|
|
if (_partyDuel)
|
|
{
|
|
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
|
{
|
|
temp.setIsInDuel(0);
|
|
temp.setTeam(Team.NONE);
|
|
temp.broadcastUserInfo();
|
|
}
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
temp.setIsInDuel(0);
|
|
temp.setTeam(Team.NONE);
|
|
temp.broadcastUserInfo();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_playerA.setIsInDuel(0);
|
|
_playerA.setTeam(Team.NONE);
|
|
_playerA.broadcastUserInfo();
|
|
_playerB.setIsInDuel(0);
|
|
_playerB.setTeam(Team.NONE);
|
|
_playerB.broadcastUserInfo();
|
|
}
|
|
|
|
// if it is an abnormal DuelEnd do not restore hp, mp, cp
|
|
if (abnormalDuelEnd)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// restore player conditions
|
|
for (PlayerCondition cond : _playerConditions)
|
|
{
|
|
cond.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 requested 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;
|
|
}
|
|
|
|
public void setFinished(boolean mode)
|
|
{
|
|
_finished = mode;
|
|
}
|
|
|
|
public boolean getFinished()
|
|
{
|
|
return _finished;
|
|
}
|
|
|
|
/**
|
|
* teleport all players to the given coordinates
|
|
* @param x
|
|
* @param y
|
|
* @param 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().getMembers())
|
|
{
|
|
temp.teleToLocation(new Location((x + offset) - 180, y - 150, z));
|
|
offset += 40;
|
|
}
|
|
offset = 0;
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
temp.teleToLocation(new Location((x + offset) - 180, y + 150, z));
|
|
offset += 40;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Broadcast a packet to the challenger team
|
|
* @param packet
|
|
*/
|
|
public void broadcastToTeam1(L2GameServerPacket packet)
|
|
{
|
|
if (_playerA == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_partyDuel && (_playerA.getParty() != null))
|
|
{
|
|
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
|
{
|
|
temp.sendPacket(packet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_playerA.sendPacket(packet);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Broadcast a packet to the challenged team
|
|
* @param packet
|
|
*/
|
|
public void broadcastToTeam2(L2GameServerPacket packet)
|
|
{
|
|
if (_playerB == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_partyDuel && (_playerB.getParty() != null))
|
|
{
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
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().getMembers())
|
|
{
|
|
temp.broadcastPacket(new SocialAction(temp.getObjectId(), 7));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
looser.broadcastPacket(new SocialAction(looser.getObjectId(), 7));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 = SystemMessage.getSystemMessage(SystemMessageId.THE_DUEL_WILL_BEGIN_IN_S1_SECOND_S);
|
|
sm.addInt(_countdown);
|
|
}
|
|
else
|
|
{
|
|
sm = SystemMessage.getSystemMessage(SystemMessageId.LET_THE_DUEL_BEGIN);
|
|
}
|
|
|
|
broadcastToTeam1(sm);
|
|
broadcastToTeam2(sm);
|
|
|
|
return _countdown;
|
|
}
|
|
|
|
/**
|
|
* The duel has reached a state in which it can no longer continue
|
|
* @param result the duel result.
|
|
*/
|
|
public void endDuel(DuelResult 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 Team1Win:
|
|
case Team2Surrender:
|
|
restorePlayerConditions(false);
|
|
// send SystemMessage
|
|
if (_partyDuel)
|
|
{
|
|
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_S_PARTY_HAS_WON_THE_DUEL);
|
|
}
|
|
else
|
|
{
|
|
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_DUEL);
|
|
}
|
|
sm.addString(_playerA.getName());
|
|
|
|
broadcastToTeam1(sm);
|
|
broadcastToTeam2(sm);
|
|
break;
|
|
case Team1Surrender:
|
|
case Team2Win:
|
|
restorePlayerConditions(false);
|
|
// send SystemMessage
|
|
if (_partyDuel)
|
|
{
|
|
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_S_PARTY_HAS_WON_THE_DUEL);
|
|
}
|
|
else
|
|
{
|
|
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_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 = SystemMessage.getSystemMessage(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 = SystemMessage.getSystemMessage(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);
|
|
}
|
|
|
|
/**
|
|
* Did a situation occur in which the duel has to be ended?
|
|
* @return DuelResult duel status
|
|
*/
|
|
public DuelResult checkEndDuelCondition()
|
|
{
|
|
// one of the players might leave during duel
|
|
if ((_playerA == null) || (_playerB == null))
|
|
{
|
|
return DuelResult.Canceled;
|
|
}
|
|
|
|
// got a duel surrender request?
|
|
if (_surrenderRequest != 0)
|
|
{
|
|
if (_surrenderRequest == 1)
|
|
{
|
|
return DuelResult.Team1Surrender;
|
|
}
|
|
return DuelResult.Team2Surrender;
|
|
}
|
|
// duel timed out
|
|
else if (getRemainingTime() <= 0)
|
|
{
|
|
return DuelResult.Timeout;
|
|
}
|
|
// Has a player been declared winner yet?
|
|
else if (_playerA.getDuelState() == DUELSTATE_WINNER)
|
|
{
|
|
// If there is a Winner already there should be no more fighting going on
|
|
stopFighting();
|
|
return DuelResult.Team1Win;
|
|
}
|
|
else if (_playerB.getDuelState() == DUELSTATE_WINNER)
|
|
{
|
|
// If there is a Winner already there should be no more fighting going on
|
|
stopFighting();
|
|
return DuelResult.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 DuelResult.Canceled;
|
|
}
|
|
|
|
// Are the players too far apart?
|
|
if (!_playerA.isInsideRadius(_playerB, 1600, false, false))
|
|
{
|
|
return DuelResult.Canceled;
|
|
}
|
|
|
|
// Did one of the players engage in PvP combat?
|
|
if (isDuelistInPvp(true))
|
|
{
|
|
return DuelResult.Canceled;
|
|
}
|
|
|
|
// is one of the players in a Siege, Peace or PvP zone?
|
|
if (_playerA.isInsideZone(ZoneId.PEACE) || _playerB.isInsideZone(ZoneId.PEACE) || _playerA.isInsideZone(ZoneId.SIEGE) || _playerB.isInsideZone(ZoneId.SIEGE) || _playerA.isInsideZone(ZoneId.PVP) || _playerB.isInsideZone(ZoneId.PVP))
|
|
{
|
|
return DuelResult.Canceled;
|
|
}
|
|
}
|
|
|
|
return DuelResult.Continue;
|
|
}
|
|
|
|
/**
|
|
* Register a surrender request
|
|
* @param player the player that surrenders.
|
|
*/
|
|
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().getMembers().contains(player))
|
|
{
|
|
_surrenderRequest = 1;
|
|
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
|
{
|
|
temp.setDuelState(DUELSTATE_DEAD);
|
|
}
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
temp.setDuelState(DUELSTATE_WINNER);
|
|
}
|
|
}
|
|
else if (_playerB.getParty().getMembers().contains(player))
|
|
{
|
|
_surrenderRequest = 2;
|
|
for (L2PcInstance temp : _playerB.getParty().getMembers())
|
|
{
|
|
temp.setDuelState(DUELSTATE_DEAD);
|
|
}
|
|
for (L2PcInstance temp : _playerA.getParty().getMembers())
|
|
{
|
|
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 defeated.
|
|
*/
|
|
public void onPlayerDefeat(L2PcInstance player)
|
|
{
|
|
// Set player as defeated
|
|
player.setDuelState(DUELSTATE_DEAD);
|
|
|
|
if (_partyDuel)
|
|
{
|
|
boolean teamdefeated = true;
|
|
for (L2PcInstance temp : player.getParty().getMembers())
|
|
{
|
|
if (temp.getDuelState() == DUELSTATE_DUELLING)
|
|
{
|
|
teamdefeated = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (teamdefeated)
|
|
{
|
|
L2PcInstance winner = _playerA;
|
|
if (_playerA.getParty().getMembers().contains(player))
|
|
{
|
|
winner = _playerB;
|
|
}
|
|
|
|
for (L2PcInstance temp : winner.getParty().getMembers())
|
|
{
|
|
temp.setDuelState(DUELSTATE_WINNER);
|
|
}
|
|
}
|
|
}
|
|
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 quitting.
|
|
*/
|
|
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 (PlayerCondition cond : _playerConditions)
|
|
{
|
|
cond.teleportBack();
|
|
cond.getPlayer().setIsInDuel(0);
|
|
}
|
|
|
|
_playerA = null;
|
|
_playerB = null;
|
|
}
|
|
else
|
|
// teleport the player back & delete his PlayerCondition record
|
|
{
|
|
for (PlayerCondition cond : _playerConditions)
|
|
{
|
|
if (cond.getPlayer() == player)
|
|
{
|
|
cond.teleportBack();
|
|
_playerConditions.remove(cond);
|
|
break;
|
|
}
|
|
}
|
|
player.setIsInDuel(0);
|
|
}
|
|
}
|
|
|
|
public void onBuff(L2PcInstance player, Skill debuff)
|
|
{
|
|
for (PlayerCondition cond : _playerConditions)
|
|
{
|
|
if (cond.getPlayer() == player)
|
|
{
|
|
cond.registerDebuff(debuff);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|