Duel.java 25 KB

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