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