com.l2jfree.gameserver.instancemanager.games.Lottery.java Source code

Java tutorial

Introduction

Here is the source code for com.l2jfree.gameserver.instancemanager.games.Lottery.java

Source

/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.l2jfree.gameserver.instancemanager.games;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.l2jfree.Config;
import com.l2jfree.L2DatabaseFactory;
import com.l2jfree.gameserver.Announcements;
import com.l2jfree.gameserver.ThreadPoolManager;
import com.l2jfree.gameserver.model.items.L2ItemInstance;
import com.l2jfree.gameserver.network.SystemMessageId;
import com.l2jfree.gameserver.network.packets.server.SystemMessage;
import com.l2jfree.lang.L2Math;
import com.l2jfree.tools.random.Rnd;

public class Lottery {
    public static final long SECOND = 1000;
    public static final long MINUTE = 60000;

    protected static Log _log = LogFactory.getLog(Lottery.class);

    private static final String INSERT_LOTTERY = "INSERT INTO games(id, idnr, enddate, prize, newprize) VALUES (?, ?, ?, ?, ?)";
    private static final String UPDATE_PRICE = "UPDATE games SET prize=?, newprize=? WHERE id = 1 AND idnr = ?";
    private static final String UPDATE_LOTTERY = "UPDATE games SET finished=1, prize=?, newprize=?, number1=?, number2=?, prize1=?, prize2=?, prize3=? WHERE id=1 AND idnr=?";
    private static final String SELECT_LAST_LOTTERY = "SELECT idnr, prize, newprize, enddate, finished FROM games WHERE id = 1 ORDER BY idnr DESC LIMIT 1";
    private static final String SELECT_LOTTERY_ITEM = "SELECT enchant_level, custom_type2 FROM items WHERE item_id = 4442 AND custom_type1 = ?";
    private static final String SELECT_LOTTERY_TICKET = "SELECT number1, number2, prize1, prize2, prize3 FROM games WHERE id = 1 AND idnr = ?";

    protected int _number;
    protected long _prize;
    protected boolean _isSellingTickets;
    protected boolean _isStarted;
    protected long _enddate;

    private Lottery() {
        _number = 1;
        _prize = Config.ALT_LOTTERY_PRIZE;
        _isSellingTickets = false;
        _isStarted = false;
        _enddate = System.currentTimeMillis();

        if (Config.ALLOW_LOTTERY)
            (new startLottery()).run();
    }

    public static Lottery getInstance() {
        return SingletonHolder._instance;
    }

    public int getId() {
        return _number;
    }

    public long getPrize() {
        return _prize;
    }

    public long getEndDate() {
        return _enddate;
    }

