Addition of Monster Race with reward system.

Adapted from aCis free version.
This commit is contained in:
MobiusDevelopment
2020-02-02 04:36:04 +00:00
parent 92ac8e59a7
commit 20a4e99da1
333 changed files with 22197 additions and 10208 deletions

View File

@@ -111,8 +111,8 @@ import org.l2jmobius.gameserver.instancemanager.SiegeManager;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.entity.Announcements;
import org.l2jmobius.gameserver.model.entity.Hero;
import org.l2jmobius.gameserver.model.entity.MonsterRace;
import org.l2jmobius.gameserver.model.entity.event.Lottery;
import org.l2jmobius.gameserver.model.entity.event.MonsterRace;
import org.l2jmobius.gameserver.model.entity.event.PcPoint;
import org.l2jmobius.gameserver.model.entity.event.manager.EventManager;
import org.l2jmobius.gameserver.model.entity.olympiad.Olympiad;

View File

@@ -63,7 +63,6 @@ import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminMassControl;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminMassRecall;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminMenu;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminMobGroup;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminMonsterRace;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminNoble;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminOnline;
import org.l2jmobius.gameserver.handler.admincommandhandlers.AdminPForge;
@@ -146,7 +145,6 @@ public class AdminCommandHandler
registerAdminCommandHandler(new AdminMassRecall());
registerAdminCommandHandler(new AdminMenu());
registerAdminCommandHandler(new AdminMobGroup());
registerAdminCommandHandler(new AdminMonsterRace());
registerAdminCommandHandler(new AdminNoble());
registerAdminCommandHandler(new AdminOnline());
registerAdminCommandHandler(new AdminPetition());

View File

@@ -1,163 +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.handler.admincommandhandlers;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.handler.IAdminCommandHandler;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.entity.MonsterRace;
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;
/**
* This class handles following admin commands: - invul = turns invulnerability on/off
* @version $Revision: 1.1.6.4 $ $Date: 2007/07/31 10:06:00 $
*/
public class AdminMonsterRace implements IAdminCommandHandler
{
private static final String[] ADMIN_COMMANDS =
{
"admin_mons"
};
protected static int state = -1;
@Override
public boolean useAdminCommand(String command, PlayerInstance activeChar)
{
if (command.equalsIgnoreCase("admin_mons"))
{
handleSendPacket(activeChar);
}
return true;
}
@Override
public String[] getAdminCommandList()
{
return ADMIN_COMMANDS;
}
private void handleSendPacket(PlayerInstance activeChar)
{
/*
* -1 0 to initialize the race 0 15322 to start race 13765 -1 in middle of race -1 0 to end the race 8003 to 8027
*/
final int[][] codes =
{
{
-1,
0
},
{
0,
15322
},
{
13765,
-1
},
{
-1,
0
}
};
final MonsterRace race = MonsterRace.getInstance();
if (state == -1)
{
state++;
race.newRace();
race.newSpeeds();
final MonRaceInfo spk = new MonRaceInfo(codes[state][0], codes[state][1], race.getMonsters(), race.getSpeeds());
activeChar.sendPacket(spk);
activeChar.broadcastPacket(spk);
}
else if (state == 0)
{
state++;
final SystemMessage sm = new SystemMessage(SystemMessageId.MONSRACE_RACE_START);
sm.addNumber(0);
activeChar.sendPacket(sm);
final PlaySound sRace = new PlaySound(1, "S_Race");
activeChar.sendPacket(sRace);
activeChar.broadcastPacket(sRace);
final PlaySound sRace2 = new PlaySound(0, "ItemSound2.race_start", true, 121209259, new Location(12125, 182487, -3559), 0);
activeChar.sendPacket(sRace2);
activeChar.broadcastPacket(sRace2);
final MonRaceInfo spk = new MonRaceInfo(codes[state][0], codes[state][1], race.getMonsters(), race.getSpeeds());
activeChar.sendPacket(spk);
activeChar.broadcastPacket(spk);
ThreadPool.schedule(new RunRace(codes, activeChar), 5000);
}
}
class RunRace implements Runnable
{
private final int[][] codes;
private final PlayerInstance activeChar;
public RunRace(int[][] pCodes, PlayerInstance pActiveChar)
{
codes = pCodes;
activeChar = pActiveChar;
}
@Override
public void run()
{
final MonRaceInfo spk = new MonRaceInfo(codes[2][0], codes[2][1], MonsterRace.getInstance().getMonsters(), MonsterRace.getInstance().getSpeeds());
activeChar.sendPacket(spk);
activeChar.broadcastPacket(spk);
ThreadPool.schedule(new RunEnd(activeChar), 30000);
}
}
class RunEnd implements Runnable
{
private final PlayerInstance activeChar;
public RunEnd(PlayerInstance pActiveChar)
{
activeChar = pActiveChar;
}
@Override
public void run()
{
DeleteObject obj = null;
for (int i = 0; i < 8; i++)
{
obj = new DeleteObject(MonsterRace.getInstance().getMonsters()[i]);
activeChar.sendPacket(obj);
activeChar.broadcastPacket(obj);
}
state = -1;
}
}
}

