Duel.java 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  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.Level;
  18. import java.util.logging.Logger;
  19. import javolution.util.FastList;
  20. import net.sf.l2j.gameserver.ThreadPoolManager;
  21. import net.sf.l2j.gameserver.ai.CtrlIntention;
  22. import net.sf.l2j.gameserver.instancemanager.DuelManager;
  23. import net.sf.l2j.gameserver.model.L2Effect;
  24. import net.sf.l2j.gameserver.model.actor.L2Character;
  25. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  26. import net.sf.l2j.gameserver.network.SystemMessageId;
  27. import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
  28. import net.sf.l2j.gameserver.network.serverpackets.ExDuelEnd;
  29. import net.sf.l2j.gameserver.network.serverpackets.ExDuelReady;
  30. import net.sf.l2j.gameserver.network.serverpackets.ExDuelStart;
  31. import net.sf.l2j.gameserver.network.serverpackets.ExDuelUpdateUserInfo;
  32. import net.sf.l2j.gameserver.network.serverpackets.L2GameServerPacket;
  33. import net.sf.l2j.gameserver.network.serverpackets.PlaySound;
  34. import net.sf.l2j.gameserver.network.serverpackets.SocialAction;
  35. import net.sf.l2j.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 = new SystemMessage(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 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 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(-102495, -209023, -3326);
  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 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 (_playerA.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.getObjectId(), 7));
  586. }
  587. else
  588. looser.broadcastPacket(new SocialAction(looser.getObjectId(), 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 = new SystemMessage(SystemMessageId.THE_DUEL_WILL_BEGIN_IN_S1_SECONDS);
  604. sm.addNumber(_countdown);
  605. }
  606. else
  607. sm = new SystemMessage(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. restorePlayerConditions(false);
  632. // send SystemMessage
  633. if (_partyDuel)
  634. sm = new SystemMessage(SystemMessageId.C1_PARTY_HAS_WON_THE_DUEL);
  635. else
  636. sm = new SystemMessage(SystemMessageId.C1_HAS_WON_THE_DUEL);
  637. sm.addString(_playerA.getName());
  638. broadcastToTeam1(sm);
  639. broadcastToTeam2(sm);
  640. break;
  641. case Team2Win:
  642. restorePlayerConditions(false);
  643. // send SystemMessage
  644. if (_partyDuel)
  645. sm = new SystemMessage(SystemMessageId.C1_PARTY_HAS_WON_THE_DUEL);
  646. else
  647. sm = new SystemMessage(SystemMessageId.C1_HAS_WON_THE_DUEL);
  648. sm.addString(_playerB.getName());
  649. broadcastToTeam1(sm);
  650. broadcastToTeam2(sm);
  651. break;
  652. case Team1Surrender:
  653. restorePlayerConditions(false);
  654. // send SystemMessage
  655. if (_partyDuel)
  656. sm = new SystemMessage(SystemMessageId.SINCE_C1_PARTY_WITHDREW_FROM_THE_DUEL_S2_PARTY_HAS_WON);
  657. else
  658. sm = new SystemMessage(SystemMessageId.SINCE_C1_WITHDREW_FROM_THE_DUEL_S2_HAS_WON);
  659. sm.addString(_playerA.getName());
  660. sm.addString(_playerB.getName());
  661. broadcastToTeam1(sm);
  662. broadcastToTeam2(sm);
  663. break;
  664. case Team2Surrender:
  665. restorePlayerConditions(false);
  666. // send SystemMessage
  667. if (_partyDuel)
  668. sm = new SystemMessage(SystemMessageId.SINCE_C1_PARTY_WITHDREW_FROM_THE_DUEL_S2_PARTY_HAS_WON);
  669. else
  670. sm = new SystemMessage(SystemMessageId.SINCE_C1_WITHDREW_FROM_THE_DUEL_S2_HAS_WON);
  671. sm.addString(_playerB.getName());
  672. sm.addString(_playerA.getName());
  673. broadcastToTeam1(sm);
  674. broadcastToTeam2(sm);
  675. break;
  676. case Canceled:
  677. stopFighting();
  678. // dont restore hp, mp, cp
  679. restorePlayerConditions(true);
  680. //TODO: is there no other message for a canceled duel?
  681. // send SystemMessage
  682. sm = new SystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);
  683. broadcastToTeam1(sm);
  684. broadcastToTeam2(sm);
  685. break;
  686. case Timeout:
  687. stopFighting();
  688. // hp,mp,cp seem to be restored in a timeout too...
  689. restorePlayerConditions(false);
  690. // send SystemMessage
  691. sm = new SystemMessage(SystemMessageId.THE_DUEL_HAS_ENDED_IN_A_TIE);
  692. broadcastToTeam1(sm);
  693. broadcastToTeam2(sm);
  694. break;
  695. }
  696. // Send end duel packet
  697. ExDuelEnd duelEnd = null;
  698. if (_partyDuel)
  699. duelEnd = new ExDuelEnd(1);
  700. else
  701. duelEnd = new ExDuelEnd(0);
  702. broadcastToTeam1(duelEnd);
  703. broadcastToTeam2(duelEnd);
  704. //clean up
  705. _playerConditions.clear();
  706. _playerConditions = null;
  707. DuelManager.getInstance().removeDuel(this);
  708. }
  709. /**
  710. * Did a situation occur in which the duel has to be ended?
  711. * @return DuelResultEnum duel status
  712. */
  713. public DuelResultEnum checkEndDuelCondition()
  714. {
  715. // one of the players might leave during duel
  716. if (_playerA == null || _playerB == null)
  717. return DuelResultEnum.Canceled;
  718. // got a duel surrender request?
  719. if (_surrenderRequest != 0)
  720. {
  721. if (_surrenderRequest == 1)
  722. return DuelResultEnum.Team1Surrender;
  723. else
  724. return DuelResultEnum.Team2Surrender;
  725. }
  726. // duel timed out
  727. else if (getRemainingTime() <= 0)
  728. {
  729. return DuelResultEnum.Timeout;
  730. }
  731. // Has a player been declared winner yet?
  732. else if (_playerA.getDuelState() == DUELSTATE_WINNER)
  733. {
  734. // If there is a Winner already there should be no more fighting going on
  735. stopFighting();
  736. return DuelResultEnum.Team1Win;
  737. }
  738. else if (_playerB.getDuelState() == DUELSTATE_WINNER)
  739. {
  740. // If there is a Winner already there should be no more fighting going on
  741. stopFighting();
  742. return DuelResultEnum.Team2Win;
  743. }
  744. // More end duel conditions for 1on1 duels
  745. else if (!_partyDuel)
  746. {
  747. // Duel was interrupted e.g.: player was attacked by mobs / other players
  748. if (_playerA.getDuelState() == DUELSTATE_INTERRUPTED || _playerB.getDuelState() == DUELSTATE_INTERRUPTED)
  749. return DuelResultEnum.Canceled;
  750. // Are the players too far apart?
  751. if (!_playerA.isInsideRadius(_playerB, 1600, false, false))
  752. return DuelResultEnum.Canceled;
  753. // Did one of the players engage in PvP combat?
  754. if (isDuelistInPvp(true))
  755. return DuelResultEnum.Canceled;
  756. // is one of the players in a Siege, Peace or PvP zone?
  757. if (_playerA.isInsideZone(L2Character.ZONE_PEACE) || _playerB.isInsideZone(L2Character.ZONE_PEACE) || _playerA.isInsideZone(L2Character.ZONE_SIEGE) || _playerB.isInsideZone(L2Character.ZONE_SIEGE)
  758. || _playerA.isInsideZone(L2Character.ZONE_PVP) || _playerB.isInsideZone(L2Character.ZONE_PVP))
  759. return DuelResultEnum.Canceled;
  760. }
  761. return DuelResultEnum.Continue;
  762. }
  763. /**
  764. * Register a surrender request
  765. * @param surrendering player
  766. */
  767. public void doSurrender(L2PcInstance player)
  768. {
  769. // already recived a surrender request
  770. if (_surrenderRequest != 0)
  771. return;
  772. // stop the fight
  773. stopFighting();
  774. // TODO: Can every party member cancel a party duel? or only the party leaders?
  775. if (_partyDuel)
  776. {
  777. if (_playerA.getParty().getPartyMembers().contains(player))
  778. {
  779. _surrenderRequest = 1;
  780. for (L2PcInstance temp : _playerA.getParty().getPartyMembers())
  781. {
  782. temp.setDuelState(DUELSTATE_DEAD);
  783. }
  784. for (L2PcInstance temp : _playerB.getParty().getPartyMembers())
  785. {
  786. temp.setDuelState(DUELSTATE_WINNER);
  787. }
  788. }
  789. else if (_playerB.getParty().getPartyMembers().contains(player))
  790. {
  791. _surrenderRequest = 2;
  792. for (L2PcInstance temp : _playerB.getParty().getPartyMembers())
  793. {
  794. temp.setDuelState(DUELSTATE_DEAD);
  795. }
  796. for (L2PcInstance temp : _playerA.getParty().getPartyMembers())
  797. {
  798. temp.setDuelState(DUELSTATE_WINNER);
  799. }
  800. }
  801. }
  802. else
  803. {
  804. if (player == _playerA)
  805. {
  806. _surrenderRequest = 1;
  807. _playerA.setDuelState(DUELSTATE_DEAD);
  808. _playerB.setDuelState(DUELSTATE_WINNER);
  809. }
  810. else if (player == _playerB)
  811. {
  812. _surrenderRequest = 2;
  813. _playerB.setDuelState(DUELSTATE_DEAD);
  814. _playerA.setDuelState(DUELSTATE_WINNER);
  815. }
  816. }
  817. }
  818. /**
  819. * This function is called whenever a player was defeated in a duel
  820. * @param dieing player
  821. */
  822. public void onPlayerDefeat(L2PcInstance player)
  823. {
  824. // Set player as defeated
  825. player.setDuelState(DUELSTATE_DEAD);
  826. if (_partyDuel)
  827. {
  828. boolean teamdefeated = true;
  829. for (L2PcInstance temp : player.getParty().getPartyMembers())
  830. {
  831. if (temp.getDuelState() == DUELSTATE_DUELLING)
  832. {
  833. teamdefeated = false;
  834. break;
  835. }
  836. }
  837. if (teamdefeated)
  838. {
  839. L2PcInstance winner = _playerA;
  840. if (_playerA.getParty().getPartyMembers().contains(player))
  841. winner = _playerB;
  842. for (L2PcInstance temp : winner.getParty().getPartyMembers())
  843. {
  844. temp.setDuelState(DUELSTATE_WINNER);
  845. }
  846. }
  847. }
  848. else
  849. {
  850. if (player != _playerA && player != _playerB)
  851. _log.warning("Error in onPlayerDefeat(): player is not part of this 1vs1 duel");
  852. if (_playerA == player)
  853. _playerB.setDuelState(DUELSTATE_WINNER);
  854. else
  855. _playerA.setDuelState(DUELSTATE_WINNER);
  856. }
  857. }
  858. /**
  859. * This function is called whenever a player leaves a party
  860. * @param leaving player
  861. */
  862. public void onRemoveFromParty(L2PcInstance player)
  863. {
  864. // if it isnt a party duel ignore this
  865. if (!_partyDuel)
  866. return;
  867. // this player is leaving his party during party duel
  868. // if hes either playerA or playerB cancel the duel and port the players back
  869. if (player == _playerA || player == _playerB)
  870. {
  871. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  872. {
  873. e.getValue().teleportBack();
  874. e.getValue().getPlayer().setIsInDuel(0);
  875. }
  876. _playerA = null;
  877. _playerB = null;
  878. }
  879. else
  880. // teleport the player back & delete his PlayerCondition record
  881. {
  882. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  883. {
  884. if (e.getValue().getPlayer() == player)
  885. {
  886. e.getValue().teleportBack();
  887. _playerConditions.remove(e.getValue());
  888. break;
  889. }
  890. }
  891. player.setIsInDuel(0);
  892. }
  893. }
  894. public void onBuff(L2PcInstance player, L2Effect debuff)
  895. {
  896. for (FastList.Node<PlayerCondition> e = _playerConditions.head(), end = _playerConditions.tail(); (e = e.getNext()) != end;)
  897. {
  898. if (e.getValue().getPlayer() == player)
  899. {
  900. e.getValue().registerDebuff(debuff);
  901. return;
  902. }
  903. }
  904. }
  905. }