Duel.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.model.entity;
  16. import java.util.Calendar;
  17. import java.util.logging.Level;
  18. import java.util.logging.Logger;
  19. import javolution.util.FastList;
  20. import com.l2jserver.gameserver.ThreadPoolManager;
  21. import com.l2jserver.gameserver.ai.CtrlIntention;
  22. import com.l2jserver.gameserver.instancemanager.DuelManager;
  23. import com.l2jserver.gameserver.model.actor.L2Character;
  24. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  25. import com.l2jserver.gameserver.model.effects.L2Effect;
  26. import com.l2jserver.gameserver.network.SystemMessageId;
  27. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  28. import com.l2jserver.gameserver.network.serverpackets.ExDuelEnd;
  29. import com.l2jserver.gameserver.network.serverpackets.ExDuelReady;
  30. import com.l2jserver.gameserver.network.serverpackets.ExDuelStart;
  31. import com.l2jserver.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
  32. import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
  33. import com.l2jserver.gameserver.network.serverpackets.PlaySound;
  34. import com.l2jserver.gameserver.network.serverpackets.SocialAction;
  35. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  36. public class Duel
  37. {
  38. protected static final Logger _log = Logger.getLogger(Duel.class.getName());
  39. public static final int DUELSTATE_NODUEL = 0;
  40. public static final int DUELSTATE_DUELLING = 1;
  41. public static final int DUELSTATE_DEAD = 2;
  42. public static final int DUELSTATE_WINNER = 3;
  43. public static final int DUELSTATE_INTERRUPTED = 4;
  44. private int _duelId;
  45. private L2PcInstance _playerA;
  46. private L2PcInstance _playerB;
  47. private boolean _partyDuel;
  48. private Calendar _duelEndTime;
  49. private int _surrenderRequest = 0;
  50. private int _countdown = 4;
  51. private boolean _finished = false;
  52. private FastList<PlayerCondition> _playerConditions;
  53. public static enum DuelResultEnum
  54. {
  55. Continue,
  56. Team1Win,
  57. Team2Win,
  58. Team1Surrender,
  59. Team2Surrender,
  60. Canceled,
  61. Timeout
  62. }
  63. public Duel(L2PcInstance playerA, L2PcInstance playerB, int partyDuel, int duelId)
  64. {
  65. _duelId = duelId;
  66. _playerA = playerA;
  67. _playerB = playerB;
  68. _partyDuel = partyDuel == 1 ? true : false;
  69. _duelEndTime = Calendar.getInstance();
  70. if (_partyDuel)
  71. _duelEndTime.add(Calendar.SECOND, 300);
  72. else
  73. _duelEndTime.add(Calendar.SECOND, 120);
  74. _playerConditions = new FastList<PlayerCondition>();
  75. setFinished(false);
  76. if (_partyDuel)
  77. {
  78. // increase countdown so that start task can teleport players
  79. _countdown++;
  80. // inform players that they will be portet shortly
  81. SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.IN_A_MOMENT_YOU_WILL_BE_TRANSPORTED_TO_THE_SITE_WHERE_THE_DUEL_WILL_TAKE_PLACE);
  82. broadcastToTeam1(sm);
  83. broadcastToTeam2(sm);
  84. }
  85. // Schedule duel start
  86. ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleStartDuelTask(this), 3000);
  87. }
  88. public static class PlayerCondition
  89. {
  90. private L2PcInstance _player;
  91. private double _hp;
  92. private double _mp;
  93. private double _cp;
  94. private boolean _paDuel;
  95. private int _x, _y, _z;
  96. private FastList<L2Effect> _debuffs;
  97. public PlayerCondition(L2PcInstance player, boolean partyDuel)
  98. {
  99. if (player == null)
  100. return;
  101. _player = player;
  102. _hp = _player.getCurrentHp();
  103. _mp = _player.getCurrentMp();
  104. _cp = _player.getCurrentCp();
  105. _paDuel = partyDuel;
  106. if (_paDuel)
  107. {
  108. _x = _player.getX();
  109. _y = _player.getY();
  110. _z = _player.getZ();
  111. }
  112. }
  113. public void restoreCondition()
  114. {
  115. if (_player == null)
  116. return;
  117. _player.setCurrentHp(_hp);
  118. _player.setCurrentMp(_mp);
  119. _player.setCurrentCp(_cp);
  120. if (_paDuel)
  121. {
  122. teleportBack();
  123. }
  124. if (_debuffs != null) // Debuff removal
  125. {
  126. for (L2Effect temp : _debuffs)
  127. if (temp != null)
  128. temp.exit();
  129. }
  130. }
  131. public void registerDebuff(L2Effect debuff)
  132. {
  133. if (_debuffs == null)
  134. _debuffs = new FastList<L2Effect>();
  135. _debuffs.add(debuff);
  136. }
  137. public void teleportBack()
  138. {
  139. if (_paDuel)
  140. _player.teleToLocation(_x, _y, _z);
  141. }
  142. public L2PcInstance getPlayer()
  143. {
  144. return _player;
  145. }
  146. }
  147. public class ScheduleDuelTask implements Runnable
  148. {
  149. private Duel _duel;
  150. public ScheduleDuelTask(Duel duel)
  151. {
  152. _duel = duel;
  153. }
  154. @Override
  155. public void run()
  156. {
  157. try
  158. {
  159. DuelResultEnum status = _duel.checkEndDuelCondition();
  160. if (status == DuelResultEnum.Canceled)
  161. {
  162. // do not schedule duel end if it was interrupted
  163. setFinished(true);
  164. _duel.endDuel(status);
  165. }
  166. else if (status != DuelResultEnum.Continue)
  167. {
  168. setFinished(true);
  169. playKneelAnimation();
  170. ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEndDuelTask(_duel, status), 5000);
  171. }
  172. else
  173. ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
  174. }
  175. catch (Exception e)
  176. {
  177. _log.log(Level.SEVERE, "", e);
  178. }
  179. }
  180. }
  181. public static class ScheduleStartDuelTask implements Runnable
  182. {
  183. private Duel _duel;
  184. public ScheduleStartDuelTask(Duel duel)
  185. {
  186. _duel = duel;
  187. }
  188. @Override
  189. public void run()
  190. {
  191. try
  192. {
  193. // start/continue countdown
  194. int count = _duel.countdown();
  195. if (count == 4)
  196. {
  197. // players need to be teleportet first
  198. //TODO: stadia manager needs a function to return an unused stadium for duels
  199. // currently only teleports to the same stadium
  200. _duel.teleportPlayers(-83760, -238825, -3331);
  201. // give players 20 seconds to complete teleport and get ready (its ought to be 30 on offical..)
  202. ThreadPoolManager.getInstance().scheduleGeneral(this, 20000);
  203. }
  204. else if (count > 0) // duel not started yet - continue countdown
  205. {
  206. ThreadPoolManager.getInstance().scheduleGeneral(this, 1000);
  207. }
  208. else
  209. _duel.startDuel();
  210. }
  211. catch (Exception e)
  212. {
  213. _log.log(Level.SEVERE, "", e);
  214. }
  215. }
  216. }
  217. public static class ScheduleEndDuelTask implements Runnable
  218. {
  219. private Duel _duel;
  220. private DuelResultEnum _result;
  221. public ScheduleEndDuelTask(Duel duel, DuelResultEnum result)
  222. {
  223. _duel = duel;
  224. _result = result;
  225. }
  226. @Override
  227. public void run()
  228. {
  229. try
  230. {
  231. _duel.endDuel(_result);
  232. }
  233. catch (Exception e)
  234. {
  235. _log.log(Level.SEVERE, "", e);
  236. }
  237. }
  238. }
  239. /**
  240. * Stops all players from attacking.
  241. * Used for duel timeout / interrupt.
  242. *
  243. */
  244. private void stopFighting()
  245. {
  246. ActionFailed af = ActionFailed.STATIC_PACKET;
  247. if (_partyDuel)
  248. {
  249. for (L2PcInstance temp : _playerA.getParty().getMembers())
  250. {
  251. temp.abortCast();
  252. temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  253. temp.setTarget(null);
  254. temp.sendPacket(af);
  255. }
  256. for (L2PcInstance temp : _playerB.getParty().getMembers())
  257. {
  258. temp.abortCast();
  259. temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  260. temp.setTarget(null);
  261. temp.sendPacket(af);
  262. }
  263. }
  264. else
  265. {
  266. _playerA.abortCast();
  267. _playerB.abortCast();
  268. _playerA.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  269. _playerA.setTarget(null);
  270. _playerB.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  271. _playerB.setTarget(null);
  272. _playerA.sendPacket(af);
  273. _playerB.sendPacket(af);
  274. }
  275. }
  276. /**
  277. * Check if a player engaged in pvp combat (only for 1on1 duels)
  278. * @param sendMessage
  279. * @return returns true if a duelist is engaged in Pvp combat
  280. */
  281. public boolean isDuelistInPvp(boolean sendMessage)
  282. {
  283. if (_partyDuel)
  284. {
  285. // Party duels take place in arenas - should be no other players there
  286. return false;
  287. }
  288. else if (_playerA.getPvpFlag() != 0 || _playerB.getPvpFlag() != 0)
  289. {
  290. if (sendMessage)
  291. {
  292. String engagedInPvP = "The duel was canceled because a duelist engaged in PvP combat.";
  293. _playerA.sendMessage(engagedInPvP);
  294. _playerB.sendMessage(engagedInPvP);
  295. }
  296. return true;
  297. }
  298. return false;
  299. }
  300. /**
  301. * Starts the duel
  302. *
  303. */
  304. public void startDuel()
  305. {
  306. // Save player Conditions
  307. savePlayerConditions();
  308. if (_playerA == null || _playerB == null || _playerA.isInDuel() || _playerB.isInDuel())
  309. {
  310. // clean up
  311. _playerConditions.clear();
  312. _playerConditions = null;
  313. DuelManager.getInstance().removeDuel(this);
  314. return;
  315. }
  316. if (_partyDuel)
  317. {
  318. // set isInDuel() state
  319. // cancel all active trades, just in case? xD
  320. for (L2PcInstance temp : _playerA.getParty().getMembers())
  321. {
  322. temp.cancelActiveTrade();
  323. temp.setIsInDuel(_duelId);
  324. temp.setTeam(1);
  325. temp.broadcastUserInfo();
  326. broadcastToTeam2(new ExDuelUpdateUserInfo(temp));
  327. }
  328. for (L2PcInstance temp : _playerB.getParty().getMembers())
  329. {
  330. temp.cancelActiveTrade();
  331. temp.setIsInDuel(_duelId);
  332. temp.setTeam(2);
  333. temp.broadcastUserInfo();
  334. broadcastToTeam1(new ExDuelUpdateUserInfo(temp));
  335. }
  336. // Send duel Start packets
  337. ExDuelReady ready = new ExDuelReady(1);
  338. ExDuelStart start = new ExDuelStart(1);
  339. broadcastToTeam1(ready);
  340. broadcastToTeam2(ready);
  341. broadcastToTeam1(start);
  342. broadcastToTeam2(start);
  343. }
  344. else
  345. {
  346. // set isInDuel() state
  347. _playerA.setIsInDuel(_duelId);
  348. _playerA.setTeam(1);
  349. _playerB.setIsInDuel(_duelId);
  350. _playerB.setTeam(2);
  351. // Send duel Start packets
  352. ExDuelReady ready = new ExDuelReady(0);
  353. ExDuelStart start = new ExDuelStart(0);
  354. broadcastToTeam1(ready);
  355. broadcastToTeam2(ready);
  356. broadcastToTeam1(start);
  357. broadcastToTeam2(start);
  358. broadcastToTeam1(new ExDuelUpdateUserInfo(_playerB));
  359. broadcastToTeam2(new ExDuelUpdateUserInfo(_playerA));
  360. _playerA.broadcastUserInfo();
  361. _playerB.broadcastUserInfo();
  362. }
  363. // play sound
  364. PlaySound ps = new PlaySound(1, "B04_S01", 0, 0, 0, 0, 0);
  365. broadcastToTeam1(ps);
  366. broadcastToTeam2(ps);
  367. // start duelling task
  368. ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleDuelTask(this), 1000);
  369. }
  370. /**
  371. * Save the current player condition: hp, mp, cp, location
  372. *
  373. */
  374. public void savePlayerConditions()
  375. {
  376. if (_partyDuel)
  377. {
  378. for (L2PcInstance temp : _playerA.getParty().getMembers())
  379. {
  380. _playerConditions.add(new PlayerCondition(temp, _partyDuel));
  381. }
  382. for (L2PcInstance temp : _playerB.getParty().getMembers())
  383. {
  384. _playerConditions.add(new PlayerCondition(temp, _partyDuel));
  385. }
  386. }
  387. else
  388. {
  389. _playerConditions.add(new PlayerCondition(_playerA, _partyDuel));
  390. _playerConditions.add(new PlayerCondition(_playerB, _partyDuel));
  391. }
  392. }
  393. /**
  394. * Restore player conditions
  395. * @param abnormalDuelEnd true if the duel was the duel canceled
  396. */
  397. public void restorePlayerConditions(boolean abnormalDuelEnd)
  398. {
  399. // update isInDuel() state for all players
  400. if (_partyDuel)
  401. {
  402. for (L2PcInstance temp : _playerA.getParty().getMembers())
  403. {
  404. temp.setIsInDuel(0);
  405. temp.setTeam(0);
  406. temp.broadcastUserInfo();
  407. }
  408. for (L2PcInstance temp : _playerB.getParty().getMembers())
  409. {
  410. temp.setIsInDuel(0);
  411. temp.setTeam(0);
  412. temp.broadcastUserInfo();
  413. }
  414. }
  415. else
  416. {
  417. _playerA.setIsInDuel(0);
  418. _playerA.setTeam(0);
  419. _playerA.broadcastUserInfo();
  420. _playerB.setIsInDuel(0);
  421. _playerB.setTeam(0);
  422. _playerB.broadcastUserInfo();
  423. }
  424. // if it is an abnormal DuelEnd do not restore hp, mp, cp
  425. if (abnormalDuelEnd)
  426. return;
  427. // restore player conditions
  428. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  429. {
  430. e.getValue().restoreCondition();
  431. }
  432. }
  433. /**
  434. * Get the duel id
  435. * @return id
  436. */
  437. public int getId()
  438. {
  439. return _duelId;
  440. }
  441. /**
  442. * Returns the remaining time
  443. * @return remaining time
  444. */
  445. public int getRemainingTime()
  446. {
  447. return (int) (_duelEndTime.getTimeInMillis() - Calendar.getInstance().getTimeInMillis());
  448. }
  449. /**
  450. * Get the player that requested the duel
  451. * @return duel requester
  452. */
  453. public L2PcInstance getPlayerA()
  454. {
  455. return _playerA;
  456. }
  457. /**
  458. * Get the player that was challenged
  459. * @return challenged player
  460. */
  461. public L2PcInstance getPlayerB()
  462. {
  463. return _playerB;
  464. }
  465. /**
  466. * Returns whether this is a party duel or not
  467. * @return is party duel
  468. */
  469. public boolean isPartyDuel()
  470. {
  471. return _partyDuel;
  472. }
  473. public void setFinished(boolean mode)
  474. {
  475. _finished = mode;
  476. }
  477. public boolean getFinished()
  478. {
  479. return _finished;
  480. }
  481. /**
  482. * teleport all players to the given coordinates
  483. * @param x
  484. * @param y
  485. * @param z
  486. */
  487. public void teleportPlayers(int x, int y, int z)
  488. {
  489. //TODO: adjust the values if needed... or implement something better (especially using more then 1 arena)
  490. if (!_partyDuel)
  491. return;
  492. int offset = 0;
  493. for (L2PcInstance temp : _playerA.getParty().getMembers())
  494. {
  495. temp.teleToLocation(x + offset - 180, y - 150, z);
  496. offset += 40;
  497. }
  498. offset = 0;
  499. for (L2PcInstance temp : _playerB.getParty().getMembers())
  500. {
  501. temp.teleToLocation(x + offset - 180, y + 150, z);
  502. offset += 40;
  503. }
  504. }
  505. /**
  506. * Broadcast a packet to the challenger team
  507. * @param packet
  508. */
  509. public void broadcastToTeam1(L2GameServerPacket packet)
  510. {
  511. if (_playerA == null)
  512. return;
  513. if (_partyDuel && _playerA.getParty() != null)
  514. {
  515. for (L2PcInstance temp : _playerA.getParty().getMembers())
  516. temp.sendPacket(packet);
  517. }
  518. else
  519. _playerA.sendPacket(packet);
  520. }
  521. /**
  522. * Broadcast a packet to the challenged team
  523. * @param packet
  524. */
  525. public void broadcastToTeam2(L2GameServerPacket packet)
  526. {
  527. if (_playerB == null)
  528. return;
  529. if (_partyDuel && _playerB.getParty() != null)
  530. {
  531. for (L2PcInstance temp : _playerB.getParty().getMembers())
  532. temp.sendPacket(packet);
  533. }
  534. else
  535. _playerB.sendPacket(packet);
  536. }
  537. /**
  538. * Get the duel winner
  539. * @return winner
  540. */
  541. public L2PcInstance getWinner()
  542. {
  543. if (!getFinished() || _playerA == null || _playerB == null)
  544. return null;
  545. if (_playerA.getDuelState() == DUELSTATE_WINNER)
  546. return _playerA;
  547. if (_playerB.getDuelState() == DUELSTATE_WINNER)
  548. return _playerB;
  549. return null;
  550. }
  551. /**
  552. * Get the duel looser
  553. * @return looser
  554. */
  555. public L2PcInstance getLooser()
  556. {
  557. if (!getFinished() || _playerA == null || _playerB == null)
  558. return null;
  559. if (_playerA.getDuelState() == DUELSTATE_WINNER)
  560. return _playerB;
  561. else if (_playerB.getDuelState() == DUELSTATE_WINNER)
  562. return _playerA;
  563. return null;
  564. }
  565. /**
  566. * Playback the bow animation for all loosers
  567. *
  568. */
  569. public void playKneelAnimation()
  570. {
  571. L2PcInstance looser = getLooser();
  572. if (looser == null)
  573. return;
  574. if (_partyDuel && looser.getParty() != null)
  575. {
  576. for (L2PcInstance temp : looser.getParty().getMembers())
  577. temp.broadcastPacket(new SocialAction(temp.getObjectId(), 7));
  578. }
  579. else
  580. looser.broadcastPacket(new SocialAction(looser.getObjectId(), 7));
  581. }
  582. /**
  583. * Do the countdown and send message to players if necessary
  584. * @return current count
  585. */
  586. public int countdown()
  587. {
  588. _countdown--;
  589. if (_countdown > 3)
  590. return _countdown;
  591. // Broadcast countdown to duelists
  592. SystemMessage sm = null;
  593. if (_countdown > 0)
  594. {
  595. sm = SystemMessage.getSystemMessage(SystemMessageId.THE_DUEL_WILL_BEGIN_IN_S1_SECONDS);
  596. sm.addNumber(_countdown);
  597. }
  598. else
  599. sm = SystemMessage.getSystemMessage(SystemMessageId.LET_THE_DUEL_BEGIN);
  600. broadcastToTeam1(sm);
  601. broadcastToTeam2(sm);
  602. return _countdown;
  603. }
  604. /**
  605. * The duel has reached a state in which it can no longer continue
  606. * @param result the duel result.
  607. */
  608. public void endDuel(DuelResultEnum result)
  609. {
  610. if (_playerA == null || _playerB == null)
  611. {
  612. //clean up
  613. _playerConditions.clear();
  614. _playerConditions = null;
  615. DuelManager.getInstance().removeDuel(this);
  616. return;
  617. }
  618. // inform players of the result
  619. SystemMessage sm = null;
  620. switch (result)
  621. {
  622. case Team1Win:
  623. case Team2Surrender:
  624. restorePlayerConditions(false);
  625. // send SystemMessage
  626. if (_partyDuel)
  627. sm = SystemMessage.getSystemMessage(SystemMessageId.C1_PARTY_HAS_WON_THE_DUEL);
  628. else
  629. sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_DUEL);
  630. sm.addString(_playerA.getName());
  631. broadcastToTeam1(sm);
  632. broadcastToTeam2(sm);
  633. break;
  634. case Team1Surrender:
  635. case Team2Win:
  636. restorePlayerConditions(false);
  637. // send SystemMessage
  638. if (_partyDuel)
  639. sm = SystemMessage.getSystemMessage(SystemMessageId.C1_PARTY_HAS_WON_THE_DUEL);
  640. else
  641. sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_WON_THE_DUEL);
  642. sm.addString(_playerB.getName());
  643. broadcastToTeam1(sm);
  644. broadcastToTeam2(sm);
  645. break;
  646. case Canceled:
  647. stopFighting();
  648. // dont restore hp, mp, cp
  649. restorePlayerConditions(true);
  650. //TODO: is there no other message for a canceled duel?
  651. // send SystemMessage
  652. sm = SystemMessage.getSystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);
  653. broadcastToTeam1(sm);
  654. broadcastToTeam2(sm);
  655. break;
  656. case Timeout:
  657. stopFighting();
  658. // hp,mp,cp seem to be restored in a timeout too...
  659. restorePlayerConditions(false);
  660. // send SystemMessage
  661. sm = SystemMessage.getSystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);
  662. broadcastToTeam1(sm);
  663. broadcastToTeam2(sm);
  664. break;
  665. }
  666. // Send end duel packet
  667. ExDuelEnd duelEnd = null;
  668. if (_partyDuel)
  669. duelEnd = new ExDuelEnd(1);
  670. else
  671. duelEnd = new ExDuelEnd(0);
  672. broadcastToTeam1(duelEnd);
  673. broadcastToTeam2(duelEnd);
  674. //clean up
  675. _playerConditions.clear();
  676. _playerConditions = null;
  677. DuelManager.getInstance().removeDuel(this);
  678. }
  679. /**
  680. * Did a situation occur in which the duel has to be ended?
  681. * @return DuelResultEnum duel status
  682. */
  683. public DuelResultEnum checkEndDuelCondition()
  684. {
  685. // one of the players might leave during duel
  686. if (_playerA == null || _playerB == null)
  687. return DuelResultEnum.Canceled;
  688. // got a duel surrender request?
  689. if (_surrenderRequest != 0)
  690. {
  691. if (_surrenderRequest == 1)
  692. return DuelResultEnum.Team1Surrender;
  693. return DuelResultEnum.Team2Surrender;
  694. }
  695. // duel timed out
  696. else if (getRemainingTime() <= 0)
  697. {
  698. return DuelResultEnum.Timeout;
  699. }
  700. // Has a player been declared winner yet?
  701. else if (_playerA.getDuelState() == DUELSTATE_WINNER)
  702. {
  703. // If there is a Winner already there should be no more fighting going on
  704. stopFighting();
  705. return DuelResultEnum.Team1Win;
  706. }
  707. else if (_playerB.getDuelState() == DUELSTATE_WINNER)
  708. {
  709. // If there is a Winner already there should be no more fighting going on
  710. stopFighting();
  711. return DuelResultEnum.Team2Win;
  712. }
  713. // More end duel conditions for 1on1 duels
  714. else if (!_partyDuel)
  715. {
  716. // Duel was interrupted e.g.: player was attacked by mobs / other players
  717. if (_playerA.getDuelState() == DUELSTATE_INTERRUPTED || _playerB.getDuelState() == DUELSTATE_INTERRUPTED)
  718. return DuelResultEnum.Canceled;
  719. // Are the players too far apart?
  720. if (!_playerA.isInsideRadius(_playerB, 1600, false, false))
  721. return DuelResultEnum.Canceled;
  722. // Did one of the players engage in PvP combat?
  723. if (isDuelistInPvp(true))
  724. return DuelResultEnum.Canceled;
  725. // is one of the players in a Siege, Peace or PvP zone?
  726. if (_playerA.isInsideZone(L2Character.ZONE_PEACE) || _playerB.isInsideZone(L2Character.ZONE_PEACE) || _playerA.isInsideZone(L2Character.ZONE_SIEGE) || _playerB.isInsideZone(L2Character.ZONE_SIEGE)
  727. || _playerA.isInsideZone(L2Character.ZONE_PVP) || _playerB.isInsideZone(L2Character.ZONE_PVP))
  728. return DuelResultEnum.Canceled;
  729. }
  730. return DuelResultEnum.Continue;
  731. }
  732. /**
  733. * Register a surrender request
  734. * @param player the player that surrenders.
  735. */
  736. public void doSurrender(L2PcInstance player)
  737. {
  738. // already recived a surrender request
  739. if (_surrenderRequest != 0)
  740. return;
  741. // stop the fight
  742. stopFighting();
  743. // TODO: Can every party member cancel a party duel? or only the party leaders?
  744. if (_partyDuel)
  745. {
  746. if (_playerA.getParty().getMembers().contains(player))
  747. {
  748. _surrenderRequest = 1;
  749. for (L2PcInstance temp : _playerA.getParty().getMembers())
  750. {
  751. temp.setDuelState(DUELSTATE_DEAD);
  752. }
  753. for (L2PcInstance temp : _playerB.getParty().getMembers())
  754. {
  755. temp.setDuelState(DUELSTATE_WINNER);
  756. }
  757. }
  758. else if (_playerB.getParty().getMembers().contains(player))
  759. {
  760. _surrenderRequest = 2;
  761. for (L2PcInstance temp : _playerB.getParty().getMembers())
  762. {
  763. temp.setDuelState(DUELSTATE_DEAD);
  764. }
  765. for (L2PcInstance temp : _playerA.getParty().getMembers())
  766. {
  767. temp.setDuelState(DUELSTATE_WINNER);
  768. }
  769. }
  770. }
  771. else
  772. {
  773. if (player == _playerA)
  774. {
  775. _surrenderRequest = 1;
  776. _playerA.setDuelState(DUELSTATE_DEAD);
  777. _playerB.setDuelState(DUELSTATE_WINNER);
  778. }
  779. else if (player == _playerB)
  780. {
  781. _surrenderRequest = 2;
  782. _playerB.setDuelState(DUELSTATE_DEAD);
  783. _playerA.setDuelState(DUELSTATE_WINNER);
  784. }
  785. }
  786. }
  787. /**
  788. * This function is called whenever a player was defeated in a duel
  789. * @param player the player defeated.
  790. */
  791. public void onPlayerDefeat(L2PcInstance player)
  792. {
  793. // Set player as defeated
  794. player.setDuelState(DUELSTATE_DEAD);
  795. if (_partyDuel)
  796. {
  797. boolean teamdefeated = true;
  798. for (L2PcInstance temp : player.getParty().getMembers())
  799. {
  800. if (temp.getDuelState() == DUELSTATE_DUELLING)
  801. {
  802. teamdefeated = false;
  803. break;
  804. }
  805. }
  806. if (teamdefeated)
  807. {
  808. L2PcInstance winner = _playerA;
  809. if (_playerA.getParty().getMembers().contains(player))
  810. winner = _playerB;
  811. for (L2PcInstance temp : winner.getParty().getMembers())
  812. {
  813. temp.setDuelState(DUELSTATE_WINNER);
  814. }
  815. }
  816. }
  817. else
  818. {
  819. if (player != _playerA && player != _playerB)
  820. _log.warning("Error in onPlayerDefeat(): player is not part of this 1vs1 duel");
  821. if (_playerA == player)
  822. _playerB.setDuelState(DUELSTATE_WINNER);
  823. else
  824. _playerA.setDuelState(DUELSTATE_WINNER);
  825. }
  826. }
  827. /**
  828. * This function is called whenever a player leaves a party
  829. * @param player the player quitting.
  830. */
  831. public void onRemoveFromParty(L2PcInstance player)
  832. {
  833. // if it isnt a party duel ignore this
  834. if (!_partyDuel)
  835. return;
  836. // this player is leaving his party during party duel
  837. // if hes either playerA or playerB cancel the duel and port the players back
  838. if (player == _playerA || player == _playerB)
  839. {
  840. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  841. {
  842. e.getValue().teleportBack();
  843. e.getValue().getPlayer().setIsInDuel(0);
  844. }
  845. _playerA = null;
  846. _playerB = null;
  847. }
  848. else
  849. // teleport the player back & delete his PlayerCondition record
  850. {
  851. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  852. {
  853. if (e.getValue().getPlayer() == player)
  854. {
  855. e.getValue().teleportBack();
  856. _playerConditions.remove(e.getValue());
  857. break;
  858. }
  859. }
  860. player.setIsInDuel(0);
  861. }
  862. }
  863. public void onBuff(L2PcInstance player, L2Effect debuff)
  864. {
  865. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  866. {
  867. if (e.getValue().getPlayer() == player)
  868. {
  869. e.getValue().registerDebuff(debuff);
  870. return;
  871. }
  872. }
  873. }
  874. }