View File

@@ -1,530 +1,374 @@
/*
* 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.model.actor.instance;
import java.util.ArrayList;
import java.util.List;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.idfactory.IdFactory;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.actor.knownlist.RaceManagerKnownList;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
import org.l2jmobius.gameserver.model.entity.MonsterRace;
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.GameServerPacket;
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 NpcInstance
{
public static final int LANES = 8;
public static final int WINDOW_START = 0;
private static List<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 =
{
100,
500,
1000,
5000,
10000,
20000,
50000,
100000
};
public RaceManagerInstance(int objectId, NpcTemplate template)
{
super(objectId, template);
getKnownList(); // init knownlist
if (_notInitialized)
{
_notInitialized = false;
_managers = new ArrayList<>();
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_AVAILABLE_FOR_S1_RACE), 0, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE), 30 * SECOND, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_AVAILABLE_FOR_S1_RACE), MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE), MINUTE + (30 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES), 2 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES), 3 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES), 4 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES), 5 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES), 6 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_TICKET_SALES_CLOSED), 7 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_MINUTES), 7 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_MINUTES), 8 * MINUTE, 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_30_SECONDS), (8 * MINUTE) + (30 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_COUNTDOWN_IN_FIVE_SECONDS), (8 * MINUTE) + (50 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS), (8 * MINUTE) + (55 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS), (8 * MINUTE) + (56 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS), (8 * MINUTE) + (57 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS), (8 * MINUTE) + (58 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS), (8 * MINUTE) + (59 * SECOND), 10 * MINUTE);
ThreadPool.scheduleAtFixedRate(new Announcement(SystemMessageId.MONSRACE_RACE_START), 9 * MINUTE, 10 * MINUTE);
}
_managers.add(this);
}
@Override
public RaceManagerKnownList getKnownList()
{
if (!(super.getKnownList() instanceof RaceManagerKnownList))
{
setKnownList(new RaceManagerKnownList(this));
}
return (RaceManagerKnownList) super.getKnownList();
}
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.MONSRACE_TICKETS_AVAILABLE_FOR_S1_RACE
case 817: // SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE
{
if (_state != ACCEPTING_BETS)
{
_state = ACCEPTING_BETS;
startRace();
}
sm.addNumber(_raceNumber);
break;
}
case 818: // SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES
case 820: // SystemMessageId.MONSRACE_BEGINS_IN_S1_MINUTES
case 823: // SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS
{
sm.addNumber(_minutes);
sm.addNumber(_raceNumber);
_minutes--;
break;
}
case 819: // SystemMessageId.MONSRACE_TICKET_SALES_CLOSED
{
sm.addNumber(_raceNumber);
_state = WAITING;
_minutes = 2;
break;
}
case 822: // SystemMessageId.MONSRACE_COUNTDOWN_IN_FIVE_SECONDS
case 825: // SystemMessageId.MONSRACE_RACE_END
{
sm.addNumber(_raceNumber);
_minutes = 5;
break;
}
case 826: // SystemMessageId.MONSRACE_FIRST_PLACE_S1_SECOND_S2
{
_state = RACE_END;
sm.addNumber(MonsterRace.getInstance().getFirstPlace());
sm.addNumber(MonsterRace.getInstance().getSecondPlace());
break;
}
}
broadcast(sm);
if (type == SystemMessageId.MONSRACE_RACE_START)
{
_state = STARTING_RACE;
startRace();
_minutes = 5;
}
}
protected void broadcast(GameServerPacket 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)
{
broadcast(new PlaySound(1, "S_Race"));
broadcast(new PlaySound(0, "ItemSound2.race_start", true, 121209259, new Location(12125, 182487, -3559), 0));
_packet = new MonRaceInfo(_codes[1][0], _codes[1][1], race.getMonsters(), race.getSpeeds());
sendMonsterInfo();
ThreadPool.schedule(new RunRace(), 5000);
}
else
{
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))
{
player.sendPacket(SystemMessageId.MONSRACE_TICKETS_NOT_AVAILABLE);
command = "Chat 0";
}
if (command.startsWith("ShowOdds") && (_state == ACCEPTING_BETS))
{
player.sendPacket(SystemMessageId.MONSRACE_NO_PAYOUT_INFO);
command = "Chat 0";
}
if (command.startsWith("BuyTicket"))
{
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);
}
else if (command.equals("ShowOdds"))
{
showOdds(player);
}
else if (command.equals("ShowInfo"))
{
showMonsterInfo(player);
}
else if (command.equals("calculateWin"))
{
// displayCalculateWinnings(player);
}
else if (command.equals("viewHistory"))
{
// displayHistory(player);
}
else
{
super.onBypassFeedback(player, command);
}
}
public void showOdds(PlayerInstance player)
{
if (_state == ACCEPTING_BETS)
{
return;
}
final int npcId = getTemplate().getNpcId();
String filename;
String search;
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
filename = getHtmlPath(npcId, 5);
html.setFile(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().getNpcId();
String filename;
String search;
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
filename = getHtmlPath(npcId, 6);
html.setFile(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().getNpcId();
SystemMessage sm;
String filename;
String search;
String replace;
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
if (value < 10)
{
filename = getHtmlPath(npcId, 2);
html.setFile(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, "" + value);
player.setRace(0, value);
}
}
else if (value < 20)
{
if (player.getRace(0) == 0)
{
return;
}
filename = getHtmlPath(npcId, 3);
html.setFile(filename);
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 (value == 10)
{
html.replace(search, "");
}
else
{
html.replace(search, "" + _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);
html.setFile(filename);
html.replace("0place", "" + 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, "" + price);
search = "0tax";
final int tax = 0;
html.replace(search, "" + tax);
search = "0total";
final int total = price + tax;
html.replace(search, "" + 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);
sm.addNumber(_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(57);
iu.addModifiedItem(adenaupdate);
player.sendPacket(iu);
return;
}
html.replace("1race", String.valueOf(_raceNumber));
html.replace("%objectId%", String.valueOf(getObjectId()));
player.sendPacket(html);
player.sendPacket(ActionFailed.STATIC_PACKET);
}
public 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.MONSRACE_FIRST_PLACE_S1_SECOND_S2);
makeAnnouncement(SystemMessageId.MONSRACE_RACE_END);
_raceNumber++;
DeleteObject obj = null;
for (int i = 0; i < 8; i++)
{
obj = new DeleteObject(MonsterRace.getInstance().getMonsters()[i]);
broadcast(obj);
}
}
}
}
/*
* 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.model.actor.instance;
import java.util.List;
import java.util.Locale;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.StringUtil;
import org.l2jmobius.gameserver.idfactory.IdFactory;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
import org.l2jmobius.gameserver.model.entity.event.MonsterRace;
import org.l2jmobius.gameserver.model.entity.event.MonsterRace.HistoryInfo;
import org.l2jmobius.gameserver.model.entity.event.MonsterRace.RaceState;
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.NpcHtmlMessage;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public class RaceManagerInstance extends FolkInstance
{
protected static final int TICKET_PRICES[] =
{
100,
500,
1000,
5000,
10000,
20000,
50000,
100000
};
public RaceManagerInstance(int objectId, NpcTemplate template)
{
super(objectId, template);
}
@Override
public void onBypassFeedback(PlayerInstance player, String command)
{
if (command.startsWith("BuyTicket"))
{
if (!Config.ALLOW_RACE || (MonsterRace.getInstance().getCurrentRaceState() != RaceState.ACCEPTING_BETS))
{
player.sendPacket(SystemMessageId.MONSRACE_TICKETS_NOT_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;
}
int npcId = getTemplate().getNpcId();
String search, replace;
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
if (val < 10)
{
html.setFile(getHtmlPath(npcId, 2));
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(getHtmlPath(npcId, 3));
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(getHtmlPath(npcId, 4));
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);
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED).addNumber(MonsterRace.getInstance().getRaceNumber()).addItemName(4443));
// 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 || (MonsterRace.getInstance().getCurrentRaceState() == RaceState.ACCEPTING_BETS))
{
player.sendPacket(SystemMessageId.MONSRACE_NO_PAYOUT_INFO);
super.onBypassFeedback(player, "Chat 0");
return;
}
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
html.setFile(getHtmlPath(getTemplate().getNpcId(), 5));
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"))
{
if (!Config.ALLOW_RACE)
{
return;
}
final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
html.setFile(getHtmlPath(getTemplate().getNpcId(), 6));
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("ShowTickets"))
{
if (!Config.ALLOW_RACE)
{
super.onBypassFeedback(player, "Chat 0");
return;
}
// 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(getHtmlPath(getTemplate().getNpcId(), 7));
html.replace("%tickets%", sb.toString());
html.replace("%objectId%", getObjectId());
player.sendPacket(html);
player.sendPacket(ActionFailed.STATIC_PACKET);
}
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(getHtmlPath(getTemplate().getNpcId(), 8));
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;
}
// 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(getHtmlPath(getTemplate().getNpcId(), 9));
html.replace("%infos%", sb.toString());
html.replace("%objectId%", getObjectId());
player.sendPacket(html);
player.sendPacket(ActionFailed.STATIC_PACKET);
}
else
{
super.onBypassFeedback(player, command);
}
}
}

View File

@@ -19,7 +19,7 @@ package org.l2jmobius.gameserver.model.actor.knownlist;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.instance.RaceManagerInstance;
import org.l2jmobius.gameserver.model.entity.MonsterRace;
import org.l2jmobius.gameserver.model.entity.event.MonsterRace;
import org.l2jmobius.gameserver.network.serverpackets.DeleteObject;
public class RaceManagerKnownList extends NpcKnownList

View File

@@ -1,148 +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.model.entity;
import java.lang.reflect.Constructor;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.datatables.sql.NpcTable;
import org.l2jmobius.gameserver.idfactory.IdFactory;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
public class MonsterRace
{
private final NpcInstance[] _monsters;
private int[][] _speeds;
private final int[] _first;
private final int[] _second;
private MonsterRace()
{
_monsters = new NpcInstance[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().getNpcId() == (id + random))
{
random = Rnd.get(24);
}
}
break;
}
try
{
final NpcTemplate template = NpcTable.getInstance().getTemplate(id + random);
final Constructor<?> constructor = Class.forName("org.l2jmobius.gameserver.model.actor.instance." + template.getType() + "Instance").getConstructors()[0];
final int objectId = IdFactory.getInstance().getNextId();
_monsters[i] = (NpcInstance) constructor.newInstance(objectId, template);
}
catch (Exception e)
{
e.printStackTrace();
}
}
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++)
{
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;
}
}
}
/**
* @return Returns the monsters.
*/
public NpcInstance[] 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();
}
}

