2
0

Lottery.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.instancemanager.games;
  16. import java.sql.Connection;
  17. import java.sql.PreparedStatement;
  18. import java.sql.ResultSet;
  19. import java.sql.SQLException;
  20. import java.util.Calendar;
  21. import java.util.logging.Level;
  22. import java.util.logging.Logger;
  23. import com.l2jserver.Config;
  24. import com.l2jserver.L2DatabaseFactory;
  25. import com.l2jserver.gameserver.Announcements;
  26. import com.l2jserver.gameserver.ThreadPoolManager;
  27. import com.l2jserver.gameserver.model.L2ItemInstance;
  28. import com.l2jserver.gameserver.network.SystemMessageId;
  29. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  30. import com.l2jserver.util.Rnd;
  31. public class Lottery
  32. {
  33. public static final long SECOND = 1000;
  34. public static final long MINUTE = 60000;
  35. protected static final Logger _log = Logger.getLogger(Lottery.class.getName());
  36. private static final String INSERT_LOTTERY = "INSERT INTO games(id, idnr, enddate, prize, newprize) VALUES (?, ?, ?, ?, ?)";
  37. private static final String UPDATE_PRICE = "UPDATE games SET prize=?, newprize=? WHERE id = 1 AND idnr = ?";
  38. private static final String UPDATE_LOTTERY = "UPDATE games SET finished=1, prize=?, newprize=?, number1=?, number2=?, prize1=?, prize2=?, prize3=? WHERE id=1 AND idnr=?";
  39. private static final String SELECT_LAST_LOTTERY = "SELECT idnr, prize, newprize, enddate, finished FROM games WHERE id = 1 ORDER BY idnr DESC LIMIT 1";
  40. private static final String SELECT_LOTTERY_ITEM = "SELECT enchant_level, custom_type2 FROM items WHERE item_id = 4442 AND custom_type1 = ?";
  41. private static final String SELECT_LOTTERY_TICKET = "SELECT number1, number2, prize1, prize2, prize3 FROM games WHERE id = 1 and idnr = ?";
  42. protected int _number;
  43. protected long _prize;
  44. protected boolean _isSellingTickets;
  45. protected boolean _isStarted;
  46. protected long _enddate;
  47. private Lottery()
  48. {
  49. _number = 1;
  50. _prize = Config.ALT_LOTTERY_PRIZE;
  51. _isSellingTickets = false;
  52. _isStarted = false;
  53. _enddate = System.currentTimeMillis();
  54. if (Config.ALLOW_LOTTERY)
  55. (new startLottery()).run();
  56. }
  57. public static Lottery getInstance()
  58. {
  59. return SingletonHolder._instance;
  60. }
  61. public int getId()
  62. {
  63. return _number;
  64. }
  65. public long getPrize()
  66. {
  67. return _prize;
  68. }
  69. public long getEndDate()
  70. {
  71. return _enddate;
  72. }
  73. public void increasePrize(long count)
  74. {
  75. _prize += count;
  76. Connection con = null;
  77. try
  78. {
  79. con = L2DatabaseFactory.getInstance().getConnection();
  80. PreparedStatement statement;
  81. statement = con.prepareStatement(UPDATE_PRICE);
  82. statement.setLong(1, getPrize());
  83. statement.setLong(2, getPrize());
  84. statement.setInt(3, getId());
  85. statement.execute();
  86. statement.close();
  87. }
  88. catch (SQLException e)
  89. {
  90. _log.log(Level.WARNING, "Lottery: Could not increase current lottery prize: " + e.getMessage(), e);
  91. }
  92. finally
  93. {
  94. try
  95. {
  96. con.close();
  97. }
  98. catch (Exception e)
  99. {
  100. }
  101. }
  102. }
  103. public boolean isSellableTickets()
  104. {
  105. return _isSellingTickets;
  106. }
  107. public boolean isStarted()
  108. {
  109. return _isStarted;
  110. }
  111. private class startLottery implements Runnable
  112. {
  113. protected startLottery()
  114. {
  115. // Do nothing
  116. }
  117. public void run()
  118. {
  119. Connection con = null;
  120. PreparedStatement statement;
  121. try
  122. {
  123. con = L2DatabaseFactory.getInstance().getConnection();
  124. statement = con.prepareStatement(SELECT_LAST_LOTTERY);
  125. ResultSet rset = statement.executeQuery();
  126. if (rset.next())
  127. {
  128. _number = rset.getInt("idnr");
  129. if (rset.getInt("finished") == 1)
  130. {
  131. _number++;
  132. _prize = rset.getLong("newprize");
  133. }
  134. else
  135. {
  136. _prize = rset.getLong("prize");
  137. _enddate = rset.getLong("enddate");
  138. if (_enddate <= System.currentTimeMillis() + 2 * MINUTE)
  139. {
  140. (new finishLottery()).run();
  141. rset.close();
  142. statement.close();
  143. return;
  144. }
  145. if (_enddate > System.currentTimeMillis())
  146. {
  147. _isStarted = true;
  148. ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(), _enddate - System.currentTimeMillis());
  149. if (_enddate > System.currentTimeMillis() + 12 * MINUTE)
  150. {
  151. _isSellingTickets = true;
  152. ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(), _enddate - System.currentTimeMillis() - 10 * MINUTE);
  153. }
  154. rset.close();
  155. statement.close();
  156. return;
  157. }
  158. }
  159. }
  160. rset.close();
  161. statement.close();
  162. }
  163. catch (SQLException e)
  164. {
  165. _log.log(Level.WARNING, "Lottery: Could not restore lottery data: " + e.getMessage(), e);
  166. }
  167. finally
  168. {
  169. try
  170. {
  171. con.close();
  172. }
  173. catch (Exception e)
  174. {
  175. }
  176. }
  177. if (Config.DEBUG)
  178. _log.info("Lottery: Starting ticket sell for lottery #" + getId() + ".");
  179. _isSellingTickets = true;
  180. _isStarted = true;
  181. Announcements.getInstance().announceToAll("Lottery tickets are now available for Lucky Lottery #" + getId() + ".");
  182. Calendar finishtime = Calendar.getInstance();
  183. finishtime.setTimeInMillis(_enddate);
  184. finishtime.set(Calendar.MINUTE, 0);
  185. finishtime.set(Calendar.SECOND, 0);
  186. if (finishtime.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
  187. {
  188. finishtime.set(Calendar.HOUR_OF_DAY, 19);
  189. _enddate = finishtime.getTimeInMillis();
  190. _enddate += 604800000;
  191. }
  192. else
  193. {
  194. finishtime.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
  195. finishtime.set(Calendar.HOUR_OF_DAY, 19);
  196. _enddate = finishtime.getTimeInMillis();
  197. }
  198. ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(), _enddate - System.currentTimeMillis() - 10 * MINUTE);
  199. ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(), _enddate - System.currentTimeMillis());
  200. try
  201. {
  202. con = L2DatabaseFactory.getInstance().getConnection();
  203. statement = con.prepareStatement(INSERT_LOTTERY);
  204. statement.setInt(1, 1);
  205. statement.setInt(2, getId());
  206. statement.setLong(3, getEndDate());
  207. statement.setLong(4, getPrize());
  208. statement.setLong(5, getPrize());
  209. statement.execute();
  210. statement.close();
  211. }
  212. catch (SQLException e)
  213. {
  214. _log.log(Level.WARNING, "Lottery: Could not store new lottery data: " + e.getMessage(), e);
  215. }
  216. finally
  217. {
  218. try
  219. {
  220. con.close();
  221. }
  222. catch (Exception e)
  223. {
  224. }
  225. }
  226. }
  227. }
  228. private class stopSellingTickets implements Runnable
  229. {
  230. protected stopSellingTickets()
  231. {
  232. // Do nothing
  233. }
  234. public void run()
  235. {
  236. if (Config.DEBUG)
  237. _log.info("Lottery: Stopping ticket sell for lottery #" + getId() + ".");
  238. _isSellingTickets = false;
  239. Announcements.getInstance().announceToAll(new SystemMessage(SystemMessageId.LOTTERY_TICKET_SALES_TEMP_SUSPENDED));
  240. }
  241. }
  242. private class finishLottery implements Runnable
  243. {
  244. protected finishLottery()
  245. {
  246. // Do nothing
  247. }
  248. public void run()
  249. {
  250. if (Config.DEBUG)
  251. _log.info("Lottery: Ending lottery #" + getId() + ".");
  252. int[] luckynums = new int[5];
  253. int luckynum = 0;
  254. for (int i = 0; i < 5; i++)
  255. {
  256. boolean found = true;
  257. while (found)
  258. {
  259. luckynum = Rnd.get(20) + 1;
  260. found = false;
  261. for (int j = 0; j < i; j++)
  262. if (luckynums[j] == luckynum)
  263. found = true;
  264. }
  265. luckynums[i] = luckynum;
  266. }
  267. if (Config.DEBUG)
  268. _log.info("Lottery: The lucky numbers are " + luckynums[0] + ", " + luckynums[1] + ", " + luckynums[2] + ", " + luckynums[3] + ", " + luckynums[4] + ".");
  269. int enchant = 0;
  270. int type2 = 0;
  271. for (int i = 0; i < 5; i++)
  272. {
  273. if (luckynums[i] < 17)
  274. enchant += Math.pow(2, luckynums[i] - 1);
  275. else
  276. type2 += Math.pow(2, luckynums[i] - 17);
  277. }
  278. if (Config.DEBUG)
  279. _log.info("Lottery: Encoded lucky numbers are " + enchant + ", " + type2);
  280. int count1 = 0;
  281. int count2 = 0;
  282. int count3 = 0;
  283. int count4 = 0;
  284. Connection con = null;
  285. PreparedStatement statement;
  286. try
  287. {
  288. con = L2DatabaseFactory.getInstance().getConnection();
  289. statement = con.prepareStatement(SELECT_LOTTERY_ITEM);
  290. statement.setInt(1, getId());
  291. ResultSet rset = statement.executeQuery();
  292. while (rset.next())
  293. {
  294. int curenchant = rset.getInt("enchant_level") & enchant;
  295. int curtype2 = rset.getInt("custom_type2") & type2;
  296. if (curenchant == 0 && curtype2 == 0)
  297. continue;
  298. int count = 0;
  299. for (int i = 1; i <= 16; i++)
  300. {
  301. int val = curenchant / 2;
  302. if (val != (double) curenchant / 2)
  303. count++;
  304. int val2 = curtype2 / 2;
  305. if (val2 != (double) curtype2 / 2)
  306. count++;
  307. curenchant = val;
  308. curtype2 = val2;
  309. }
  310. if (count == 5)
  311. count1++;
  312. else if (count == 4)
  313. count2++;
  314. else if (count == 3)
  315. count3++;
  316. else if (count > 0)
  317. count4++;
  318. }
  319. rset.close();
  320. statement.close();
  321. }
  322. catch (SQLException e)
  323. {
  324. _log.log(Level.WARNING, "Lottery: Could restore lottery data: " + e.getMessage(), e);
  325. }
  326. finally
  327. {
  328. try
  329. {
  330. con.close();
  331. }
  332. catch (Exception e)
  333. {
  334. }
  335. }
  336. long prize4 = count4 * Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE;
  337. long prize1 = 0;
  338. long prize2 = 0;
  339. long prize3 = 0;
  340. if (count1 > 0)
  341. prize1 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_5_NUMBER_RATE / count1);
  342. if (count2 > 0)
  343. prize2 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_4_NUMBER_RATE / count2);
  344. if (count3 > 0)
  345. prize3 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_3_NUMBER_RATE / count3);
  346. if (Config.DEBUG)
  347. {
  348. _log.info("Lottery: " + count1 + " players with all FIVE numbers each win " + prize1 + ".");
  349. _log.info("Lottery: " + count2 + " players with FOUR numbers each win " + prize2 + ".");
  350. _log.info("Lottery: " + count3 + " players with THREE numbers each win " + prize3 + ".");
  351. _log.info("Lottery: " + count4 + " players with ONE or TWO numbers each win " + prize4 + ".");
  352. }
  353. long newprize = getPrize() - (prize1 + prize2 + prize3 + prize4);
  354. if (Config.DEBUG)
  355. _log.info("Lottery: Jackpot for next lottery is " + newprize + ".");
  356. SystemMessage sm;
  357. if (count1 > 0)
  358. {
  359. // There are winners.
  360. sm = new SystemMessage(SystemMessageId.AMOUNT_FOR_WINNER_S1_IS_S2_ADENA_WE_HAVE_S3_PRIZE_WINNER);
  361. sm.addNumber(getId());
  362. sm.addItemNumber(getPrize());
  363. sm.addItemNumber(count1);
  364. Announcements.getInstance().announceToAll(sm);
  365. }
  366. else
  367. {
  368. // There are no winners.
  369. sm = new SystemMessage(SystemMessageId.AMOUNT_FOR_LOTTERY_S1_IS_S2_ADENA_NO_WINNER);
  370. sm.addNumber(getId());
  371. sm.addItemNumber(getPrize());
  372. Announcements.getInstance().announceToAll(sm);
  373. }
  374. try
  375. {
  376. con = L2DatabaseFactory.getInstance().getConnection();
  377. statement = con.prepareStatement(UPDATE_LOTTERY);
  378. statement.setLong(1, getPrize());
  379. statement.setLong(2, newprize);
  380. statement.setInt(3, enchant);
  381. statement.setInt(4, type2);
  382. statement.setLong(5, prize1);
  383. statement.setLong(6, prize2);
  384. statement.setLong(7, prize3);
  385. statement.setInt(8, getId());
  386. statement.execute();
  387. statement.close();
  388. }
  389. catch (SQLException e)
  390. {
  391. _log.log(Level.WARNING, "Lottery: Could not store finished lottery data: " + e.getMessage(), e);
  392. }
  393. finally
  394. {
  395. try
  396. {
  397. con.close();
  398. }
  399. catch (Exception e)
  400. {
  401. }
  402. }
  403. ThreadPoolManager.getInstance().scheduleGeneral(new startLottery(), MINUTE);
  404. _number++;
  405. _isStarted = false;
  406. }
  407. }
  408. public int[] decodeNumbers(int enchant, int type2)
  409. {
  410. int res[] = new int[5];
  411. int id = 0;
  412. int nr = 1;
  413. while (enchant > 0)
  414. {
  415. int val = enchant / 2;
  416. if (val != (double) enchant / 2)
  417. {
  418. res[id++] = nr;
  419. }
  420. enchant /= 2;
  421. nr++;
  422. }
  423. nr = 17;
  424. while (type2 > 0)
  425. {
  426. int val = type2 / 2;
  427. if (val != (double) type2 / 2)
  428. {
  429. res[id++] = nr;
  430. }
  431. type2 /= 2;
  432. nr++;
  433. }
  434. return res;
  435. }
  436. public long[] checkTicket(L2ItemInstance item)
  437. {
  438. return checkTicket(item.getCustomType1(), item.getEnchantLevel(), item.getCustomType2());
  439. }
  440. public long[] checkTicket(int id, int enchant, int type2)
  441. {
  442. long res[] = { 0, 0 };
  443. Connection con = null;
  444. PreparedStatement statement;
  445. try
  446. {
  447. con = L2DatabaseFactory.getInstance().getConnection();
  448. statement = con.prepareStatement(SELECT_LOTTERY_TICKET);
  449. statement.setInt(1, id);
  450. ResultSet rset = statement.executeQuery();
  451. if (rset.next())
  452. {
  453. int curenchant = rset.getInt("number1") & enchant;
  454. int curtype2 = rset.getInt("number2") & type2;
  455. if (curenchant == 0 && curtype2 == 0)
  456. {
  457. rset.close();
  458. statement.close();
  459. return res;
  460. }
  461. int count = 0;
  462. for (int i = 1; i <= 16; i++)
  463. {
  464. int val = curenchant / 2;
  465. if (val != (double) curenchant / 2)
  466. count++;
  467. int val2 = curtype2 / 2;
  468. if (val2 != (double) curtype2 / 2)
  469. count++;
  470. curenchant = val;
  471. curtype2 = val2;
  472. }
  473. switch (count)
  474. {
  475. case 0:
  476. break;
  477. case 5:
  478. res[0] = 1;
  479. res[1] = rset.getLong("prize1");
  480. break;
  481. case 4:
  482. res[0] = 2;
  483. res[1] = rset.getLong("prize2");
  484. break;
  485. case 3:
  486. res[0] = 3;
  487. res[1] = rset.getLong("prize3");
  488. break;
  489. default:
  490. res[0] = 4;
  491. res[1] = 200;
  492. }
  493. if (Config.DEBUG)
  494. _log.warning("count: " + count + ", id: " + id + ", enchant: " + enchant + ", type2: " + type2);
  495. }
  496. rset.close();
  497. statement.close();
  498. }
  499. catch (SQLException e)
  500. {
  501. _log.log(Level.WARNING, "Lottery: Could not check lottery ticket #" + id + ": " + e.getMessage(), e);
  502. }
  503. finally
  504. {
  505. try
  506. {
  507. con.close();
  508. }
  509. catch (Exception e)
  510. {
  511. }
  512. }
  513. return res;
  514. }
  515. @SuppressWarnings("synthetic-access")
  516. private static class SingletonHolder
  517. {
  518. protected static final Lottery _instance = new Lottery();
  519. }
  520. }