Duel.java 25 KB

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