View File

@@ -0,0 +1,595 @@
/*
* 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.model.entity.event;
import java.lang.reflect.Constructor;
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.datatables.sql.NpcTable;
import org.l2jmobius.gameserver.idfactory.IdFactory;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
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");
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 Constructor<?> _constructor;
private final NpcInstance[] _monsters = new NpcInstance[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());
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, _packet, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber));
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
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber));
break;
}
case 300: // 5 min
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(10));
break;
}
case 600: // 10 min
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(5));
break;
}
case 840: // 14 min
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_STOP_IN_S1_MINUTES).addNumber(1));
break;
}
case 900: // 15 min
{
_state = RaceState.WAITING;
calculateOdds();
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_TICKETS_NOW_AVAILABLE_FOR_S1_RACE).addNumber(_raceNumber), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_TICKET_SALES_CLOSED).addNumber(_raceNumber));
break;
}
case 960: // 16 min
case 1020: // 17 min
{
final int minutes = (_finalCountdown == 960) ? 2 : 1;
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S2_BEGINS_IN_S1_MINUTES).addNumber(minutes).addNumber(_raceNumber));
break;
}
case 1050: // 17 min 30 sec
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_BEGINS_IN_30_SECONDS));
break;
}
case 1070: // 17 min 50 sec
{
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_COUNTDOWN_IN_FIVE_SECONDS));
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;
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_BEGINS_IN_S1_SECONDS).addNumber(seconds));
break;
}
case 1080: // 18 min
{
_state = RaceState.STARTING_RACE;
_packet = new MonRaceInfo(CODES[1][0], CODES[1][1], getMonsters(), getSpeeds());
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_RACE_START), 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();
Broadcast.toAllPlayersInZoneType(DerbyTrackZone.class, SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_FIRST_PLACE_S1_SECOND_S2).addNumber(getFirstPlace()).addNumber(getSecondPlace()), SystemMessage.getSystemMessage(SystemMessageId.MONSRACE_S1_RACE_END).addNumber(_raceNumber));
_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 = NpcTable.getInstance().getTemplate(_npcTemplates.get(i));
_constructor = Class.forName("org.l2jmobius.gameserver.model.actor.instance." + template.getType() + "Instance").getConstructors()[0];
final int objectId = IdFactory.getInstance().getNextId();
_monsters[i] = (NpcInstance) _constructor.newInstance(objectId, 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 NpcInstance[] 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();
}
}

View File

@@ -2177,25 +2177,25 @@ public enum SystemMessageId
* ID: 819<br>
* Message: Tickets sales are closed for Monster Race $s1. Odds are posted.
*/
MONSRACE_TICKET_SALES_CLOSED(819),
MONSRACE_S1_TICKET_SALES_CLOSED(819),
/**
* ID: 820<br>
* Message: Monster Race $s2 will begin in $s1 minute(s)!
*/
MONSRACE_BEGINS_IN_S1_MINUTES(820),
MONSRACE_S2_BEGINS_IN_S1_MINUTES(820),
/**
* ID: 821<br>
* Message: Monster Race $s1 will begin in 30 seconds!
*/
MONSRACE_BEGINS_IN_30_SECONDS(821),
MONSRACE_S1_BEGINS_IN_30_SECONDS(821),
/**
* ID: 822<br>
* Message: Monster Race $s1 is about to begin! Countdown in five seconds!
*/
MONSRACE_COUNTDOWN_IN_FIVE_SECONDS(822),
MONSRACE_S1_COUNTDOWN_IN_FIVE_SECONDS(822),
/**
* ID: 823<br>
@@ -2213,7 +2213,7 @@ public enum SystemMessageId
* ID: 825<br>
* Message: Monster Race $s1 is finished!
*/
MONSRACE_RACE_END(825),
MONSRACE_S1_RACE_END(825),
/**
* ID: 826<br>

View File

@@ -16,9 +16,11 @@
*/
package org.l2jmobius.gameserver.util;
import org.l2jmobius.gameserver.datatables.xml.ZoneData;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Creature;
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.GameServerPacket;
import org.l2jmobius.gameserver.network.serverpackets.RelationChanged;
@@ -180,4 +182,29 @@ public class Broadcast
onlinePlayer.sendPacket(packet);
}
}
/**
* 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, GameServerPacket... packets)
{
for (ZoneType zone : ZoneData.getInstance().getAllZones(zoneType))
{
for (Creature creature : zone.getCharactersInside().values())
{
if (creature == null)
{
continue;
}
for (GameServerPacket packet : packets)
{
creature.sendPacket(packet);
}
}
}
}
}