    public void increasePrize(long count) {
        _prize += count;
        Connection con = null;
        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            PreparedStatement statement;
            statement = con.prepareStatement(UPDATE_PRICE);
            statement.setLong(1, getPrize());
            statement.setLong(2, getPrize());
            statement.setInt(3, getId());
            statement.execute();
            statement.close();
        } catch (SQLException e) {
            _log.warn("Lottery: Could not increase current lottery prize: ", e);
        } finally {
            L2DatabaseFactory.close(con);
        }
    }

    public boolean isSellableTickets() {
        return _isSellingTickets;
    }

    public boolean isStarted() {
        return _isStarted;
    }

    private class startLottery implements Runnable {
        protected startLottery() {
            // Do nothing
        }

        @Override
        public void run() {
            if (restoreLotteryData()) {
                announceLottery();

                scheduleEndOfLottery();

                createNewLottery();
            }
        }

        private boolean restoreLotteryData() {
            Connection con = null;
            PreparedStatement statement;
            try {
                con = L2DatabaseFactory.getInstance().getConnection(con);
                statement = con.prepareStatement(SELECT_LAST_LOTTERY);
                ResultSet rset = statement.executeQuery();

                if (rset.next()) {
                    _number = rset.getInt("idnr");

                    if (rset.getInt("finished") == 1) {
                        _number++;
                        _prize = rset.getLong("newprize");
                    } else {
                        _prize = rset.getLong("prize");
                        _enddate = rset.getLong("enddate");

                        if (_enddate <= System.currentTimeMillis() + 2 * MINUTE) {
                            (new finishLottery()).run();
                            rset.close();
                            statement.close();
                            return false;
                        }

                        if (_enddate > System.currentTimeMillis()) {
                            _isStarted = true;
                            ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(),
                                    _enddate - System.currentTimeMillis());

                            if (_enddate > System.currentTimeMillis() + 12 * MINUTE) {
                                _isSellingTickets = true;
                                ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(),
                                        _enddate - System.currentTimeMillis() - 10 * MINUTE);
                            }
                            rset.close();
                            statement.close();
                            return false;
                        }
                    }
                }
                rset.close();
                statement.close();
            } catch (SQLException e) {
                _log.warn("Lottery: Could not restore lottery data: ", e);
            } finally {
                L2DatabaseFactory.close(con);
            }

            return true;
        }

        private void announceLottery() {
            if (_log.isDebugEnabled())
                _log.info("Lottery: Starting ticket sell for lottery #" + getId() + ".");
            _isSellingTickets = true;
            _isStarted = true;

            Announcements.getInstance()
                    .announceToAll("Lottery tickets are now available for Lucky Lottery #" + getId() + ".");
        }

        private void scheduleEndOfLottery() {
            Calendar finishtime = Calendar.getInstance();
            finishtime.setTimeInMillis(_enddate);
            finishtime.set(Calendar.MINUTE, 0);
            finishtime.set(Calendar.SECOND, 0);
            finishtime.add(Calendar.DAY_OF_MONTH, 7);
            finishtime.set(Calendar.DAY_OF_WEEK, 6);
            finishtime.set(Calendar.HOUR_OF_DAY, 7);
            _enddate = finishtime.getTimeInMillis();

            ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(),
                    _enddate - System.currentTimeMillis() - 10 * MINUTE);
            ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(),
                    _enddate - System.currentTimeMillis());
        }

        /**
         * @param statement
         */
        private void createNewLottery() {
            Connection con = null;
            PreparedStatement statement;
            try {
                con = L2DatabaseFactory.getInstance().getConnection(con);
                statement = con.prepareStatement(INSERT_LOTTERY);
                statement.setInt(1, 1);
                statement.setInt(2, getId());
                statement.setLong(3, getEndDate());
                statement.setLong(4, getPrize());
                statement.setLong(5, getPrize());
                statement.execute();
                statement.close();
            } catch (SQLException e) {
                _log.warn("Lottery: Could not store new lottery data: ", e);
            } finally {
                L2DatabaseFactory.close(con);
            }
        }
    }

    private class stopSellingTickets implements Runnable {
        protected stopSellingTickets() {
            // Do nothing
        }

        @Override
        public void run() {
            if (_log.isDebugEnabled())
                _log.info("Lottery: Stopping ticket sell for lottery #" + getId() + ".");
            _isSellingTickets = false;

            Announcements.getInstance().announceToAll(SystemMessageId.LOTTERY_TICKET_SALES_TEMP_SUSPENDED);
        }
    }

    private class finishLottery implements Runnable {
        protected finishLottery() {
            // Do nothing
        }

        @Override
        public void run() {
            if (_log.isDebugEnabled())
                _log.info("Lottery: Ending lottery #" + getId() + ".");

            int[] luckynums = new int[5];
            int luckynum = 0;

            for (int i = 0; i < 5; i++) {
                boolean found = true;

                while (found) {
                    luckynum = Rnd.get(20) + 1;
                    found = false;

                    for (int j = 0; j < i; j++)
                        if (luckynums[j] == luckynum)
                            found = true;
                }

                luckynums[i] = luckynum;
            }

            if (_log.isDebugEnabled())
                _log.debug("Lottery: The lucky numbers are " + luckynums[0] + ", " + luckynums[1] + ", "
                        + luckynums[2] + ", " + luckynums[3] + ", " + luckynums[4] + ".");

            int enchant = 0;
            int type2 = 0;

            for (int i = 0; i < 5; i++) {
                if (luckynums[i] < 17)
                    enchant += L2Math.pow(2, luckynums[i] - 1);
                else
                    type2 += L2Math.pow(2, luckynums[i] - 17);
            }

            if (_log.isDebugEnabled())
                _log.debug("Lottery: Encoded lucky numbers are " + enchant + ", " + type2);

            int count1 = 0;
            int count2 = 0;
            int count3 = 0;
            int count4 = 0;

            Connection con = null;
            PreparedStatement statement;
            try {
                con = L2DatabaseFactory.getInstance().getConnection(con);
                statement = con.prepareStatement(SELECT_LOTTERY_ITEM);
                statement.setInt(1, getId());
                ResultSet rset = statement.executeQuery();

                while (rset.next()) {
                    int curenchant = rset.getInt("enchant_level") & enchant;
                    int curtype2 = rset.getInt("custom_type2") & type2;

                    if (curenchant == 0 && curtype2 == 0)
                        continue;

                    int count = 0;

                    for (int i = 1; i <= 16; i++) {
                        int val = curenchant / 2;

                        if (val != (double) curenchant / 2)
                            count++;

                        int val2 = curtype2 / 2;

                        if (val2 != (double) curtype2 / 2)
                            count++;

                        curenchant = val;
                        curtype2 = val2;
                    }

                    if (count == 5)
                        count1++;
                    else if (count == 4)
                        count2++;
                    else if (count == 3)
                        count3++;
                    else if (count > 0)
                        count4++;
                }
                rset.close();
                statement.close();
            } catch (SQLException e) {
                _log.warn("Lottery: Could restore lottery data: ", e);
            } finally {
                L2DatabaseFactory.close(con);
            }

            long prize4 = count4 * Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE;
            long prize1 = 0;
            long prize2 = 0;
            long prize3 = 0;

            if (count1 > 0)
                prize1 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_5_NUMBER_RATE / count1);

            if (count2 > 0)
                prize2 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_4_NUMBER_RATE / count2);

            if (count3 > 0)
                prize3 = (long) ((getPrize() - prize4) * Config.ALT_LOTTERY_3_NUMBER_RATE / count3);

            if (_log.isDebugEnabled()) {
                _log.info("Lottery: " + count1 + " players with all FIVE numbers each win " + prize1 + ".");
                _log.info("Lottery: " + count2 + " players with FOUR numbers each win " + prize2 + ".");
                _log.info("Lottery: " + count3 + " players with THREE numbers each win " + prize3 + ".");
                _log.info("Lottery: " + count4 + " players with ONE or TWO numbers each win " + prize4 + ".");
            }

            long newprize = getPrize() - (prize1 + prize2 + prize3 + prize4);
            if (_log.isDebugEnabled())
                _log.info("Lottery: Jackpot for next lottery is " + newprize + ".");

            SystemMessage sm;
            if (count1 > 0) {
                // There are winners.
                sm = new SystemMessage(SystemMessageId.AMOUNT_FOR_WINNER_S1_IS_S2_ADENA_WE_HAVE_S3_PRIZE_WINNER);
                sm.addNumber(getId());
                sm.addItemNumber(getPrize());
                sm.addItemNumber(count1);
                Announcements.getInstance().announceToAll(sm);
            } else {
                // There are no winners.
                sm = new SystemMessage(SystemMessageId.AMOUNT_FOR_LOTTERY_S1_IS_S2_ADENA_NO_WINNER);
                sm.addNumber(getId());
                sm.addItemNumber(getPrize());
                Announcements.getInstance().announceToAll(sm);
            }
            con = null;
            try {

                con = L2DatabaseFactory.getInstance().getConnection(con);
                statement = con.prepareStatement(UPDATE_LOTTERY);
                statement.setLong(1, getPrize());
                statement.setLong(2, newprize);
                statement.setInt(3, enchant);
                statement.setInt(4, type2);
                statement.setLong(5, prize1);
                statement.setLong(6, prize2);
                statement.setLong(7, prize3);
                statement.setInt(8, getId());
                statement.execute();
                statement.close();
            } catch (SQLException e) {
                _log.warn("Lottery: Could not store finished lottery data: ", e);
            } finally {
                L2DatabaseFactory.close(con);
            }

            ThreadPoolManager.getInstance().scheduleGeneral(new startLottery(), 1 * MINUTE);
            _number++;

            _isStarted = false;
        }
    }

    public int[] decodeNumbers(int enchant, int type2) {
        int res[] = new int[5];
        int id = 0;
        int nr = 1;

        while (enchant > 0) {
            int val = enchant / 2;
            if (val != (double) enchant / 2) {
                res[id++] = nr;
            }
            enchant /= 2;
            nr++;
        }

        nr = 17;

        while (type2 > 0) {
            int val = type2 / 2;
            if (val != (double) type2 / 2) {
                res[id++] = nr;
            }
            type2 /= 2;
            nr++;
        }

        return res;
    }

    public long[] checkTicket(L2ItemInstance item) {
        return checkTicket(item.getCustomType1(), item.getEnchantLevel(), item.getCustomType2());
    }

    public long[] checkTicket(int id, int enchant, int type2) {
        long res[] = { 0, 0 };

        Connection con = null;
        PreparedStatement statement;

        try {
            con = L2DatabaseFactory.getInstance().getConnection(con);
            statement = con.prepareStatement(SELECT_LOTTERY_TICKET);
            statement.setInt(1, id);
            ResultSet rset = statement.executeQuery();

            if (rset.next()) {
                int curenchant = rset.getInt("number1") & enchant;
                int curtype2 = rset.getInt("number2") & type2;

                if (curenchant == 0 && curtype2 == 0) {
                    rset.close();
                    statement.close();
                    return res;
                }

                int count = 0;

                for (int i = 1; i <= 16; i++) {
                    int val = curenchant / 2;
                    if (val != (double) curenchant / 2)
                        count++;
                    int val2 = curtype2 / 2;
                    if (val2 != (double) curtype2 / 2)
                        count++;
                    curenchant = val;
                    curtype2 = val2;
                }

                switch (count) {
                case 0:
                    break;
                case 5:
                    res[0] = 1;
                    res[1] = rset.getLong("prize1");
                    break;
                case 4:
                    res[0] = 2;
                    res[1] = rset.getLong("prize2");
                    break;
                case 3:
                    res[0] = 3;
                    res[1] = rset.getLong("prize3");
                    break;
                default:
                    res[0] = 4;
                    res[1] = 200;
                }

                if (_log.isDebugEnabled())
                    _log.warn("count: " + count + ", id: " + id + ", enchant: " + enchant + ", type2: " + type2);
            }

            rset.close();
            statement.close();
        } catch (SQLException e) {
            _log.warn("Lottery: Could not check lottery ticket #" + id + ": ", e);
        } finally {
            L2DatabaseFactory.close(con);
        }

        return res;
    }

    @SuppressWarnings("synthetic-access")
    private static class SingletonHolder {
        protected static final Lottery _instance = new Lottery();
    }
}