Addition of Monster Race with reward system.
Adapted from aCis free version.
This commit is contained in:
@ -148,6 +148,7 @@ import org.l2jmobius.gameserver.instancemanager.SiegeGuardManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.SiegeManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.WalkingManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.ZoneManager;
|
||||
import org.l2jmobius.gameserver.instancemanager.games.MonsterRace;
|
||||
import org.l2jmobius.gameserver.model.World;
|
||||
import org.l2jmobius.gameserver.model.entity.Hero;
|
||||
import org.l2jmobius.gameserver.model.events.EventDispatcher;
|
||||
@ -412,10 +413,8 @@ public class GameServer
|
||||
ItemsAutoDestroy.getInstance();
|
||||
}
|
||||
|
||||
if (Config.ALLOW_RACE)
|
||||
{
|
||||
MonsterRace.getInstance();
|
||||
}
|
||||
MonsterRace.getInstance();
|
||||
|
||||
TaskManager.getInstance();
|
||||
|
||||
AntiFeedManager.getInstance().registerEvent(AntiFeedManager.GAME_ID);
|
||||
|
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 org.l2jmobius.gameserver;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.l2jmobius.commons.util.Rnd;
|
||||
import org.l2jmobius.gameserver.data.xml.impl.NpcData;
|
||||
import org.l2jmobius.gameserver.model.actor.Npc;
|
||||
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
|
||||
|
||||
public class MonsterRace
|
||||
{
|
||||
protected static final Logger LOGGER = Logger.getLogger(MonsterRace.class.getName());
|
||||
|
||||
private final Npc[] _monsters;
|
||||
private int[][] _speeds;
|
||||
private final int[] _first;
|
||||
private final int[] _second;
|
||||
|
||||
protected MonsterRace()
|
||||
{
|
||||
_monsters = new Npc[8];
|
||||
_speeds = new int[8][20];
|
||||
_first = new int[2];
|
||||
_second = new int[2];
|
||||
}
|
||||
|
||||
public void newRace()
|
||||
{
|
||||
int random = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
final int id = 31003;
|
||||
random = Rnd.get(24);
|
||||
while (true)
|
||||
{
|
||||
for (int j = i - 1; j >= 0; j--)
|
||||
{
|
||||
if (_monsters[j].getTemplate().getId() == (id + random))
|
||||
{
|
||||
random = Rnd.get(24);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
final NpcTemplate template = NpcData.getInstance().getTemplate(id + random);
|
||||
_monsters[i] = (Npc) Class.forName("org.l2jmobius.gameserver.model.actor.instance." + template.getType() + "Instance").getConstructors()[0].newInstance(template);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "Unable to create monster!", e);
|
||||
}
|
||||
}
|
||||
newSpeeds();
|
||||
}
|
||||
|
||||
public void newSpeeds()
|
||||
{
|
||||
_speeds = new int[8][20];
|
||||
int total = 0;
|
||||
_first[1] = 0;
|
||||
_second[1] = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
total = 0;
|
||||
for (int j = 0; j < 20; j++)
|
||||
{
|
||||
_speeds[i][j] = j == 19 ? 100 : Rnd.get(60) + 65;
|
||||
total += _speeds[i][j];
|
||||
}
|
||||
if (total >= _first[1])
|
||||
{
|
||||
_second[0] = _first[0];
|
||||
_second[1] = _first[1];
|
||||
_first[0] = 8 - i;
|
||||
_first[1] = total;
|
||||
}
|
||||
else if (total >= _second[1])
|
||||
{
|
||||
_second[0] = 8 - i;
|
||||
_second[1] = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the monsters.
|
||||
*/
|
||||
public Npc[] getMonsters()
|
||||
{
|
||||
return _monsters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the speeds.
|
||||
*/
|
||||
public int[][] getSpeeds()
|
||||
{
|
||||
return _speeds;
|
||||
}
|
||||
|
||||
public int getFirstPlace()
|
||||
{
|
||||
return _first[0];
|
||||
}
|
||||
|
||||
public int getSecondPlace()
|
||||
{
|
||||
return _second[0];
|
||||
}
|
||||
|
||||
public static MonsterRace getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final MonsterRace INSTANCE = new MonsterRace();
|
||||
}
|
||||
}
|
@ -0,0 +1,623 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* 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 org.l2jmobius.gameserver.instancemanager.games;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
import org.l2jmobius.commons.concurrent.ThreadPool;
|
||||
import org.l2jmobius.commons.database.DatabaseFactory;
|
||||
import org.l2jmobius.commons.util.Rnd;
|
||||
import org.l2jmobius.gameserver.data.xml.impl.NpcData;
|
||||
import org.l2jmobius.gameserver.model.actor.Npc;
|
||||
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
|
||||
import org.l2jmobius.gameserver.model.zone.type.DerbyTrackZone;
|
||||
import org.l2jmobius.gameserver.network.SystemMessageId;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.DeleteObject;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.MonRaceInfo;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.PlaySound;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
|
||||
import org.l2jmobius.gameserver.util.Broadcast;
|
||||
|
||||
public class MonsterRace
|
||||
{
|
||||
protected static final Logger LOGGER = Logger.getLogger(MonsterRace.class.getName());
|
||||
|
||||
public static enum RaceState
|
||||
{
|
||||
ACCEPTING_BETS,
|
||||
WAITING,
|
||||
STARTING_RACE,
|
||||
RACE_END
|
||||
}
|
||||
|
||||
protected static final PlaySound SOUND_1 = new PlaySound(1, "S_Race", 0, 0, 0, 0, 0);
|
||||
protected static final PlaySound SOUND_2 = new PlaySound("ItemSound2.race_start");
|
||||
|
||||
protected static final int[][] CODES =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
0
|
||||
},
|
||||
{
|
||||
0,
|
||||
15322
|
||||
},
|
||||
{
|
||||
13765,
|
||||
-1
|
||||
}
|
||||
};
|
||||
|
||||
protected final List<Integer> _npcTemplates = new ArrayList<>(); // List holding npc templates, shuffled on a new race.
|
||||
protected final List<HistoryInfo> _history = new ArrayList<>(); // List holding old race records.
|
||||
protected final Map<Integer, Long> _betsPerLane = new ConcurrentHashMap<>(); // Map holding all bets for each lane ; values setted to 0 after every race.
|
||||
protected final List<Double> _odds = new ArrayList<>(); // List holding sorted odds per lane ; cleared at new odds calculation.
|
||||
|
||||
protected int _raceNumber = 1;
|
||||
protected int _finalCountdown = 0;
|
||||
protected RaceState _state = RaceState.RACE_END;
|
||||
|
||||
protected MonRaceInfo _packet;
|
||||
|
||||
private final Npc[] _monsters = new Npc[8];
|
||||
private int[][] _speeds = new int[8][20];
|
||||
private final int[] _first = new int[2];
|
||||
private final int[] _second = new int[2];
|
||||
|
||||
protected MonsterRace()
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Feed _history with previous race results.
|
||||
loadHistory();
|
||||
|
||||
// Feed _betsPerLane with stored informations on bets.
|
||||
loadBets();
|
||||
|
||||
// Feed _npcTemplates, we will only have to shuffle it when needed.
|
||||
for (int i = 31003; i < 31027; i++)
|
||||
{
|
||||
_npcTemplates.add(i);
|
||||
}
|
||||
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(), 0, 1000);
|
||||
}
|
||||
|
||||
public static class HistoryInfo
|
||||
{
|
||||
private final int _raceId;
|
||||
private int _first;
|
||||
private int _second;
|
||||
private double _oddRate;
|
||||
|
||||
public HistoryInfo(int raceId, int first, int second, double oddRate)
|
||||
{
|
||||
_raceId = raceId;
|
||||
_first = first;
|
||||
_second = second;
|
||||
_oddRate = oddRate;
|
||||
}
|
||||
|
||||
public int getRaceId()
|
||||
{
|
||||
return _raceId;
|
||||
}
|
||||
|
||||
public int getFirst()
|
||||
{
|
||||
return _first;
|
||||
}
|
||||
|
||||
public int getSecond()
|
||||
{
|
||||
return _second;
|
||||
}
|
||||
|
||||
public double getOddRate()
|
||||
{
|
||||
return _oddRate;
|
||||
}
|
||||
|
||||
public void setFirst(int first)
|
||||
{
|
||||
_first = first;
|
||||
}
|
||||
|
||||
public void setSecond(int second)
|
||||
{
|
||||
_second = second;
|
||||
}
|
||||
|
||||
public void setOddRate(double oddRate)
|
||||
{
|
||||
_oddRate = oddRate;
|
||||
}
|
||||
}
|
||||
|
||||
private class Announcement implements Runnable
|
||||
{
|
||||
public Announcement()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (_finalCountdown > 1200)
|
||||
{
|
||||
_finalCountdown = 0;
|
||||
}
|
||||
|
||||
switch (_finalCountdown)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
newRace();
|
||||
newSpeeds();
|
||||
|
||||
_state = RaceState.ACCEPTING_BETS;
|
||||
_packet = new MonRaceInfo(CODES[0][0], CODES[0][1], getMonsters(), getSpeeds());
|
||||
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, _packet, msg);
|
||||
break;
|
||||
}
|
||||
case 30: // 30 sec
|
||||
case 60: // 1 min
|
||||
case 90: // 1 min 30 sec
|
||||
case 120: // 2 min
|
||||
case 150: // 2 min 30
|
||||
case 180: // 3 min
|
||||
case 210: // 3 min 30
|
||||
case 240: // 4 min
|
||||
case 270: // 4 min 30 sec
|
||||
case 330: // 5 min 30 sec
|
||||
case 360: // 6 min
|
||||
case 390: // 6 min 30 sec
|
||||
case 420: // 7 min
|
||||
case 450: // 7 min 30
|
||||
case 480: // 8 min
|
||||
case 510: // 8 min 30
|
||||
case 540: // 9 min
|
||||
case 570: // 9 min 30 sec
|
||||
case 630: // 10 min 30 sec
|
||||
case 660: // 11 min
|
||||
case 690: // 11 min 30 sec
|
||||
case 720: // 12 min
|
||||
case 750: // 12 min 30
|
||||
case 780: // 13 min
|
||||
case 810: // 13 min 30
|
||||
case 870: // 14 min 30 sec
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 300: // 5 min
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
// final SystemMessage msg2 = new SystemMessage(SystemMessageId.TICKET_SALES_FOR_THE_MONSTER_RACE_WILL_END_IN_S1_MINUTE_S);
|
||||
// msg2.addInt(10);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 600: // 10 min
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
// final SystemMessage msg2 = new SystemMessage(SystemMessageId.TICKET_SALES_FOR_THE_MONSTER_RACE_WILL_END_IN_S1_MINUTE_S);
|
||||
// msg2.addInt(5);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 840: // 14 min
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
// final SystemMessage msg2 = new SystemMessage(SystemMessageId.TICKET_SALES_FOR_THE_MONSTER_RACE_WILL_END_IN_S1_MINUTE_S);
|
||||
// msg2.addInt(1);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 900: // 15 min
|
||||
{
|
||||
_state = RaceState.WAITING;
|
||||
|
||||
calculateOdds();
|
||||
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1);
|
||||
msg.addInt(_raceNumber);
|
||||
final SystemMessage msg2 = new SystemMessage(SystemMessageId.TICKETS_SALES_ARE_CLOSED_FOR_MONSTER_RACE_S1_YOU_CAN_SEE_THE_AMOUNT_OF_WIN);
|
||||
msg2.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg, msg2);
|
||||
break;
|
||||
}
|
||||
case 960: // 16 min
|
||||
case 1020: // 17 min
|
||||
{
|
||||
final int minutes = (_finalCountdown == 960) ? 2 : 1;
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_S1_MINUTE_S);
|
||||
msg.addInt(minutes);
|
||||
msg.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 1050: // 17 min 30 sec
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_30_SECONDS);
|
||||
msg.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 1070: // 17 min 50 sec
|
||||
{
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.MONSTER_RACE_S1_IS_ABOUT_TO_BEGIN_COUNTDOWN_IN_FIVE_SECONDS);
|
||||
msg.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 1075: // 17 min 55 sec
|
||||
case 1076: // 17 min 56 sec
|
||||
case 1077: // 17 min 57 sec
|
||||
case 1078: // 17 min 58 sec
|
||||
case 1079: // 17 min 59 sec
|
||||
{
|
||||
final int seconds = 1080 - _finalCountdown;
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S);
|
||||
msg.addInt(seconds);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg);
|
||||
break;
|
||||
}
|
||||
case 1080: // 18 min
|
||||
{
|
||||
_state = RaceState.STARTING_RACE;
|
||||
_packet = new MonRaceInfo(CODES[1][0], CODES[1][1], getMonsters(), getSpeeds());
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, new SystemMessage(SystemMessageId.THEY_RE_OFF), SOUND_1, SOUND_2, _packet);
|
||||
break;
|
||||
}
|
||||
case 1085: // 18 min 5 sec
|
||||
{
|
||||
_packet = new MonRaceInfo(CODES[2][0], CODES[2][1], getMonsters(), getSpeeds());
|
||||
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, _packet);
|
||||
break;
|
||||
}
|
||||
case 1115: // 18 min 35 sec
|
||||
{
|
||||
_state = RaceState.RACE_END;
|
||||
|
||||
// Populate history info with data, stores it in database.
|
||||
final HistoryInfo info = _history.get(_history.size() - 1);
|
||||
info.setFirst(getFirstPlace());
|
||||
info.setSecond(getSecondPlace());
|
||||
info.setOddRate(_odds.get(getFirstPlace() - 1));
|
||||
|
||||
saveHistory(info);
|
||||
clearBets();
|
||||
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.FIRST_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S1_SECOND_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S2);
|
||||
msg.addInt(getFirstPlace());
|
||||
msg.addInt(getSecondPlace());
|
||||
final SystemMessage msg2 = new SystemMessage(SystemMessageId.MONSTER_RACE_S1_IS_FINISHED);
|
||||
msg2.addInt(_raceNumber);
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, msg, msg2);
|
||||
_raceNumber++;
|
||||
break;
|
||||
}
|
||||
case 1140: // 19 min
|
||||
{
|
||||
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, new DeleteObject(getMonsters()[0]), new DeleteObject(getMonsters()[1]), new DeleteObject(getMonsters()[2]), new DeleteObject(getMonsters()[3]), new DeleteObject(getMonsters()[4]), new DeleteObject(getMonsters()[5]), new DeleteObject(getMonsters()[6]), new DeleteObject(getMonsters()[7]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
_finalCountdown += 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void newRace()
|
||||
{
|
||||
// Edit _history.
|
||||
_history.add(new HistoryInfo(_raceNumber, 0, 0, 0));
|
||||
|
||||
// Randomize _npcTemplates.
|
||||
Collections.shuffle(_npcTemplates);
|
||||
|
||||
// Setup 8 new creatures ; pickup the first 8 from _npcTemplates.
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
final NpcTemplate template = NpcData.getInstance().getTemplate(_npcTemplates.get(i));
|
||||
_monsters[i] = (Npc) Class.forName("org.l2jmobius.gameserver.model.actor.instance." + template.getType() + "Instance").getConstructors()[0].newInstance(template);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void newSpeeds()
|
||||
{
|
||||
_speeds = new int[8][20];
|
||||
int total = 0;
|
||||
_first[1] = 0;
|
||||
_second[1] = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
total = 0;
|
||||
for (int j = 0; j < 20; j++)
|
||||
{
|
||||
if (j == 19)
|
||||
{
|
||||
_speeds[i][j] = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
_speeds[i][j] = Rnd.get(60) + 65;
|
||||
}
|
||||
total += _speeds[i][j];
|
||||
}
|
||||
|
||||
if (total >= _first[1])
|
||||
{
|
||||
_second[0] = _first[0];
|
||||
_second[1] = _first[1];
|
||||
_first[0] = 8 - i;
|
||||
_first[1] = total;
|
||||
}
|
||||
else if (total >= _second[1])
|
||||
{
|
||||
_second[0] = 8 - i;
|
||||
_second[1] = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load past races informations, feeding _history arrayList.<br>
|
||||
* Also sets _raceNumber, based on latest HistoryInfo loaded.
|
||||
*/
|
||||
protected void loadHistory()
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT * FROM mdt_history");
|
||||
ResultSet rset = statement.executeQuery();
|
||||
|
||||
while (rset.next())
|
||||
{
|
||||
_history.add(new HistoryInfo(rset.getInt("race_id"), rset.getInt("first"), rset.getInt("second"), rset.getDouble("odd_rate")));
|
||||
_raceNumber++;
|
||||
}
|
||||
rset.close();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "MonsterRace: Can't load history: " + e.getMessage(), e);
|
||||
}
|
||||
LOGGER.info("MonsterRace: loaded " + _history.size() + " records, currently on race #" + _raceNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an history record into database.
|
||||
* @param history The infos to store.
|
||||
*/
|
||||
protected void saveHistory(HistoryInfo history)
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("INSERT INTO mdt_history (race_id, first, second, odd_rate) VALUES (?,?,?,?)");
|
||||
statement.setInt(1, history.getRaceId());
|
||||
statement.setInt(2, history.getFirst());
|
||||
statement.setInt(3, history.getSecond());
|
||||
statement.setDouble(4, history.getOddRate());
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "MonsterRace: Can't save history: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load current bets per lane ; initialize the map keys.
|
||||
*/
|
||||
protected void loadBets()
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("SELECT * FROM mdt_bets");
|
||||
ResultSet rset = statement.executeQuery();
|
||||
|
||||
while (rset.next())
|
||||
{
|
||||
setBetOnLane(rset.getInt("lane_id"), rset.getLong("bet"), false);
|
||||
}
|
||||
|
||||
rset.close();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "MonsterRace: Can't load bets: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current lane bet into database.
|
||||
* @param lane : The lane to affect.
|
||||
* @param sum : The sum to set.
|
||||
*/
|
||||
protected void saveBet(int lane, long sum)
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("REPLACE INTO mdt_bets (lane_id, bet) VALUES (?,?)");
|
||||
statement.setInt(1, lane);
|
||||
statement.setLong(2, sum);
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "MonsterRace: Can't save bet: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all lanes bets, either on database or Map.
|
||||
*/
|
||||
protected void clearBets()
|
||||
{
|
||||
for (int key : _betsPerLane.keySet())
|
||||
{
|
||||
_betsPerLane.put(key, 0L);
|
||||
}
|
||||
|
||||
try (Connection con = DatabaseFactory.getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("UPDATE mdt_bets SET bet = 0");
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, "MonsterRace: Can't clear bets: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup lane bet, based on previous value (if any).
|
||||
* @param lane : The lane to edit.
|
||||
* @param amount : The amount to add.
|
||||
* @param saveOnDb : Should it be saved on db or not.
|
||||
*/
|
||||
public void setBetOnLane(int lane, long amount, boolean saveOnDb)
|
||||
{
|
||||
final long sum = (_betsPerLane.containsKey(lane)) ? _betsPerLane.get(lane) + amount : amount;
|
||||
|
||||
_betsPerLane.put(lane, sum);
|
||||
|
||||
if (saveOnDb)
|
||||
{
|
||||
saveBet(lane, sum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate odds for every lane, based on others lanes.
|
||||
*/
|
||||
protected void calculateOdds()
|
||||
{
|
||||
// Clear previous List holding old odds.
|
||||
_odds.clear();
|
||||
|
||||
// Sort bets lanes per lane.
|
||||
final Map<Integer, Long> sortedLanes = new TreeMap<>(_betsPerLane);
|
||||
|
||||
// Pass a first loop in order to calculate total sum of all lanes.
|
||||
long sumOfAllLanes = 0;
|
||||
for (long amount : sortedLanes.values())
|
||||
{
|
||||
sumOfAllLanes += amount;
|
||||
}
|
||||
|
||||
// As we get the sum, we can now calculate the odd rate of each lane.
|
||||
for (long amount : sortedLanes.values())
|
||||
{
|
||||
_odds.add((amount == 0) ? 0D : Math.max(1.25, (sumOfAllLanes * 0.7) / amount));
|
||||
}
|
||||
}
|
||||
|
||||
public Npc[] getMonsters()
|
||||
{
|
||||
return _monsters;
|
||||
}
|
||||
|
||||
public int[][] getSpeeds()
|
||||
{
|
||||
return _speeds;
|
||||
}
|
||||
|
||||
public int getFirstPlace()
|
||||
{
|
||||
return _first[0];
|
||||
}
|
||||
|
||||
public int getSecondPlace()
|
||||
{
|
||||
return _second[0];
|
||||
}
|
||||
|
||||
public MonRaceInfo getRacePacket()
|
||||
{
|
||||
return _packet;
|
||||
}
|
||||
|
||||
public RaceState getCurrentRaceState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
public int getRaceNumber()
|
||||
{
|
||||
return _raceNumber;
|
||||
}
|
||||
|
||||
public List<HistoryInfo> getHistory()
|
||||
{
|
||||
return _history;
|
||||
}
|
||||
|
||||
public List<Double> getOdds()
|
||||
{
|
||||
return _odds;
|
||||
}
|
||||
|
||||
public static MonsterRace getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final MonsterRace INSTANCE = new MonsterRace();
|
||||
}
|
||||
}
|
@ -16,69 +16,26 @@
|
||||
*/
|
||||
package org.l2jmobius.gameserver.model.actor.instance;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.l2jmobius.Config;
|
||||
import org.l2jmobius.commons.concurrent.ThreadPool;
|
||||
import org.l2jmobius.gameserver.MonsterRace;
|
||||
import org.l2jmobius.gameserver.enums.InstanceType;
|
||||
import org.l2jmobius.commons.util.StringUtil;
|
||||
import org.l2jmobius.gameserver.idfactory.IdFactory;
|
||||
import org.l2jmobius.gameserver.model.actor.Creature;
|
||||
import org.l2jmobius.gameserver.instancemanager.games.MonsterRace;
|
||||
import org.l2jmobius.gameserver.instancemanager.games.MonsterRace.HistoryInfo;
|
||||
import org.l2jmobius.gameserver.instancemanager.games.MonsterRace.RaceState;
|
||||
import org.l2jmobius.gameserver.model.actor.Npc;
|
||||
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
|
||||
import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
|
||||
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
|
||||
import org.l2jmobius.gameserver.network.SystemMessageId;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.DeleteObject;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.MonRaceInfo;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.PlaySound;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
|
||||
import org.l2jmobius.gameserver.util.Broadcast;
|
||||
|
||||
public class RaceManagerInstance extends Npc
|
||||
{
|
||||
public static final int LANES = 8;
|
||||
public static final int WINDOW_START = 0;
|
||||
|
||||
private static Collection<RaceManagerInstance> _managers;
|
||||
protected static int _raceNumber = 4;
|
||||
|
||||
// Time Constants
|
||||
private static final long SECOND = 1000;
|
||||
private static final long MINUTE = 60 * SECOND;
|
||||
|
||||
private static int _minutes = 5;
|
||||
|
||||
// States
|
||||
private static final int ACCEPTING_BETS = 0;
|
||||
private static final int WAITING = 1;
|
||||
private static final int STARTING_RACE = 2;
|
||||
private static final int RACE_END = 3;
|
||||
private static int _state = RACE_END;
|
||||
|
||||
protected static final int[][] _codes =
|
||||
{
|
||||
{
|
||||
-1,
|
||||
0
|
||||
},
|
||||
{
|
||||
0,
|
||||
15322
|
||||
},
|
||||
{
|
||||
13765,
|
||||
-1
|
||||
}
|
||||
};
|
||||
private static boolean _notInitialized = true;
|
||||
protected static MonRaceInfo _packet;
|
||||
protected static final int[] _cost =
|
||||
protected static final int TICKET_PRICES[] =
|
||||
{
|
||||
100,
|
||||
500,
|
||||
@ -93,223 +50,167 @@ public class RaceManagerInstance extends Npc
|
||||
public RaceManagerInstance(NpcTemplate template)
|
||||
{
|
||||
super(template);
|
||||
setInstanceType(InstanceType.RaceManagerInstance);
|
||||
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_notInitialized)
|
||||
{
|
||||
_notInitialized = false;
|
||||
|
||||
_managers = ConcurrentHashMap.newKeySet();
|
||||
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1), 0, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1), 30 * SECOND, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1), MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1), MINUTE + (30 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKET_SALES_FOR_MONSTER_RACE_S1_ARE_CLOSED), 2 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKET_SALES_FOR_MONSTER_RACE_S1_ARE_CLOSED), 3 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKET_SALES_FOR_MONSTER_RACE_S1_ARE_CLOSED), 4 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKET_SALES_FOR_MONSTER_RACE_S1_ARE_CLOSED), 5 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKET_SALES_FOR_MONSTER_RACE_S1_ARE_CLOSED), 6 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.TICKETS_SALES_ARE_CLOSED_FOR_MONSTER_RACE_S1_YOU_CAN_SEE_THE_AMOUNT_OF_WIN), 7 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_S1_MINUTE_S), 7 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_S1_MINUTE_S), 8 * MINUTE, 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_30_SECONDS), (8 * MINUTE) + (30 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSTER_RACE_S1_IS_ABOUT_TO_BEGIN_COUNTDOWN_IN_FIVE_SECONDS), (8 * MINUTE) + (50 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S), (8 * MINUTE) + (55 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S), (8 * MINUTE) + (56 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S), (8 * MINUTE) + (57 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S), (8 * MINUTE) + (58 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S), (8 * MINUTE) + (59 * SECOND), 10 * MINUTE);
|
||||
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.THEY_RE_OFF), 9 * MINUTE, 10 * MINUTE);
|
||||
}
|
||||
_managers.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoAttackable(Creature attacker)
|
||||
{
|
||||
if (attacker.isMonster())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.isAutoAttackable(attacker);
|
||||
}
|
||||
|
||||
class Announcement implements Runnable
|
||||
{
|
||||
private final SystemMessageId _type;
|
||||
|
||||
public Announcement(SystemMessageId pType)
|
||||
{
|
||||
_type = pType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
makeAnnouncement(_type);
|
||||
}
|
||||
}
|
||||
|
||||
public void makeAnnouncement(SystemMessageId type)
|
||||
{
|
||||
final SystemMessage sm = new SystemMessage(type);
|
||||
switch (type.getId())
|
||||
{
|
||||
case 816: // SystemMessageId.TICKETS_ARE_NOW_AVAILABLE_FOR_MONSTER_RACE_S1
|
||||
case 817: // SystemMessageId.NOW_SELLING_TICKETS_FOR_MONSTER_RACE_S1
|
||||
{
|
||||
if (_state != ACCEPTING_BETS)
|
||||
{// LOGGER.info("Race Initializing");
|
||||
_state = ACCEPTING_BETS;
|
||||
startRace();
|
||||
} // else{LOGGER.info("Race open");}
|
||||
sm.addInt(_raceNumber);
|
||||
break;
|
||||
}
|
||||
case 818: // SystemMessageId.TICKET_SALES_FOR_THE_MONSTER_RACE_WILL_END_IN_S1_MINUTE_S
|
||||
case 820: // SystemMessageId.MONSTER_RACE_S2_WILL_BEGIN_IN_S1_MINUTE_S
|
||||
case 823: // SystemMessageId.THE_RACE_WILL_BEGIN_IN_S1_SECOND_S
|
||||
{
|
||||
sm.addInt(_minutes);
|
||||
if (type.getId() == 820)
|
||||
{
|
||||
sm.addInt(_raceNumber);
|
||||
}
|
||||
_minutes--;
|
||||
break;
|
||||
}
|
||||
case 819: // SystemMessageId.TICKETS_SALES_ARE_CLOSED_FOR_MONSTER_RACE_S1_ODDS_ARE_POSTED
|
||||
{
|
||||
// LOGGER.info("Sales closed");
|
||||
sm.addInt(_raceNumber);
|
||||
_state = WAITING;
|
||||
_minutes = 2;
|
||||
break;
|
||||
}
|
||||
case 821: // SystemMessageId.MONSTER_RACE_S1_WILL_BEGIN_IN_30_SECONDS
|
||||
case 822: // SystemMessageId.MONSTER_RACE_S1_IS_ABOUT_TO_BEGIN_COUNTDOWN_IN_FIVE_SECONDS
|
||||
case 825: // SystemMessageId.MONSTER_RACE_S1_IS_FINISHED
|
||||
{
|
||||
sm.addInt(_raceNumber);
|
||||
_minutes = 5;
|
||||
break;
|
||||
}
|
||||
case 826: // SystemMessageId.FIRST_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S1_SECOND_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S2
|
||||
{
|
||||
// LOGGER.info("Placing");
|
||||
_state = RACE_END;
|
||||
sm.addInt(MonsterRace.getInstance().getFirstPlace());
|
||||
sm.addInt(MonsterRace.getInstance().getSecondPlace());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// _logn.info("Counter: "+minutes);
|
||||
// LOGGER.info("State: "+state);
|
||||
broadcast(sm);
|
||||
// LOGGER.info("Player's known: "+getKnownPlayers().size());
|
||||
|
||||
if (type == SystemMessageId.THEY_RE_OFF)
|
||||
{
|
||||
// LOGGER.info("Starting race");
|
||||
_state = STARTING_RACE;
|
||||
startRace();
|
||||
_minutes = 5;
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcast(IClientOutgoingPacket pkt)
|
||||
{
|
||||
for (RaceManagerInstance manager : _managers)
|
||||
{
|
||||
if (!manager.isDead())
|
||||
{
|
||||
Broadcast.toKnownPlayers(manager, pkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMonsterInfo()
|
||||
{
|
||||
broadcast(_packet);
|
||||
}
|
||||
|
||||
private void startRace()
|
||||
{
|
||||
final MonsterRace race = MonsterRace.getInstance();
|
||||
if (_state == STARTING_RACE)
|
||||
{
|
||||
// state++;
|
||||
broadcast(new PlaySound(1, "S_Race", 0, 0, 0, 0, 0));
|
||||
broadcast(new PlaySound(0, "ItemSound2.race_start", 1, 121209259, 12125, 182487, -3559));
|
||||
_packet = new MonRaceInfo(_codes[1][0], _codes[1][1], race.getMonsters(), race.getSpeeds());
|
||||
sendMonsterInfo();
|
||||
|
||||
ThreadPool.schedule(new RunRace(), 5000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// state++;
|
||||
race.newRace();
|
||||
race.newSpeeds();
|
||||
_packet = new MonRaceInfo(_codes[0][0], _codes[0][1], race.getMonsters(), race.getSpeeds());
|
||||
sendMonsterInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBypassFeedback(PlayerInstance player, String command)
|
||||
{
|
||||
if (command.startsWith("BuyTicket") && (_state != ACCEPTING_BETS))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.sendPacket(SystemMessageId.MONSTER_RACE_TICKETS_ARE_NO_LONGER_AVAILABLE);
|
||||
command = "Chat 0";
|
||||
}
|
||||
if (command.startsWith("ShowOdds") && (_state == ACCEPTING_BETS))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.sendPacket(SystemMessageId.MONSTER_RACE_PAYOUT_INFORMATION_IS_NOT_AVAILABLE_WHILE_TICKETS_ARE_BEING_SOLD);
|
||||
command = "Chat 0";
|
||||
}
|
||||
|
||||
if (command.startsWith("BuyTicket"))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
if (!Config.ALLOW_RACE || (MonsterRace.getInstance().getCurrentRaceState() != RaceState.ACCEPTING_BETS))
|
||||
{
|
||||
player.sendPacket(SystemMessageId.MONSTER_RACE_TICKETS_ARE_NO_LONGER_AVAILABLE);
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
int val = Integer.parseInt(command.substring(10));
|
||||
if (val == 0)
|
||||
{
|
||||
player.setRace(0, 0);
|
||||
player.setRace(1, 0);
|
||||
}
|
||||
|
||||
if (((val == 10) && (player.getRace(0) == 0)) || ((val == 20) && (player.getRace(0) == 0) && (player.getRace(1) == 0)))
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
showBuyTicket(player, val);
|
||||
|
||||
String search, replace;
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
|
||||
if (val < 10)
|
||||
{
|
||||
html.setFile(player, getHtmlPath(getId(), 2, player));
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int n = i + 1;
|
||||
search = "Mob" + n;
|
||||
html.replace(search, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
}
|
||||
search = "No1";
|
||||
if (val == 0)
|
||||
{
|
||||
html.replace(search, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
html.replace(search, val);
|
||||
player.setRace(0, val);
|
||||
}
|
||||
}
|
||||
else if (val < 20)
|
||||
{
|
||||
if (player.getRace(0) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
html.setFile(player, getHtmlPath(getId(), 3, player));
|
||||
html.replace("0place", player.getRace(0));
|
||||
search = "Mob1";
|
||||
replace = MonsterRace.getInstance().getMonsters()[player.getRace(0) - 1].getTemplate().getName();
|
||||
html.replace(search, replace);
|
||||
search = "0adena";
|
||||
|
||||
if (val == 10)
|
||||
{
|
||||
html.replace(search, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
html.replace(search, TICKET_PRICES[val - 11]);
|
||||
player.setRace(1, val - 10);
|
||||
}
|
||||
}
|
||||
else if (val == 20)
|
||||
{
|
||||
if ((player.getRace(0) == 0) || (player.getRace(1) == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
html.setFile(player, getHtmlPath(getId(), 4, player));
|
||||
html.replace("0place", player.getRace(0));
|
||||
search = "Mob1";
|
||||
replace = MonsterRace.getInstance().getMonsters()[player.getRace(0) - 1].getTemplate().getName();
|
||||
html.replace(search, replace);
|
||||
search = "0adena";
|
||||
int price = TICKET_PRICES[player.getRace(1) - 1];
|
||||
html.replace(search, price);
|
||||
search = "0tax";
|
||||
int tax = 0;
|
||||
html.replace(search, tax);
|
||||
search = "0total";
|
||||
int total = price + tax;
|
||||
html.replace(search, total);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((player.getRace(0) == 0) || (player.getRace(1) == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ticket = player.getRace(0);
|
||||
int priceId = player.getRace(1);
|
||||
|
||||
if (!player.reduceAdena("Race", TICKET_PRICES[priceId - 1], this, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
player.setRace(0, 0);
|
||||
player.setRace(1, 0);
|
||||
|
||||
ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443);
|
||||
item.setCount(1);
|
||||
item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber());
|
||||
item.setCustomType1(ticket);
|
||||
item.setCustomType2(TICKET_PRICES[priceId - 1] / 100);
|
||||
|
||||
player.addItem("Race", item, player, false);
|
||||
final SystemMessage msg = new SystemMessage(SystemMessageId.ACQUIRED_S1_S2);
|
||||
msg.addInt(MonsterRace.getInstance().getRaceNumber());
|
||||
msg.addItemName(4443);
|
||||
player.sendPacket(msg);
|
||||
|
||||
// Refresh lane bet.
|
||||
MonsterRace.getInstance().setBetOnLane(ticket, TICKET_PRICES[priceId - 1], true);
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
html.replace("1race", MonsterRace.getInstance().getRaceNumber());
|
||||
html.replace("%objectId%", getObjectId());
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else if (command.equals("ShowOdds"))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
if (!Config.ALLOW_RACE || (MonsterRace.getInstance().getCurrentRaceState() == RaceState.ACCEPTING_BETS))
|
||||
{
|
||||
player.sendPacket(SystemMessageId.MONSTER_RACE_PAYOUT_INFORMATION_IS_NOT_AVAILABLE_WHILE_TICKETS_ARE_BEING_SOLD);
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
showOdds(player);
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
html.setFile(player, getHtmlPath(getId(), 5, player));
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
final int n = i + 1;
|
||||
|
||||
html.replace("Mob" + n, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
|
||||
// Odd
|
||||
final double odd = MonsterRace.getInstance().getOdds().get(i);
|
||||
html.replace("Odd" + n, (odd > 0D) ? String.format(Locale.ENGLISH, "%.1f", odd) : "&$804;");
|
||||
}
|
||||
html.replace("1race", MonsterRace.getInstance().getRaceNumber());
|
||||
html.replace("%objectId%", getObjectId());
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else if (command.equals("ShowInfo"))
|
||||
{
|
||||
@ -317,269 +218,160 @@ public class RaceManagerInstance extends Npc
|
||||
{
|
||||
return;
|
||||
}
|
||||
showMonsterInfo(player);
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
html.setFile(player, getHtmlPath(getId(), 6, player));
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int n = i + 1;
|
||||
String search = "Mob" + n;
|
||||
html.replace(search, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
}
|
||||
html.replace("%objectId%", getObjectId());
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else if (command.equals("calculateWin"))
|
||||
else if (command.equals("ShowTickets"))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
// displayCalculateWinnings(player);
|
||||
|
||||
// Generate data.
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Retrieve player's tickets.
|
||||
for (ItemInstance ticket : player.getInventory().getAllItemsByItemId(4443))
|
||||
{
|
||||
// Don't list current race tickets.
|
||||
if (ticket.getEnchantLevel() == MonsterRace.getInstance().getRaceNumber())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
StringUtil.append(sb, "<tr><td><a action=\"bypass -h npc_%objectId%_ShowTicket ", "" + ticket.getObjectId(), "\">", "" + ticket.getEnchantLevel(), " Race Number</a></td><td align=right><font color=\"LEVEL\">", "" + ticket.getCustomType1(), "</font> Number</td><td align=right><font color=\"LEVEL\">", "" + (ticket.getCustomType2() * 100), "</font> Adena</td></tr>");
|
||||
}
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
html.setFile(player, getHtmlPath(getId(), 7, player));
|
||||
html.replace("%tickets%", sb.toString());
|
||||
html.replace("%objectId%", getObjectId());
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else if (command.equals("viewHistory"))
|
||||
else if (command.startsWith("ShowTicket"))
|
||||
{
|
||||
// Retrieve ticket objectId.
|
||||
final int val = Integer.parseInt(command.substring(11));
|
||||
if (!Config.ALLOW_RACE || (val == 0))
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve ticket on player's inventory.
|
||||
final ItemInstance ticket = player.getInventory().getItemByObjectId(val);
|
||||
if (ticket == null)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
final int raceId = ticket.getEnchantLevel();
|
||||
final int lane = ticket.getCustomType1();
|
||||
final int bet = ticket.getCustomType2() * 100;
|
||||
|
||||
// Retrieve HistoryInfo for that race.
|
||||
final HistoryInfo info = MonsterRace.getInstance().getHistory().get(raceId - 1);
|
||||
if (info == null)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
html.setFile(player, getHtmlPath(getId(), 8, player));
|
||||
html.replace("%raceId%", raceId);
|
||||
html.replace("%lane%", lane);
|
||||
html.replace("%bet%", bet);
|
||||
html.replace("%firstLane%", info.getFirst());
|
||||
html.replace("%odd%", (lane == info.getFirst()) ? String.format(Locale.ENGLISH, "%.2f", info.getOddRate()) : "0.01");
|
||||
html.replace("%objectId%", getObjectId());
|
||||
html.replace("%ticketObjectId%", val);
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else if (command.startsWith("CalculateWin"))
|
||||
{
|
||||
// Retrieve ticket objectId.
|
||||
final int val = Integer.parseInt(command.substring(13));
|
||||
if (!Config.ALLOW_RACE || (val == 0))
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete ticket on player's inventory.
|
||||
final ItemInstance ticket = player.getInventory().getItemByObjectId(val);
|
||||
if (ticket == null)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
final int raceId = ticket.getEnchantLevel();
|
||||
final int lane = ticket.getCustomType1();
|
||||
final int bet = ticket.getCustomType2() * 100;
|
||||
|
||||
// Retrieve HistoryInfo for that race.
|
||||
final HistoryInfo info = MonsterRace.getInstance().getHistory().get(raceId - 1);
|
||||
if (info == null)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Destroy the ticket.
|
||||
if (player.destroyItem("MonsterTrack", ticket, this, true))
|
||||
{
|
||||
player.addAdena("MonsterTrack", (int) (bet * ((lane == info.getFirst()) ? info.getOddRate() : 0.01)), this, true);
|
||||
}
|
||||
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
else if (command.equals("ViewHistory"))
|
||||
{
|
||||
if (!Config.ALLOW_RACE)
|
||||
{
|
||||
super.onBypassFeedback(player, "Chat 0");
|
||||
return;
|
||||
}
|
||||
// displayHistory(player);
|
||||
|
||||
// Generate data.
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Use whole history, pickup from 'last element' and stop at 'latest element - 7'.
|
||||
final List<HistoryInfo> history = MonsterRace.getInstance().getHistory();
|
||||
for (int i = history.size() - 1; i >= Math.max(0, history.size() - 7); i--)
|
||||
{
|
||||
final HistoryInfo info = history.get(i);
|
||||
StringUtil.append(sb, "<tr><td><font color=\"LEVEL\">", "" + info.getRaceId(), "</font> th</td><td><font color=\"LEVEL\">", "" + info.getFirst(), "</font> Lane </td><td><font color=\"LEVEL\">", "" + info.getSecond(), "</font> Lane</td><td align=right><font color=00ffff>", String.format(Locale.ENGLISH, "%.2f", info.getOddRate()), "</font> Times</td></tr>");
|
||||
}
|
||||
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
html.setFile(player, getHtmlPath(getId(), 9, player));
|
||||
html.replace("%infos%", sb.toString());
|
||||
html.replace("%objectId%", getObjectId());
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
else
|
||||
{
|
||||
// getKnownList().removeKnownObject(player);
|
||||
super.onBypassFeedback(player, command);
|
||||
}
|
||||
}
|
||||
|
||||
public void showOdds(PlayerInstance player)
|
||||
{
|
||||
if (_state == ACCEPTING_BETS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final int npcId = getTemplate().getId();
|
||||
String filename;
|
||||
String search;
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
filename = getHtmlPath(npcId, 5, player);
|
||||
html.setFile(player, filename);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
final int n = i + 1;
|
||||
search = "Mob" + n;
|
||||
html.replace(search, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
}
|
||||
html.replace("1race", String.valueOf(_raceNumber));
|
||||
html.replace("%objectId%", String.valueOf(getObjectId()));
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
|
||||
public void showMonsterInfo(PlayerInstance player)
|
||||
{
|
||||
final int npcId = getTemplate().getId();
|
||||
String filename;
|
||||
String search;
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
filename = getHtmlPath(npcId, 6, player);
|
||||
html.setFile(player, filename);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
final int n = i + 1;
|
||||
search = "Mob" + n;
|
||||
html.replace(search, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
}
|
||||
html.replace("%objectId%", String.valueOf(getObjectId()));
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
|
||||
public void showBuyTicket(PlayerInstance player, int value)
|
||||
{
|
||||
if (_state != ACCEPTING_BETS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final int npcId = getTemplate().getId();
|
||||
SystemMessage sm;
|
||||
String filename;
|
||||
String search;
|
||||
String replace;
|
||||
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
|
||||
if (value < 10)
|
||||
{
|
||||
filename = getHtmlPath(npcId, 2, player);
|
||||
html.setFile(player, filename);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
final int n = i + 1;
|
||||
search = "Mob" + n;
|
||||
html.replace(search, MonsterRace.getInstance().getMonsters()[i].getTemplate().getName());
|
||||
}
|
||||
search = "No1";
|
||||
if (value == 0)
|
||||
{
|
||||
html.replace(search, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
html.replace(search, Integer.toString(value));
|
||||
player.setRace(0, value);
|
||||
}
|
||||
}
|
||||
else if (value < 20)
|
||||
{
|
||||
if (player.getRace(0) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filename = getHtmlPath(npcId, 3, player);
|
||||
html.setFile(player, filename);
|
||||
html.replace("0place", Integer.toString(player.getRace(0)));
|
||||
search = "Mob1";
|
||||
replace = MonsterRace.getInstance().getMonsters()[player.getRace(0) - 1].getTemplate().getName();
|
||||
html.replace(search, replace);
|
||||
search = "0adena";
|
||||
if (value == 10)
|
||||
{
|
||||
html.replace(search, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
html.replace(search, Integer.toString(_cost[value - 11]));
|
||||
player.setRace(1, value - 10);
|
||||
}
|
||||
}
|
||||
else if (value == 20)
|
||||
{
|
||||
if ((player.getRace(0) == 0) || (player.getRace(1) == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
filename = getHtmlPath(npcId, 4, player);
|
||||
html.setFile(player, filename);
|
||||
html.replace("0place", Integer.toString(player.getRace(0)));
|
||||
search = "Mob1";
|
||||
replace = MonsterRace.getInstance().getMonsters()[player.getRace(0) - 1].getTemplate().getName();
|
||||
html.replace(search, replace);
|
||||
search = "0adena";
|
||||
final int price = _cost[player.getRace(1) - 1];
|
||||
html.replace(search, Integer.toString(price));
|
||||
search = "0tax";
|
||||
final int tax = 0;
|
||||
html.replace(search, Integer.toString(tax));
|
||||
search = "0total";
|
||||
final int total = price + tax;
|
||||
html.replace(search, Integer.toString(total));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((player.getRace(0) == 0) || (player.getRace(1) == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
final int ticket = player.getRace(0);
|
||||
final int priceId = player.getRace(1);
|
||||
if (!player.reduceAdena("Race", _cost[priceId - 1], this, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.setRace(0, 0);
|
||||
player.setRace(1, 0);
|
||||
sm = new SystemMessage(SystemMessageId.ACQUIRED_S1_S2);
|
||||
sm.addInt(_raceNumber);
|
||||
sm.addItemName(4443);
|
||||
player.sendPacket(sm);
|
||||
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443);
|
||||
item.setCount(1);
|
||||
item.setEnchantLevel(_raceNumber);
|
||||
item.setCustomType1(ticket);
|
||||
item.setCustomType2(_cost[priceId - 1] / 100);
|
||||
player.getInventory().addItem("Race", item, player, this);
|
||||
final InventoryUpdate iu = new InventoryUpdate();
|
||||
iu.addItem(item);
|
||||
final ItemInstance adenaupdate = player.getInventory().getItemByItemId(Inventory.ADENA_ID);
|
||||
iu.addModifiedItem(adenaupdate);
|
||||
player.sendInventoryUpdate(iu);
|
||||
return;
|
||||
}
|
||||
html.replace("1race", String.valueOf(_raceNumber));
|
||||
html.replace("%objectId%", String.valueOf(getObjectId()));
|
||||
player.sendPacket(html);
|
||||
player.sendPacket(ActionFailed.STATIC_PACKET);
|
||||
}
|
||||
|
||||
public static class Race
|
||||
{
|
||||
private final Info[] _info;
|
||||
|
||||
public Race(Info[] pInfo)
|
||||
{
|
||||
_info = pInfo;
|
||||
}
|
||||
|
||||
public Info getLaneInfo(int lane)
|
||||
{
|
||||
return _info[lane];
|
||||
}
|
||||
|
||||
public class Info
|
||||
{
|
||||
private final int _id;
|
||||
private final int _place;
|
||||
private final int _odds;
|
||||
private final int _payout;
|
||||
|
||||
public Info(int pId, int pPlace, int pOdds, int pPayout)
|
||||
{
|
||||
_id = pId;
|
||||
_place = pPlace;
|
||||
_odds = pOdds;
|
||||
_payout = pPayout;
|
||||
}
|
||||
|
||||
public int getId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public int getOdds()
|
||||
{
|
||||
return _odds;
|
||||
}
|
||||
|
||||
public int getPayout()
|
||||
{
|
||||
return _payout;
|
||||
}
|
||||
|
||||
public int getPlace()
|
||||
{
|
||||
return _place;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RunRace implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
_packet = new MonRaceInfo(_codes[2][0], _codes[2][1], MonsterRace.getInstance().getMonsters(), MonsterRace.getInstance().getSpeeds());
|
||||
sendMonsterInfo();
|
||||
ThreadPool.schedule(new RunEnd(), 30000);
|
||||
}
|
||||
}
|
||||
|
||||
class RunEnd implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
makeAnnouncement(SystemMessageId.FIRST_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S1_SECOND_PRIZE_GOES_TO_THE_PLAYER_IN_LANE_S2);
|
||||
makeAnnouncement(SystemMessageId.MONSTER_RACE_S1_IS_FINISHED);
|
||||
_raceNumber++;
|
||||
|
||||
DeleteObject obj = null;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
obj = new DeleteObject(MonsterRace.getInstance().getMonsters()[i]);
|
||||
broadcast(obj);
|
||||
MonsterRace.getInstance().getMonsters()[i].deleteMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,10 +20,12 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.l2jmobius.gameserver.enums.ChatType;
|
||||
import org.l2jmobius.gameserver.instancemanager.ZoneManager;
|
||||
import org.l2jmobius.gameserver.model.World;
|
||||
import org.l2jmobius.gameserver.model.actor.Creature;
|
||||
import org.l2jmobius.gameserver.model.actor.Summon;
|
||||
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
|
||||
import org.l2jmobius.gameserver.model.zone.ZoneType;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.CharInfo;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.CreatureSay;
|
||||
import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
|
||||
@ -191,4 +193,29 @@ public class Broadcast
|
||||
{
|
||||
toAllOnlinePlayers(new ExShowScreenMessage(text, 10000));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to all players in a specific zone type.
|
||||
* @param <T> ZoneType.
|
||||
* @param zoneType : The zone type to send packets.
|
||||
* @param packets : The packets to send.
|
||||
*/
|
||||
public static <T extends ZoneType> void toAllPlayersInZoneType(Class<T> zoneType, IClientOutgoingPacket... packets)
|
||||
{
|
||||
for (ZoneType zone : ZoneManager.getInstance().getAllZones(zoneType))
|
||||
{
|
||||
for (Creature creature : zone.getCharactersInside())
|
||||
{
|
||||
if (creature == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (IClientOutgoingPacket packet : packets)
|
||||
{
|
||||
creature.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user