2
0

Duel.java 25 KB

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