Duel.java 25 KB

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