Replaced FeanorEventParser with LongTimeEvent.

This commit is contained in:
MobiusDevelopment
2022-01-28 22:35:35 +00:00
parent 36921fd4f8
commit 610d8c6aa1
46 changed files with 1692 additions and 1984 deletions

View File

@ -33,6 +33,16 @@ PlayerRateDropItem = 0
PlayerRateDropEquip = 0
PlayerRateDropEquipWeapon = 0
# ---------------------------------------------------------------------------
# Item Drop Level Difference Settings
# ---------------------------------------------------------------------------
# Allow event items drop within custom level range between character and monster.
# Default: 9
EventItemMaxLevelDifference = 9
# --------------------------------
# Karma Rates
# --------------------------------

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="event">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="droplist" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="unbounded" minOccurs="1">
<xs:complexType>
<xs:attribute name="item" type="xs:positiveInteger" use="required" />
<xs:attribute name="min" type="xs:positiveInteger" use="required" />
<xs:attribute name="max" type="xs:positiveInteger" use="required" />
<xs:attribute name="chance" type="xs:token" use="required" />
<xs:attribute name="minLevel" type="xs:positiveInteger" use="optional" />
<xs:attribute name="maxLevel" type="xs:positiveInteger" use="optional" />
<xs:attribute name="monsterIds" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="spawnlist" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="unbounded" minOccurs="1">
<xs:complexType>
<xs:attribute name="npc" type="xs:positiveInteger" use="required" />
<xs:attribute name="x" type="xs:integer" use="required" />
<xs:attribute name="y" type="xs:integer" use="required" />
<xs:attribute name="z" type="xs:integer" use="required" />
<xs:attribute name="heading" type="xs:integer" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="destroyItemsOnEnd" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="messages" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="2" minOccurs="2">
<xs:complexType>
<xs:attribute name="type" use="required">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="onEnd" />
<xs:enumeration value="onEnter" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="text" type="xs:token" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="active" type="xs:token" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -250,6 +250,7 @@ public class Config
public static int PLAYER_RATE_DROP_ITEM;
public static int PLAYER_RATE_DROP_EQUIP;
public static int PLAYER_RATE_DROP_EQUIP_WEAPON;
public static int EVENT_ITEM_MAX_LEVEL_DIFFERENCE;
public static float PET_XP_RATE;
public static int PET_FOOD_RATE;
public static float SINEATER_XP_RATE;
@ -1189,6 +1190,7 @@ public class Config
PLAYER_RATE_DROP_ITEM = ratesConfig.getInt("PlayerRateDropItem", 70);
PLAYER_RATE_DROP_EQUIP = ratesConfig.getInt("PlayerRateDropEquip", 25);
PLAYER_RATE_DROP_EQUIP_WEAPON = ratesConfig.getInt("PlayerRateDropEquipWeapon", 5);
EVENT_ITEM_MAX_LEVEL_DIFFERENCE = ratesConfig.getInt("EventItemMaxLevelDifference", 9);
PET_XP_RATE = ratesConfig.getFloat("PetXpRate", 1f);
PET_FOOD_RATE = ratesConfig.getInt("PetFoodRate", 1);
SINEATER_XP_RATE = ratesConfig.getFloat("SinEaterXpRate", 1f);

View File

@ -117,8 +117,6 @@ import org.l2jmobius.gameserver.model.siege.clanhalls.DevastatedCastle;
import org.l2jmobius.gameserver.model.siege.clanhalls.FortressOfResistance;
import org.l2jmobius.gameserver.model.spawn.AutoSpawnHandler;
import org.l2jmobius.gameserver.network.ClientNetworkManager;
import org.l2jmobius.gameserver.script.EventDroplist;
import org.l2jmobius.gameserver.script.faenor.FaenorScriptEngine;
import org.l2jmobius.gameserver.scripting.ScriptEngineManager;
import org.l2jmobius.gameserver.taskmanager.GameTimeTaskManager;
import org.l2jmobius.gameserver.taskmanager.ItemsAutoDestroyTaskManager;
@ -289,7 +287,6 @@ public class GameServer
printSection("Misc");
RecipeData.getInstance();
RecipeManager.getInstance();
EventDroplist.getInstance();
MonsterRace.getInstance();
Lottery.getInstance();
MercTicketManager.getInstance();
@ -364,7 +361,6 @@ public class GameServer
{
LOGGER.info("ScriptEngineManager: Loading server scripts:");
ScriptEngineManager.getInstance().executeScriptList();
FaenorScriptEngine.getInstance();
}
else
{

View File

@ -104,6 +104,7 @@ public class AnnouncementsTable
{
sendAnnouncements(player, AnnouncementType.NORMAL);
sendAnnouncements(player, AnnouncementType.CRITICAL);
sendAnnouncements(player, AnnouncementType.EVENT);
}
/**

View File

@ -0,0 +1,105 @@
/*
* 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;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
/**
* @author Mobius
*/
public class EventDropManager
{
private static final Map<LongTimeEvent, List<EventDropHolder>> EVENT_DROPS = new ConcurrentHashMap<>(1);
public void addDrops(LongTimeEvent longTimeEvent, List<EventDropHolder> dropList)
{
EVENT_DROPS.put(longTimeEvent, dropList);
}
public void removeDrops(LongTimeEvent longTimeEvent)
{
EVENT_DROPS.remove(longTimeEvent);
}
public void doEventDrop(Creature attacker, Attackable attackable)
{
if (EVENT_DROPS.isEmpty())
{
return;
}
// Event items drop only for players.
if ((attacker == null) || !attacker.isPlayable())
{
return;
}
// Event items drop only within a default 9 level difference.
final Player player = attacker.getActingPlayer();
if ((player.getLevel() - attackable.getLevel()) > Config.EVENT_ITEM_MAX_LEVEL_DIFFERENCE)
{
return;
}
for (List<EventDropHolder> eventDrops : EVENT_DROPS.values())
{
DROPS: for (EventDropHolder drop : eventDrops)
{
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(attackable.getNpcId()))
{
continue DROPS;
}
final int monsterLevel = attackable.getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final int itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT || attackable.isFlying())
{
player.doAutoLoot(attackable, new ItemHolder(itemId, itemCount)); // Give the item to the player that has killed the attackable.
}
else
{
attackable.dropItem(player, itemId, itemCount); // Drop the item on the ground.
}
}
}
}
}
public static EventDropManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final EventDropManager INSTANCE = new EventDropManager();
}
}

View File

@ -35,6 +35,7 @@ import org.l2jmobius.gameserver.data.ItemTable;
import org.l2jmobius.gameserver.data.xml.ManorSeedData;
import org.l2jmobius.gameserver.enums.AbsorbCrystalType;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.instancemanager.EventDropManager;
import org.l2jmobius.gameserver.model.CommandChannel;
import org.l2jmobius.gameserver.model.DropCategory;
import org.l2jmobius.gameserver.model.DropData;
@ -63,8 +64,6 @@ import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.script.EventDroplist;
import org.l2jmobius.gameserver.script.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.taskmanager.ItemsAutoDestroyTaskManager;
import org.l2jmobius.gameserver.util.Util;
@ -634,7 +633,8 @@ public class Attackable extends Npc
doItemDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker);
// Manage drop of Special Events created by GM for a defined period
doEventDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker);
EventDropManager.getInstance().doEventDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker, this);
if (!_mustGiveExpSp)
{
return;
@ -1872,69 +1872,6 @@ public class Attackable extends Npc
}
}
/**
* Manage Special Events drops created by GM for a defined period.<br>
* <br>
* <b><u>Concept</u>:</b><br>
* <br>
* During a Special Event all Attackable can drop extra Items. Those extra Items are defined in the table <b>allNpcDateDrops</b> of the EventDroplist. Each Special Event has a start and end date to stop to drop extra Items automaticaly.<br>
* <br>
* <b><u>Actions</u> : <i>If an extra drop must be generated</i></b><br>
* <li>Get an Item Identifier (random) from the DateDrop Item table of this Event</li>
* <li>Get the Item quantity dropped (random)</li>
* <li>Create this or these Item corresponding to this Item Identifier</li>
* <li>If the autoLoot mode is actif and if the Creature that has killed the Attackable is a Player, give this or these Item(s) to the Player that has killed the Attackable</li>
* <li>If the autoLoot mode isn't actif or if the Creature that has killed the Attackable is not a Player, add this or these Item(s) in the world as a visible object at the position where mob was last</li><br>
* @param lastAttacker The Creature that has killed the Attackable
*/
public void doEventDrop(Creature lastAttacker)
{
Player player = null;
if (lastAttacker instanceof Player)
{
player = (Player) lastAttacker;
}
else if (lastAttacker instanceof Summon)
{
player = ((Summon) lastAttacker).getOwner();
}
if (player == null)
{
return; // Don't drop anything if the last attacker or owner isn't Player
}
if ((player.getLevel() - getLevel()) > 9)
{
return;
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(DropData.MAX_CHANCE) < drop.chance)
{
final ItemHolder item = new ItemHolder(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
if (Config.AUTO_LOOT)
{
final ItemTemplate itemTemplate = ItemTable.getInstance().getTemplate(item.getId());
if (!player.getInventory().validateCapacity(itemTemplate))
{
dropItem(player, item);
}
else
{
player.doAutoLoot(this, item); // Give this or these Item(s) to the Player that has killed the Attackable
}
}
else
{
dropItem(player, item); // drop the item on the ground
}
}
}
}
/**
* Drop reward item.
* @param mainDamageDealer

View File

@ -26,6 +26,7 @@ public enum AnnouncementType
{
NORMAL,
CRITICAL,
EVENT,
AUTO_NORMAL,
AUTO_CRITICAL;

View File

@ -0,0 +1,106 @@
/*
* 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.announce;
import java.util.Date;
import org.l2jmobius.gameserver.instancemanager.IdManager;
import org.l2jmobius.gameserver.script.DateRange;
/**
* @author UnAfraid
*/
public class EventAnnouncement implements IAnnouncement
{
private final int _id;
private final DateRange _range;
private String _content;
public EventAnnouncement(DateRange range, String content)
{
_id = IdManager.getInstance().getNextId();
_range = range;
_content = content;
}
@Override
public int getId()
{
return _id;
}
@Override
public AnnouncementType getType()
{
return AnnouncementType.EVENT;
}
@Override
public void setType(AnnouncementType type)
{
throw new UnsupportedOperationException();
}
@Override
public boolean isValid()
{
return _range.isWithinRange(new Date());
}
@Override
public String getContent()
{
return _content;
}
@Override
public void setContent(String content)
{
_content = content;
}
@Override
public String getAuthor()
{
return "N/A";
}
@Override
public void setAuthor(String author)
{
throw new UnsupportedOperationException();
}
@Override
public boolean deleteMe()
{
IdManager.getInstance().releaseId(_id);
return true;
}
@Override
public boolean storeMe()
{
return true;
}
@Override
public boolean updateMe()
{
throw new UnsupportedOperationException();
}
}

View File

@ -14,43 +14,43 @@
* 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.script;
package org.l2jmobius.gameserver.model.holders;
/**
* @author Luis Arias
* @author Mobius
*/
public class IntList
public class DropHolder
{
public static int[] parse(String range)
private final int _itemId;
private final int _min;
private final int _max;
private final double _chance;
public DropHolder(int itemId, int min, int max, double chance)
{
if (range.contains("-"))
{
return getIntegerList(range.split("-"));
}
else if (range.contains(","))
{
return getIntegerList(range.split(","));
_itemId = itemId;
_min = min;
_max = max;
_chance = chance;
}
final int[] list =
public int getItemId()
{
getInt(range)
};
return list;
return _itemId;
}
private static int getInt(String number)
public int getMin()
{
return Integer.parseInt(number);
return _min;
}
private static int[] getIntegerList(String[] numbers)
public int getMax()
{
final int[] list = new int[numbers.length];
for (int i = 0; i < list.length; i++)
return _max;
}
public double getChance()
{
list[i] = getInt(numbers[i]);
}
return list;
return _chance;
}
}

View File

@ -14,43 +14,39 @@
* 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.script;
package org.l2jmobius.gameserver.model.holders;
import java.util.Collection;
/**
* @author -Nemesiss-
* @author Mobius
*/
public class ShortList
public class EventDropHolder extends DropHolder
{
public static short[] parse(String range)
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, int min, int max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
if (range.contains("-"))
{
return getShortList(range.split("-"));
}
else if (range.contains(","))
{
return getShortList(range.split(","));
super(itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
final short[] list =
public int getMinLevel()
{
getShort(range)
};
return list;
return _minLevel;
}
private static short getShort(String number)
public int getMaxLevel()
{
return Short.parseShort(number);
return _maxLevel;
}
private static short[] getShortList(String[] numbers)
public Collection<Integer> getMonsterIds()
{
final short[] list = new short[numbers.length];
for (int i = 0; i < list.length; i++)
{
list[i] = getShort(numbers[i]);
}
return list;
return _monsterIds;
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.holders;
/**
* A DTO for items; contains item ID, count and chance.<br>
* @author xban1x
*/
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
public ItemChanceHolder(int id, double chance)
{
this(id, chance, 1);
}
public ItemChanceHolder(int id, double chance, int count)
{
super(id, count);
_chance = chance;
}
/**
* Gets the chance.
* @return the drop chance of the item contained in this object
*/
public double getChance()
{
return _chance;
}
@Override
public String toString()
{
return "[" + getClass().getSimpleName() + "] ID: " + getId() + ", count: " + getCount() + ", chance: " + _chance;
}
}

View File

@ -0,0 +1,418 @@
/*
* 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.quest;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.gameserver.data.ItemTable;
import org.l2jmobius.gameserver.data.sql.AnnouncementsTable;
import org.l2jmobius.gameserver.data.sql.NpcTable;
import org.l2jmobius.gameserver.instancemanager.EventDropManager;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* Parent class for long time events.<br>
* Maintains config reading, spawn of NPCs, adding of event's drop.
* @author GKR
*/
public class LongTimeEvent extends Quest
{
protected String _eventName;
protected DateRange _eventPeriod = null;
protected boolean _active = false;
// Messages
protected String _onEnterMsg = "";
protected String _endMsg = "";
protected int _enterAnnounceId = -1;
// NPCs to spawm and their spawn points
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destroyItemsOnEnd = new ArrayList<>();
protected class NpcSpawn
{
protected final Location loc;
protected final int npcId;
protected NpcSpawn(int pNpcId, Location spawnLoc)
{
loc = spawnLoc;
npcId = pNpcId;
}
}
public LongTimeEvent()
{
super(-1, "events");
loadConfig();
if (_eventPeriod != null)
{
if (_eventPeriod.isWithinRange(new Date()))
{
startEvent();
LOGGER.info("Event " + _eventName + " active till " + _eventPeriod.getEndDate());
}
else if (_eventPeriod.getStartDate().after(new Date()))
{
final long delay = _eventPeriod.getStartDate().getTime() - Chronos.currentTimeMillis();
ThreadPool.schedule(new ScheduleStart(), delay);
LOGGER.info("Event " + _eventName + " will be started at " + _eventPeriod.getStartDate());
}
else
{
// Destroy items that must exist only on event period.
destroyItemsOnEnd();
LOGGER.info("Event " + _eventName + " has passed... Ignored ");
}
}
}
/**
* Load event configuration file
*/
private void loadConfig()
{
final File configFile = new File("data/scripts/events/" + getName() + "/config.xml");
try
{
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document doc = db.parse(configFile);
if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase("event"))
{
throw new NullPointerException("WARNING!!! " + getName() + " event: bad config file!");
}
_eventName = doc.getDocumentElement().getAttributes().getNamedItem("name").getNodeValue();
final String currentYear = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
final String period = doc.getDocumentElement().getAttributes().getNamedItem("active").getNodeValue();
if (period.length() == 21)
{
// dd MM yyyy-dd MM yyyy
_eventPeriod = DateRange.parse(period, new SimpleDateFormat("dd MM yyyy", Locale.US));
}
else if (period.length() == 11)
{
// dd MM-dd MM
final String start = period.split("-")[0].concat(" ").concat(currentYear);
final String end = period.split("-")[1].concat(" ").concat(currentYear);
final String activePeriod = start.concat("-").concat(end);
_eventPeriod = DateRange.parse(activePeriod, new SimpleDateFormat("dd MM yyyy", Locale.US));
}
if (_eventPeriod == null)
{
throw new NullPointerException("WARNING!!! " + getName() + " event: illegal event period");
}
final Date today = new Date();
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
try
{
final int itemId = Integer.parseInt(d.getAttributes().getNamedItem("item").getNodeValue());
final int minCount = Integer.parseInt(d.getAttributes().getNamedItem("min").getNodeValue());
final int maxCount = Integer.parseInt(d.getAttributes().getNamedItem("max").getNodeValue());
final String chance = d.getAttributes().getNamedItem("chance").getNodeValue();
final double finalChance = !chance.isEmpty() && chance.endsWith("%") ? Double.parseDouble(chance.substring(0, chance.length() - 1)) : 0;
final Node minLevelNode = d.getAttributes().getNamedItem("minLevel");
final int minLevel = minLevelNode == null ? 1 : Integer.parseInt(minLevelNode.getNodeValue());
final Node maxLevelNode = d.getAttributes().getNamedItem("maxLevel");
final int maxLevel = maxLevelNode == null ? Integer.MAX_VALUE : Integer.parseInt(maxLevelNode.getNodeValue());
final Node monsterIdsNode = d.getAttributes().getNamedItem("monsterIds");
final List<Integer> monsterIds = new ArrayList<>();
if (monsterIdsNode != null)
{
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.warning(getName() + " event: " + itemId + " is wrong item id, item was not added in droplist");
continue;
}
if (minCount > maxCount)
{
LOGGER.warning(getName() + " event: item " + itemId + " - min greater than max, item was not added in droplist");
continue;
}
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml droplist block for " + getName() + " event");
}
}
}
}
else if (n.getNodeName().equalsIgnoreCase("spawnlist"))
{
// Loading spawnlist
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
try
{
final int npcId = Integer.parseInt(d.getAttributes().getNamedItem("npc").getNodeValue());
final int xPos = Integer.parseInt(d.getAttributes().getNamedItem("x").getNodeValue());
final int yPos = Integer.parseInt(d.getAttributes().getNamedItem("y").getNodeValue());
final int zPos = Integer.parseInt(d.getAttributes().getNamedItem("z").getNodeValue());
final int heading = d.getAttributes().getNamedItem("heading").getNodeValue() != null ? Integer.parseInt(d.getAttributes().getNamedItem("heading").getNodeValue()) : 0;
if (NpcTable.getInstance().getTemplate(npcId) == null)
{
LOGGER.warning(getName() + " event: " + npcId + " is wrong NPC id, NPC was not added in spawnlist");
continue;
}
_spawnList.add(new NpcSpawn(npcId, new Location(xPos, yPos, zPos, heading)));
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml spawnlist block for " + getName() + " event");
}
}
}
}
else if (n.getNodeName().equalsIgnoreCase("messages"))
{
// Loading Messages
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
final String msgType = d.getAttributes().getNamedItem("type").getNodeValue();
final String msgText = d.getAttributes().getNamedItem("text").getNodeValue();
if ((msgType != null) && (msgText != null))
{
if (msgType.equalsIgnoreCase("onEnd"))
{
_endMsg = msgText;
}
else if (msgType.equalsIgnoreCase("onEnter"))
{
_onEnterMsg = msgText;
}
}
}
}
}
}
}
// Load destroy item list at all times.
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destroyItemsOnEnd"))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("item"))
{
try
{
final int itemId = Integer.parseInt(d.getAttributes().getNamedItem("id").getNodeValue());
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.warning(getName() + " event: Item " + itemId + " does not exist.");
continue;
}
_destroyItemsOnEnd.add(itemId);
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml destroyItemsOnEnd block for " + getName() + " event");
}
}
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getName() + " event: error reading " + configFile.getAbsolutePath() + " ! " + e.getMessage(), e);
}
}
protected class ScheduleStart implements Runnable
{
@Override
public void run()
{
startEvent();
}
}
protected void startEvent()
{
// Set Active.
_active = true;
// Add event drops.
EventDropManager.getInstance().addDrops(this, _dropList);
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - Chronos.currentTimeMillis();
for (NpcSpawn spawn : _spawnList)
{
addSpawn(spawn.npcId, spawn.loc.getX(), spawn.loc.getY(), spawn.loc.getZ(), spawn.loc.getHeading(), false, millisToEventEnd.intValue());
}
// Event enter announcement.
if (!_onEnterMsg.isEmpty())
{
// Send message on begin.
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// Add announce for entering players.
final EventAnnouncement announce = new EventAnnouncement(_eventPeriod, _onEnterMsg);
AnnouncementsTable.getInstance().addAnnouncement(announce);
_enterAnnounceId = announce.getId();
}
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
protected class ScheduleEnd implements Runnable
{
@Override
public void run()
{
stopEvent();
}
}
protected void stopEvent()
{
// Set Active.
_active = false;
// Stop event drops.
EventDropManager.getInstance().removeDrops(this);
// Destroy items that must exist only on event period.
destroyItemsOnEnd();
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
protected void destroyItemsOnEnd()
{
if (!_destroyItemsOnEnd.isEmpty())
{
for (int itemId : _destroyItemsOnEnd)
{
// Remove item from online players.
for (Player player : World.getInstance().getAllPlayers())
{
if (player != null)
{
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{
statement.setInt(1, itemId);
statement.execute();
}
catch (SQLException e)
{
LOGGER.warning(e.toString());
}
}
}
}
public DateRange getEventPeriod()
{
return _eventPeriod;
}
/**
* @return {@code true} if now is event period
*/
public boolean isEventPeriod()
{
return _active;
}
}

View File

@ -73,4 +73,10 @@ public class DateRange
{
return _startDate;
}
@Override
public String toString()
{
return "DateRange: From: " + _startDate + " To: " + _endDate;
}
}

View File

@ -1,101 +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.script;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* This class manage drop of Special Events created by GM for a defined period. During a Special Event all Attackable can drop extra Items. Those extra Items are defined in the table <b>allNpcDateDrops</b>. Each Special Event has a start and end date to stop to drop extra Items automaticaly.
*/
public class EventDroplist
{
/** The table containing all DataDrop object */
private final List<DateDrop> _allNpcDateDrops;
public class DateDrop
{
/** Start and end date of the Event */
public DateRange dateRange;
/** The table containing Item identifier that can be dropped as extra Items during the Event */
public int[] items;
/** The min number of Item dropped in one time during this Event */
public int min;
/** The max number of Item dropped in one time during this Event */
public int max;
/** The rate of drop for this Event */
public int chance;
}
/**
* Constructor of EventDroplist.
*/
protected EventDroplist()
{
_allNpcDateDrops = new ArrayList<>();
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param items The table containing all item identifier of this DateDrop
* @param count The table containing min and max value of this DateDrop
* @param chance The chance to obtain this drop
* @param range The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] items, int[] count, int chance, DateRange range)
{
final DateDrop date = new DateDrop();
date.dateRange = range;
date.items = items;
date.min = count[0];
date.max = count[1];
date.chance = chance;
_allNpcDateDrops.add(date);
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
{
final List<DateDrop> list = new ArrayList<>();
for (DateDrop drop : _allNpcDateDrops)
{
final Date currentDate = new Date();
if (drop.dateRange.isWithinRange(currentDate))
{
list.add(drop);
}
}
return list;
}
public static EventDroplist getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final EventDroplist INSTANCE = new EventDroplist();
}
}

View File

@ -19,26 +19,23 @@ package org.l2jmobius.gameserver.script;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.script.faenor.FaenorInterface;
/**
* @author Luis Arias
*/
public class ScriptEngine
{
protected EngineInterface _utils = FaenorInterface.getInstance();
public static final Map<String, ParserFactory> parserFactories = new HashMap<>();
public static final Map<String, ParserFactory> PARSER_FACTORIES = new HashMap<>();
protected static Parser createParser(String name) throws ParserNotCreatedException
{
ParserFactory s = parserFactories.get(name);
ParserFactory s = PARSER_FACTORIES.get(name);
if (s == null) // Shape not found.
{
try
{
Class.forName("org.l2jmobius.gameserver.script." + name);
// By now the static block with no function would have been executed if the shape was found. The shape is expected to have put its factory in the hashtable.
s = parserFactories.get(name);
s = PARSER_FACTORIES.get(name);
if (s == null) // If the shape factory is not there even now.
{
throw new ParserNotCreatedException();

View File

@ -1,122 +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.script;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* @author Luis Arias
*/
public class ScriptPackage
{
private final List<ScriptDocument> _scriptFiles;
private final List<String> _otherFiles;
private final String _name;
public ScriptPackage(ZipFile pack)
{
_scriptFiles = new ArrayList<>();
_otherFiles = new ArrayList<>();
_name = pack.getName();
addFiles(pack);
}
/**
* @return Returns the otherFiles.
*/
public List<String> getOtherFiles()
{
return _otherFiles;
}
/**
* @return Returns the scriptFiles.
*/
public List<ScriptDocument> getScriptFiles()
{
return _scriptFiles;
}
/**
* @param pack
*/
private void addFiles(ZipFile pack)
{
for (Enumeration<? extends ZipEntry> e = pack.entries(); e.hasMoreElements();)
{
final ZipEntry entry = e.nextElement();
if (entry.getName().endsWith(".xml"))
{
try
{
final ScriptDocument newScript = new ScriptDocument(entry.getName(), pack.getInputStream(entry));
_scriptFiles.add(newScript);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
else if (!entry.isDirectory())
{
_otherFiles.add(entry.getName());
}
}
}
/**
* @return Returns the name.
*/
public String getName()
{
return _name;
}
@Override
public String toString()
{
if (_scriptFiles.isEmpty() && _otherFiles.isEmpty())
{
return "Empty Package.";
}
String out = "Package Name: " + _name + "\n";
if (!_scriptFiles.isEmpty())
{
out += "Xml Script Files...\n";
for (ScriptDocument script : _scriptFiles)
{
out += script.getName() + "\n";
}
}
if (!_otherFiles.isEmpty())
{
out += "Other Files...\n";
for (String fileName : _otherFiles)
{
out += fileName + "\n";
}
}
return out;
}
}

View File

@ -1,137 +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.script.faenor;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.Config;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.IntList;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserFactory;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorEventParser extends FaenorParser
{
private static final Logger LOGGER = Logger.getLogger(FaenorEventParser.class.getName());
private DateRange _eventDates = null;
@Override
public void parseScript(Node eventNode, ScriptContext context)
{
final String id = attribute(eventNode, "ID");
_eventDates = DateRange.parse(attribute(eventNode, "Active"), DATE_FORMAT);
final Date currentDate = new Date();
if (_eventDates.getEndDate().before(currentDate))
{
LOGGER.info("Event ID: (" + id + ") has passed... Ignored.");
return;
}
if (_eventDates.getStartDate().after(currentDate))
{
LOGGER.info("Event ID: (" + id + ") is not active yet... Ignored.");
ThreadPool.schedule(() -> parseEventDropAndMessage(eventNode), _eventDates.getStartDate().getTime() - currentDate.getTime());
return;
}
parseEventDropAndMessage(eventNode);
}
protected void parseEventDropAndMessage(Node eventNode)
{
for (Node node = eventNode.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DropList"))
{
parseEventDropList(node);
}
else if (isNodeName(node, "Message"))
{
parseEventMessage(node);
}
}
}
private void parseEventMessage(Node sysMsg)
{
try
{
final String type = attribute(sysMsg, "Type");
final String[] message = attribute(sysMsg, "Msg").split(Config.EOL);
if (type.equalsIgnoreCase("OnJoin"))
{
_bridge.onPlayerLogin(message, _eventDates);
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error in event parser: " + e.getMessage());
}
}
private void parseEventDropList(Node dropList)
{
for (Node node = dropList.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "AllDrop"))
{
parseEventDrop(node);
}
}
}
private void parseEventDrop(Node drop)
{
try
{
final int[] items = IntList.parse(attribute(drop, "Items"));
final int[] count = IntList.parse(attribute(drop, "Count"));
final double chance = getPercent(attribute(drop, "Chance"));
_bridge.addEventDrop(items, count, chance, _eventDates);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "ERROR(parseEventDrop):" + e.getMessage());
}
}
static class FaenorEventParserFactory extends ParserFactory
{
@Override
public Parser create()
{
return (new FaenorEventParser());
}
}
static
{
ScriptEngine.parserFactories.put(getParserName("Event"), new FaenorEventParserFactory());
}
}

View File

@ -1,160 +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.script.faenor;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.l2jmobius.gameserver.data.sql.AnnouncementsTable;
import org.l2jmobius.gameserver.data.sql.NpcTable;
import org.l2jmobius.gameserver.model.DropCategory;
import org.l2jmobius.gameserver.model.DropData;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
import org.l2jmobius.gameserver.model.announce.Announcement;
import org.l2jmobius.gameserver.model.announce.AnnouncementType;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EngineInterface;
import org.l2jmobius.gameserver.script.EventDroplist;
/**
* @author Luis Arias
*/
public class FaenorInterface implements EngineInterface
{
protected static final Logger LOGGER = Logger.getLogger(FaenorInterface.class.getName());
public static FaenorInterface getInstance()
{
return SingletonHolder.INSTANCE;
}
public List<?> getAllPlayers()
{
return null;
}
/**
* Adds a new Quest Drop to an NPC
*/
@Override
public void addQuestDrop(int npcID, int itemID, int min, int max, int chance, String questID, String[] states)
{
final NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID);
if (npc == null)
{
throw new NullPointerException();
}
final DropData drop = new DropData();
drop.setItemId(itemID);
drop.setMinDrop(min);
drop.setMaxDrop(max);
drop.setChance(chance);
drop.setQuestID(questID);
drop.addStates(states);
addDrop(npc, drop, false);
}
/**
* Adds a new Drop to an NPC
* @param npcID
* @param itemID
* @param min
* @param max
* @param sweep
* @param chance
*/
public void addDrop(int npcID, int itemID, int min, int max, boolean sweep, int chance)
{
final NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID);
if (npc == null)
{
throw new NullPointerException();
}
final DropData drop = new DropData();
drop.setItemId(itemID);
drop.setMinDrop(min);
drop.setMaxDrop(max);
drop.setChance(chance);
addDrop(npc, drop, sweep);
}
/**
* Adds a new drop to an NPC. If the drop is sweep, it adds it to the NPC's Sweep category If the drop is non-sweep, it creates a new category for this drop.
* @param npc
* @param drop
* @param sweep
*/
public void addDrop(NpcTemplate npc, DropData drop, boolean sweep)
{
if (sweep)
{
addDrop(npc, drop, -1);
}
else
{
int maxCategory = -1;
if (npc.getDropData() != null)
{
for (DropCategory cat : npc.getDropData())
{
if (maxCategory < cat.getCategoryType())
{
maxCategory = cat.getCategoryType();
}
}
}
maxCategory++;
npc.addDropData(drop, maxCategory);
}
}
/**
* Adds a new drop to an NPC, in the specified category. If the category does not exist, it is created.
* @param npc
* @param drop
* @param category
*/
public void addDrop(NpcTemplate npc, DropData drop, int category)
{
npc.addDropData(drop, category);
}
@Override
public void addEventDrop(int[] items, int[] count, double chance, DateRange range)
{
EventDroplist.getInstance().addGlobalDrop(items, count, (int) (chance * 1000000), range);
}
@Override
public void onPlayerLogin(String[] message, DateRange validDateRange)
{
if (!validDateRange.isValid() || validDateRange.isWithinRange(new Date()))
{
for (String element : message)
{
AnnouncementsTable.getInstance().addAnnouncement(new Announcement(AnnouncementType.CRITICAL, element, ""), false);
}
}
}
private static class SingletonHolder
{
protected static final FaenorInterface INSTANCE = new FaenorInterface();
}
}

View File

@ -1,127 +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.script.faenor;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.l2jmobius.gameserver.script.Parser;
/**
* @author Luis Arias
*/
public abstract class FaenorParser extends Parser
{
protected static FaenorInterface _bridge = FaenorInterface.getInstance();
protected final DateFormat DATE_FORMAT = new SimpleDateFormat("dd MMM yyyy", Locale.US);
public static String attribute(Node node, String attributeName)
{
return attribute(node, attributeName, null);
}
public static String element(Node node, String elementName)
{
return element(node, elementName, null);
}
public static String attribute(Node node, String attributeName, String defaultValue)
{
try
{
return node.getAttributes().getNamedItem(attributeName).getNodeValue();
}
catch (Exception e)
{
if (defaultValue != null)
{
return defaultValue;
}
throw new NullPointerException(e.getMessage());
}
}
public static String element(Node parentNode, String elementName, String defaultValue)
{
try
{
final NodeList list = parentNode.getChildNodes();
for (int i = 0; i < list.getLength(); i++)
{
final Node node = list.item(i);
if (node.getNodeName().equalsIgnoreCase(elementName))
{
return node.getTextContent();
}
}
}
catch (Exception e)
{
}
if (defaultValue != null)
{
return defaultValue;
}
throw new NullPointerException();
}
public static boolean isNodeName(Node node, String name)
{
return node.getNodeName().equalsIgnoreCase(name);
}
public Date getDate(String date) throws ParseException
{
return DATE_FORMAT.parse(date);
}
public static double getPercent(String percent)
{
return (Double.parseDouble(percent.split("%")[0]) / 100.0);
}
protected static int getInt(String number)
{
return Integer.parseInt(number);
}
protected static double getDouble(String number)
{
return Double.parseDouble(number);
}
protected static float getFloat(String number)
{
return Float.parseFloat(number);
}
protected static String getParserName(String name)
{
return "faenor.Faenor" + name + "Parser";
}
@Override
public abstract void parseScript(Node node, ScriptContext context);
}

View File

@ -1,110 +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.script.faenor;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserFactory;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorQuestParser extends FaenorParser
{
protected static final Logger LOGGER = Logger.getLogger(FaenorQuestParser.class.getName());
@Override
public void parseScript(Node questNode, ScriptContext context)
{
final String questID = attribute(questNode, "ID");
for (Node node = questNode.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DROPLIST"))
{
parseQuestDropList(node.cloneNode(true), questID);
}
else if (isNodeName(node, "DIALOG WINDOWS"))
{
// parseDialogWindows(node.cloneNode(true));
}
else if (isNodeName(node, "INITIATOR"))
{
// parseInitiator(node.cloneNode(true));
}
else if (isNodeName(node, "STATE"))
{
// parseState(node.cloneNode(true));
}
}
}
private void parseQuestDropList(Node dropList, String questID)
{
for (Node node = dropList.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DROP"))
{
parseQuestDrop(node.cloneNode(true), questID);
}
}
}
private void parseQuestDrop(Node drop, String questID)
{
int npcID;
int itemID;
int min;
int max;
int chance;
String[] states;
try
{
npcID = getInt(attribute(drop, "NpcID"));
itemID = getInt(attribute(drop, "ItemID"));
min = getInt(attribute(drop, "Min"));
max = getInt(attribute(drop, "Max"));
chance = getInt(attribute(drop, "Chance"));
states = (attribute(drop, "States")).split(",");
}
catch (NullPointerException e)
{
throw new NullPointerException("Incorrect Drop Data");
}
_bridge.addQuestDrop(npcID, itemID, min, max, chance, questID, states);
}
static class FaenorQuestParserFactory extends ParserFactory
{
@Override
public Parser create()
{
return (new FaenorQuestParser());
}
}
static
{
ScriptEngine.parserFactories.put(getParserName("Quest"), new FaenorQuestParserFactory());
}
}

View File

@ -1,105 +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.script.faenor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.file.filter.XMLFilter;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserNotCreatedException;
import org.l2jmobius.gameserver.script.ScriptDocument;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorScriptEngine extends ScriptEngine
{
private static final Logger LOGGER = Logger.getLogger(FaenorScriptEngine.class.getName());
public static final String PACKAGE_DIRECTORY = "data/faenor/";
protected FaenorScriptEngine()
{
final File packDirectory = new File(Config.DATAPACK_ROOT, PACKAGE_DIRECTORY);
final File[] files = packDirectory.listFiles(new XMLFilter());
if (files != null)
{
for (File file : files)
{
try (InputStream in = new FileInputStream(file))
{
parseScript(new ScriptDocument(file.getName(), in), null);
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
}
}
}
public void parseScript(ScriptDocument script, ScriptContext context)
{
final Node node = script.getDocument().getFirstChild();
final String parserClass = "faenor.Faenor" + node.getNodeName() + "Parser";
Parser parser = null;
try
{
parser = createParser(parserClass);
}
catch (ParserNotCreatedException e)
{
LOGGER.log(Level.WARNING, "ERROR: No parser registered for Script: " + parserClass + ": " + e.getMessage());
}
if (parser == null)
{
LOGGER.warning("Unknown Script Type: " + script.getName());
return;
}
try
{
parser.parseScript(node, context);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + script.getName() + " successfully.");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Script Parsing Failed: " + e.getMessage());
}
}
public static FaenorScriptEngine getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final FaenorScriptEngine INSTANCE = new FaenorScriptEngine();
}
}

View File

@ -17,11 +17,13 @@
package org.l2jmobius.gameserver.util;
import org.l2jmobius.gameserver.data.xml.ZoneData;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Player;
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.IClientOutgoingPacket;
import org.l2jmobius.gameserver.network.serverpackets.RelationChanged;
@ -194,6 +196,16 @@ public class Broadcast
}
}
public static void toAllOnlinePlayers(String text)
{
toAllOnlinePlayers(text, false);
}
public static void toAllOnlinePlayers(String text, boolean isCritical)
{
toAllOnlinePlayers(new CreatureSay(0, isCritical ? ChatType.CRITICAL_ANNOUNCE : ChatType.ANNOUNCEMENT, null, text));
}
/**
* Send a packet to all players in a specific zone type.
* @param <T> ZoneType.

View File

@ -33,6 +33,16 @@ PlayerRateDropItem = 0
PlayerRateDropEquip = 0
PlayerRateDropEquipWeapon = 0
# ---------------------------------------------------------------------------
# Item Drop Level Difference Settings
# ---------------------------------------------------------------------------
# Allow event items drop within custom level range between character and monster.
# Default: 9
EventItemMaxLevelDifference = 9
# --------------------------------
# Karma Rates
# --------------------------------

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="event">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="droplist" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="unbounded" minOccurs="1">
<xs:complexType>
<xs:attribute name="item" type="xs:positiveInteger" use="required" />
<xs:attribute name="min" type="xs:positiveInteger" use="required" />
<xs:attribute name="max" type="xs:positiveInteger" use="required" />
<xs:attribute name="chance" type="xs:token" use="required" />
<xs:attribute name="minLevel" type="xs:positiveInteger" use="optional" />
<xs:attribute name="maxLevel" type="xs:positiveInteger" use="optional" />
<xs:attribute name="monsterIds" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="spawnlist" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="unbounded" minOccurs="1">
<xs:complexType>
<xs:attribute name="npc" type="xs:positiveInteger" use="required" />
<xs:attribute name="x" type="xs:integer" use="required" />
<xs:attribute name="y" type="xs:integer" use="required" />
<xs:attribute name="z" type="xs:integer" use="required" />
<xs:attribute name="heading" type="xs:integer" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="destroyItemsOnEnd" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="messages" maxOccurs="1" minOccurs="0">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="add" maxOccurs="2" minOccurs="2">
<xs:complexType>
<xs:attribute name="type" use="required">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="onEnd" />
<xs:enumeration value="onEnter" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="text" type="xs:token" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="active" type="xs:token" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -270,6 +270,7 @@ public class Config
public static int PLAYER_RATE_DROP_ITEM;
public static int PLAYER_RATE_DROP_EQUIP;
public static int PLAYER_RATE_DROP_EQUIP_WEAPON;
public static int EVENT_ITEM_MAX_LEVEL_DIFFERENCE;
public static float PET_XP_RATE;
public static int PET_FOOD_RATE;
public static float SINEATER_XP_RATE;
@ -1232,6 +1233,7 @@ public class Config
PLAYER_RATE_DROP_ITEM = ratesConfig.getInt("PlayerRateDropItem", 70);
PLAYER_RATE_DROP_EQUIP = ratesConfig.getInt("PlayerRateDropEquip", 25);
PLAYER_RATE_DROP_EQUIP_WEAPON = ratesConfig.getInt("PlayerRateDropEquipWeapon", 5);
EVENT_ITEM_MAX_LEVEL_DIFFERENCE = ratesConfig.getInt("EventItemMaxLevelDifference", 9);
PET_XP_RATE = ratesConfig.getFloat("PetXpRate", 1f);
PET_FOOD_RATE = ratesConfig.getInt("PetFoodRate", 1);
SINEATER_XP_RATE = ratesConfig.getFloat("SinEaterXpRate", 1f);

View File

@ -121,8 +121,6 @@ import org.l2jmobius.gameserver.model.siege.clanhalls.DevastatedCastle;
import org.l2jmobius.gameserver.model.siege.clanhalls.FortressOfResistance;
import org.l2jmobius.gameserver.model.spawn.AutoSpawnHandler;
import org.l2jmobius.gameserver.network.ClientNetworkManager;
import org.l2jmobius.gameserver.script.EventDroplist;
import org.l2jmobius.gameserver.script.faenor.FaenorScriptEngine;
import org.l2jmobius.gameserver.scripting.ScriptEngineManager;
import org.l2jmobius.gameserver.taskmanager.GameTimeTaskManager;
import org.l2jmobius.gameserver.taskmanager.ItemsAutoDestroyTaskManager;
@ -294,7 +292,6 @@ public class GameServer
printSection("Misc");
RecipeData.getInstance();
RecipeManager.getInstance();
EventDroplist.getInstance();
AugmentationData.getInstance();
MonsterRace.getInstance();
Lottery.getInstance();
@ -371,7 +368,6 @@ public class GameServer
{
LOGGER.info("ScriptEngineManager: Loading server scripts:");
ScriptEngineManager.getInstance().executeScriptList();
FaenorScriptEngine.getInstance();
}
else
{

View File

@ -104,6 +104,7 @@ public class AnnouncementsTable
{
sendAnnouncements(player, AnnouncementType.NORMAL);
sendAnnouncements(player, AnnouncementType.CRITICAL);
sendAnnouncements(player, AnnouncementType.EVENT);
}
/**

View File

@ -0,0 +1,105 @@
/*
* 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;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
/**
* @author Mobius
*/
public class EventDropManager
{
private static final Map<LongTimeEvent, List<EventDropHolder>> EVENT_DROPS = new ConcurrentHashMap<>(1);
public void addDrops(LongTimeEvent longTimeEvent, List<EventDropHolder> dropList)
{
EVENT_DROPS.put(longTimeEvent, dropList);
}
public void removeDrops(LongTimeEvent longTimeEvent)
{
EVENT_DROPS.remove(longTimeEvent);
}
public void doEventDrop(Creature attacker, Attackable attackable)
{
if (EVENT_DROPS.isEmpty())
{
return;
}
// Event items drop only for players.
if ((attacker == null) || !attacker.isPlayable())
{
return;
}
// Event items drop only within a default 9 level difference.
final Player player = attacker.getActingPlayer();
if ((player.getLevel() - attackable.getLevel()) > Config.EVENT_ITEM_MAX_LEVEL_DIFFERENCE)
{
return;
}
for (List<EventDropHolder> eventDrops : EVENT_DROPS.values())
{
DROPS: for (EventDropHolder drop : eventDrops)
{
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(attackable.getNpcId()))
{
continue DROPS;
}
final int monsterLevel = attackable.getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final int itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT || attackable.isFlying())
{
player.doAutoLoot(attackable, new ItemHolder(itemId, itemCount)); // Give the item to the player that has killed the attackable.
}
else
{
attackable.dropItem(player, itemId, itemCount); // Drop the item on the ground.
}
}
}
}
}
public static EventDropManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final EventDropManager INSTANCE = new EventDropManager();
}
}

View File

@ -36,6 +36,7 @@ import org.l2jmobius.gameserver.data.xml.ManorSeedData;
import org.l2jmobius.gameserver.enums.AbsorbCrystalType;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import org.l2jmobius.gameserver.instancemanager.EventDropManager;
import org.l2jmobius.gameserver.model.CommandChannel;
import org.l2jmobius.gameserver.model.DropCategory;
import org.l2jmobius.gameserver.model.DropData;
@ -64,8 +65,6 @@ import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.script.EventDroplist;
import org.l2jmobius.gameserver.script.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.taskmanager.ItemsAutoDestroyTaskManager;
import org.l2jmobius.gameserver.util.Util;
@ -635,7 +634,8 @@ public class Attackable extends Npc
doItemDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker);
// Manage drop of Special Events created by GM for a defined period
doEventDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker);
EventDropManager.getInstance().doEventDrop((maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker, this);
if (!_mustGiveExpSp)
{
return;
@ -2224,69 +2224,6 @@ public class Attackable extends Npc
}
}
/**
* Manage Special Events drops created by GM for a defined period.<br>
* <br>
* <b><u>Concept</u>:</b><br>
* <br>
* During a Special Event all Attackable can drop extra Items. Those extra Items are defined in the table <b>allNpcDateDrops</b> of the EventDroplist. Each Special Event has a start and end date to stop to drop extra Items automaticaly.<br>
* <br>
* <b><u>Actions</u> : <i>If an extra drop must be generated</i></b><br>
* <li>Get an Item Identifier (random) from the DateDrop Item table of this Event</li>
* <li>Get the Item quantity dropped (random)</li>
* <li>Create this or these Item corresponding to this Item Identifier</li>
* <li>If the autoLoot mode is actif and if the Creature that has killed the Attackable is a Player, give this or these Item(s) to the Player that has killed the Attackable</li>
* <li>If the autoLoot mode isn't actif or if the Creature that has killed the Attackable is not a Player, add this or these Item(s) in the world as a visible object at the position where mob was last</li><br>
* @param lastAttacker The Creature that has killed the Attackable
*/
public void doEventDrop(Creature lastAttacker)
{
Player player = null;
if (lastAttacker instanceof Player)
{
player = (Player) lastAttacker;
}
else if (lastAttacker instanceof Summon)
{
player = ((Summon) lastAttacker).getOwner();
}
if (player == null)
{
return; // Don't drop anything if the last attacker or owner isn't Player
}
if ((player.getLevel() - getLevel()) > 9)
{
return;
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(DropData.MAX_CHANCE) < drop.chance)
{
final ItemHolder item = new ItemHolder(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
if (Config.AUTO_LOOT)
{
final ItemTemplate itemTemplate = ItemTable.getInstance().getTemplate(item.getId());
if (!player.getInventory().validateCapacity(itemTemplate))
{
dropItem(player, item);
}
else
{
player.doAutoLoot(this, item); // Give this or these Item(s) to the Player that has killed the Attackable
}
}
else
{
dropItem(player, item); // drop the item on the ground
}
}
}
}
/**
* Drop reward item.
* @param mainDamageDealer

View File

@ -26,6 +26,7 @@ public enum AnnouncementType
{
NORMAL,
CRITICAL,
EVENT,
AUTO_NORMAL,
AUTO_CRITICAL;

View File

@ -0,0 +1,106 @@
/*
* 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.announce;
import java.util.Date;
import org.l2jmobius.gameserver.instancemanager.IdManager;
import org.l2jmobius.gameserver.script.DateRange;
/**
* @author UnAfraid
*/
public class EventAnnouncement implements IAnnouncement
{
private final int _id;
private final DateRange _range;
private String _content;
public EventAnnouncement(DateRange range, String content)
{
_id = IdManager.getInstance().getNextId();
_range = range;
_content = content;
}
@Override
public int getId()
{
return _id;
}
@Override
public AnnouncementType getType()
{
return AnnouncementType.EVENT;
}
@Override
public void setType(AnnouncementType type)
{
throw new UnsupportedOperationException();
}
@Override
public boolean isValid()
{
return _range.isWithinRange(new Date());
}
@Override
public String getContent()
{
return _content;
}
@Override
public void setContent(String content)
{
_content = content;
}
@Override
public String getAuthor()
{
return "N/A";
}
@Override
public void setAuthor(String author)
{
throw new UnsupportedOperationException();
}
@Override
public boolean deleteMe()
{
IdManager.getInstance().releaseId(_id);
return true;
}
@Override
public boolean storeMe()
{
return true;
}
@Override
public boolean updateMe()
{
throw new UnsupportedOperationException();
}
}

View File

@ -14,43 +14,43 @@
* 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.script;
package org.l2jmobius.gameserver.model.holders;
/**
* @author Luis Arias
* @author Mobius
*/
public class IntList
public class DropHolder
{
public static int[] parse(String range)
private final int _itemId;
private final int _min;
private final int _max;
private final double _chance;
public DropHolder(int itemId, int min, int max, double chance)
{
if (range.contains("-"))
{
return getIntegerList(range.split("-"));
}
else if (range.contains(","))
{
return getIntegerList(range.split(","));
_itemId = itemId;
_min = min;
_max = max;
_chance = chance;
}
final int[] list =
public int getItemId()
{
getInt(range)
};
return list;
return _itemId;
}
private static int getInt(String number)
public int getMin()
{
return Integer.parseInt(number);
return _min;
}
private static int[] getIntegerList(String[] numbers)
public int getMax()
{
final int[] list = new int[numbers.length];
for (int i = 0; i < list.length; i++)
return _max;
}
public double getChance()
{
list[i] = getInt(numbers[i]);
}
return list;
return _chance;
}
}

View File

@ -14,43 +14,39 @@
* 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.script;
package org.l2jmobius.gameserver.model.holders;
import java.util.Collection;
/**
* @author -Nemesiss-
* @author Mobius
*/
public class ShortList
public class EventDropHolder extends DropHolder
{
public static short[] parse(String range)
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, int min, int max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
if (range.contains("-"))
{
return getShortList(range.split("-"));
}
else if (range.contains(","))
{
return getShortList(range.split(","));
super(itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
final short[] list =
public int getMinLevel()
{
getShort(range)
};
return list;
return _minLevel;
}
private static short getShort(String number)
public int getMaxLevel()
{
return Short.parseShort(number);
return _maxLevel;
}
private static short[] getShortList(String[] numbers)
public Collection<Integer> getMonsterIds()
{
final short[] list = new short[numbers.length];
for (int i = 0; i < list.length; i++)
{
list[i] = getShort(numbers[i]);
}
return list;
return _monsterIds;
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.holders;
/**
* A DTO for items; contains item ID, count and chance.<br>
* @author xban1x
*/
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
public ItemChanceHolder(int id, double chance)
{
this(id, chance, 1);
}
public ItemChanceHolder(int id, double chance, int count)
{
super(id, count);
_chance = chance;
}
/**
* Gets the chance.
* @return the drop chance of the item contained in this object
*/
public double getChance()
{
return _chance;
}
@Override
public String toString()
{
return "[" + getClass().getSimpleName() + "] ID: " + getId() + ", count: " + getCount() + ", chance: " + _chance;
}
}

View File

@ -0,0 +1,418 @@
/*
* 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.quest;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.gameserver.data.ItemTable;
import org.l2jmobius.gameserver.data.sql.AnnouncementsTable;
import org.l2jmobius.gameserver.data.sql.NpcTable;
import org.l2jmobius.gameserver.instancemanager.EventDropManager;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* Parent class for long time events.<br>
* Maintains config reading, spawn of NPCs, adding of event's drop.
* @author GKR
*/
public class LongTimeEvent extends Quest
{
protected String _eventName;
protected DateRange _eventPeriod = null;
protected boolean _active = false;
// Messages
protected String _onEnterMsg = "";
protected String _endMsg = "";
protected int _enterAnnounceId = -1;
// NPCs to spawm and their spawn points
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destroyItemsOnEnd = new ArrayList<>();
protected class NpcSpawn
{
protected final Location loc;
protected final int npcId;
protected NpcSpawn(int pNpcId, Location spawnLoc)
{
loc = spawnLoc;
npcId = pNpcId;
}
}
public LongTimeEvent()
{
super(-1, "events");
loadConfig();
if (_eventPeriod != null)
{
if (_eventPeriod.isWithinRange(new Date()))
{
startEvent();
LOGGER.info("Event " + _eventName + " active till " + _eventPeriod.getEndDate());
}
else if (_eventPeriod.getStartDate().after(new Date()))
{
final long delay = _eventPeriod.getStartDate().getTime() - Chronos.currentTimeMillis();
ThreadPool.schedule(new ScheduleStart(), delay);
LOGGER.info("Event " + _eventName + " will be started at " + _eventPeriod.getStartDate());
}
else
{
// Destroy items that must exist only on event period.
destroyItemsOnEnd();
LOGGER.info("Event " + _eventName + " has passed... Ignored ");
}
}
}
/**
* Load event configuration file
*/
private void loadConfig()
{
final File configFile = new File("data/scripts/events/" + getName() + "/config.xml");
try
{
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document doc = db.parse(configFile);
if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase("event"))
{
throw new NullPointerException("WARNING!!! " + getName() + " event: bad config file!");
}
_eventName = doc.getDocumentElement().getAttributes().getNamedItem("name").getNodeValue();
final String currentYear = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
final String period = doc.getDocumentElement().getAttributes().getNamedItem("active").getNodeValue();
if (period.length() == 21)
{
// dd MM yyyy-dd MM yyyy
_eventPeriod = DateRange.parse(period, new SimpleDateFormat("dd MM yyyy", Locale.US));
}
else if (period.length() == 11)
{
// dd MM-dd MM
final String start = period.split("-")[0].concat(" ").concat(currentYear);
final String end = period.split("-")[1].concat(" ").concat(currentYear);
final String activePeriod = start.concat("-").concat(end);
_eventPeriod = DateRange.parse(activePeriod, new SimpleDateFormat("dd MM yyyy", Locale.US));
}
if (_eventPeriod == null)
{
throw new NullPointerException("WARNING!!! " + getName() + " event: illegal event period");
}
final Date today = new Date();
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
try
{
final int itemId = Integer.parseInt(d.getAttributes().getNamedItem("item").getNodeValue());
final int minCount = Integer.parseInt(d.getAttributes().getNamedItem("min").getNodeValue());
final int maxCount = Integer.parseInt(d.getAttributes().getNamedItem("max").getNodeValue());
final String chance = d.getAttributes().getNamedItem("chance").getNodeValue();
final double finalChance = !chance.isEmpty() && chance.endsWith("%") ? Double.parseDouble(chance.substring(0, chance.length() - 1)) : 0;
final Node minLevelNode = d.getAttributes().getNamedItem("minLevel");
final int minLevel = minLevelNode == null ? 1 : Integer.parseInt(minLevelNode.getNodeValue());
final Node maxLevelNode = d.getAttributes().getNamedItem("maxLevel");
final int maxLevel = maxLevelNode == null ? Integer.MAX_VALUE : Integer.parseInt(maxLevelNode.getNodeValue());
final Node monsterIdsNode = d.getAttributes().getNamedItem("monsterIds");
final List<Integer> monsterIds = new ArrayList<>();
if (monsterIdsNode != null)
{
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.warning(getName() + " event: " + itemId + " is wrong item id, item was not added in droplist");
continue;
}
if (minCount > maxCount)
{
LOGGER.warning(getName() + " event: item " + itemId + " - min greater than max, item was not added in droplist");
continue;
}
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml droplist block for " + getName() + " event");
}
}
}
}
else if (n.getNodeName().equalsIgnoreCase("spawnlist"))
{
// Loading spawnlist
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
try
{
final int npcId = Integer.parseInt(d.getAttributes().getNamedItem("npc").getNodeValue());
final int xPos = Integer.parseInt(d.getAttributes().getNamedItem("x").getNodeValue());
final int yPos = Integer.parseInt(d.getAttributes().getNamedItem("y").getNodeValue());
final int zPos = Integer.parseInt(d.getAttributes().getNamedItem("z").getNodeValue());
final int heading = d.getAttributes().getNamedItem("heading").getNodeValue() != null ? Integer.parseInt(d.getAttributes().getNamedItem("heading").getNodeValue()) : 0;
if (NpcTable.getInstance().getTemplate(npcId) == null)
{
LOGGER.warning(getName() + " event: " + npcId + " is wrong NPC id, NPC was not added in spawnlist");
continue;
}
_spawnList.add(new NpcSpawn(npcId, new Location(xPos, yPos, zPos, heading)));
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml spawnlist block for " + getName() + " event");
}
}
}
}
else if (n.getNodeName().equalsIgnoreCase("messages"))
{
// Loading Messages
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("add"))
{
final String msgType = d.getAttributes().getNamedItem("type").getNodeValue();
final String msgText = d.getAttributes().getNamedItem("text").getNodeValue();
if ((msgType != null) && (msgText != null))
{
if (msgType.equalsIgnoreCase("onEnd"))
{
_endMsg = msgText;
}
else if (msgType.equalsIgnoreCase("onEnter"))
{
_onEnterMsg = msgText;
}
}
}
}
}
}
}
// Load destroy item list at all times.
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destroyItemsOnEnd"))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equalsIgnoreCase("item"))
{
try
{
final int itemId = Integer.parseInt(d.getAttributes().getNamedItem("id").getNodeValue());
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.warning(getName() + " event: Item " + itemId + " does not exist.");
continue;
}
_destroyItemsOnEnd.add(itemId);
}
catch (NumberFormatException nfe)
{
LOGGER.warning("Wrong number format in config.xml destroyItemsOnEnd block for " + getName() + " event");
}
}
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getName() + " event: error reading " + configFile.getAbsolutePath() + " ! " + e.getMessage(), e);
}
}
protected class ScheduleStart implements Runnable
{
@Override
public void run()
{
startEvent();
}
}
protected void startEvent()
{
// Set Active.
_active = true;
// Add event drops.
EventDropManager.getInstance().addDrops(this, _dropList);
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - Chronos.currentTimeMillis();
for (NpcSpawn spawn : _spawnList)
{
addSpawn(spawn.npcId, spawn.loc.getX(), spawn.loc.getY(), spawn.loc.getZ(), spawn.loc.getHeading(), false, millisToEventEnd.intValue());
}
// Event enter announcement.
if (!_onEnterMsg.isEmpty())
{
// Send message on begin.
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// Add announce for entering players.
final EventAnnouncement announce = new EventAnnouncement(_eventPeriod, _onEnterMsg);
AnnouncementsTable.getInstance().addAnnouncement(announce);
_enterAnnounceId = announce.getId();
}
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
protected class ScheduleEnd implements Runnable
{
@Override
public void run()
{
stopEvent();
}
}
protected void stopEvent()
{
// Set Active.
_active = false;
// Stop event drops.
EventDropManager.getInstance().removeDrops(this);
// Destroy items that must exist only on event period.
destroyItemsOnEnd();
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
protected void destroyItemsOnEnd()
{
if (!_destroyItemsOnEnd.isEmpty())
{
for (int itemId : _destroyItemsOnEnd)
{
// Remove item from online players.
for (Player player : World.getInstance().getAllPlayers())
{
if (player != null)
{
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{
statement.setInt(1, itemId);
statement.execute();
}
catch (SQLException e)
{
LOGGER.warning(e.toString());
}
}
}
}
public DateRange getEventPeriod()
{
return _eventPeriod;
}
/**
* @return {@code true} if now is event period
*/
public boolean isEventPeriod()
{
return _active;
}
}

View File

@ -73,4 +73,10 @@ public class DateRange
{
return _startDate;
}
@Override
public String toString()
{
return "DateRange: From: " + _startDate + " To: " + _endDate;
}
}

View File

@ -1,101 +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.script;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* This class manage drop of Special Events created by GM for a defined period. During a Special Event all Attackable can drop extra Items. Those extra Items are defined in the table <b>allNpcDateDrops</b>. Each Special Event has a start and end date to stop to drop extra Items automaticaly.
*/
public class EventDroplist
{
/** The table containing all DataDrop object */
private final List<DateDrop> _allNpcDateDrops;
public class DateDrop
{
/** Start and end date of the Event */
public DateRange dateRange;
/** The table containing Item identifier that can be dropped as extra Items during the Event */
public int[] items;
/** The min number of Item dropped in one time during this Event */
public int min;
/** The max number of Item dropped in one time during this Event */
public int max;
/** The rate of drop for this Event */
public int chance;
}
/**
* Constructor of EventDroplist.
*/
protected EventDroplist()
{
_allNpcDateDrops = new ArrayList<>();
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param items The table containing all item identifier of this DateDrop
* @param count The table containing min and max value of this DateDrop
* @param chance The chance to obtain this drop
* @param range The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] items, int[] count, int chance, DateRange range)
{
final DateDrop date = new DateDrop();
date.dateRange = range;
date.items = items;
date.min = count[0];
date.max = count[1];
date.chance = chance;
_allNpcDateDrops.add(date);
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
{
final List<DateDrop> list = new ArrayList<>();
for (DateDrop drop : _allNpcDateDrops)
{
final Date currentDate = new Date();
if (drop.dateRange.isWithinRange(currentDate))
{
list.add(drop);
}
}
return list;
}
public static EventDroplist getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final EventDroplist INSTANCE = new EventDroplist();
}
}

View File

@ -19,26 +19,23 @@ package org.l2jmobius.gameserver.script;
import java.util.HashMap;
import java.util.Map;
import org.l2jmobius.gameserver.script.faenor.FaenorInterface;
/**
* @author Luis Arias
*/
public class ScriptEngine
{
protected EngineInterface _utils = FaenorInterface.getInstance();
public static final Map<String, ParserFactory> parserFactories = new HashMap<>();
public static final Map<String, ParserFactory> PARSER_FACTORIES = new HashMap<>();
protected static Parser createParser(String name) throws ParserNotCreatedException
{
ParserFactory s = parserFactories.get(name);
ParserFactory s = PARSER_FACTORIES.get(name);
if (s == null) // Shape not found.
{
try
{
Class.forName("org.l2jmobius.gameserver.script." + name);
// By now the static block with no function would have been executed if the shape was found. The shape is expected to have put its factory in the hashtable.
s = parserFactories.get(name);
s = PARSER_FACTORIES.get(name);
if (s == null) // If the shape factory is not there even now.
{
throw new ParserNotCreatedException();

View File

@ -1,122 +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.script;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* @author Luis Arias
*/
public class ScriptPackage
{
private final List<ScriptDocument> _scriptFiles;
private final List<String> _otherFiles;
private final String _name;
public ScriptPackage(ZipFile pack)
{
_scriptFiles = new ArrayList<>();
_otherFiles = new ArrayList<>();
_name = pack.getName();
addFiles(pack);
}
/**
* @return Returns the otherFiles.
*/
public List<String> getOtherFiles()
{
return _otherFiles;
}
/**
* @return Returns the scriptFiles.
*/
public List<ScriptDocument> getScriptFiles()
{
return _scriptFiles;
}
/**
* @param pack
*/
private void addFiles(ZipFile pack)
{
for (Enumeration<? extends ZipEntry> e = pack.entries(); e.hasMoreElements();)
{
final ZipEntry entry = e.nextElement();
if (entry.getName().endsWith(".xml"))
{
try
{
final ScriptDocument newScript = new ScriptDocument(entry.getName(), pack.getInputStream(entry));
_scriptFiles.add(newScript);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
else if (!entry.isDirectory())
{
_otherFiles.add(entry.getName());
}
}
}
/**
* @return Returns the name.
*/
public String getName()
{
return _name;
}
@Override
public String toString()
{
if (_scriptFiles.isEmpty() && _otherFiles.isEmpty())
{
return "Empty Package.";
}
String out = "Package Name: " + _name + "\n";
if (!_scriptFiles.isEmpty())
{
out += "Xml Script Files...\n";
for (ScriptDocument script : _scriptFiles)
{
out += script.getName() + "\n";
}
}
if (!_otherFiles.isEmpty())
{
out += "Other Files...\n";
for (String fileName : _otherFiles)
{
out += fileName + "\n";
}
}
return out;
}
}

View File

@ -1,137 +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.script.faenor;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.Config;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.IntList;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserFactory;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorEventParser extends FaenorParser
{
private static final Logger LOGGER = Logger.getLogger(FaenorEventParser.class.getName());
private DateRange _eventDates = null;
@Override
public void parseScript(Node eventNode, ScriptContext context)
{
final String id = attribute(eventNode, "ID");
_eventDates = DateRange.parse(attribute(eventNode, "Active"), DATE_FORMAT);
final Date currentDate = new Date();
if (_eventDates.getEndDate().before(currentDate))
{
LOGGER.info("Event ID: (" + id + ") has passed... Ignored.");
return;
}
if (_eventDates.getStartDate().after(currentDate))
{
LOGGER.info("Event ID: (" + id + ") is not active yet... Ignored.");
ThreadPool.schedule(() -> parseEventDropAndMessage(eventNode), _eventDates.getStartDate().getTime() - currentDate.getTime());
return;
}
parseEventDropAndMessage(eventNode);
}
protected void parseEventDropAndMessage(Node eventNode)
{
for (Node node = eventNode.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DropList"))
{
parseEventDropList(node);
}
else if (isNodeName(node, "Message"))
{
parseEventMessage(node);
}
}
}
private void parseEventMessage(Node sysMsg)
{
try
{
final String type = attribute(sysMsg, "Type");
final String[] message = attribute(sysMsg, "Msg").split(Config.EOL);
if (type.equalsIgnoreCase("OnJoin"))
{
_bridge.onPlayerLogin(message, _eventDates);
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error in event parser: " + e.getMessage());
}
}
private void parseEventDropList(Node dropList)
{
for (Node node = dropList.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "AllDrop"))
{
parseEventDrop(node);
}
}
}
private void parseEventDrop(Node drop)
{
try
{
final int[] items = IntList.parse(attribute(drop, "Items"));
final int[] count = IntList.parse(attribute(drop, "Count"));
final double chance = getPercent(attribute(drop, "Chance"));
_bridge.addEventDrop(items, count, chance, _eventDates);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "ERROR(parseEventDrop):" + e.getMessage());
}
}
static class FaenorEventParserFactory extends ParserFactory
{
@Override
public Parser create()
{
return (new FaenorEventParser());
}
}
static
{
ScriptEngine.parserFactories.put(getParserName("Event"), new FaenorEventParserFactory());
}
}

View File

@ -1,160 +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.script.faenor;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.l2jmobius.gameserver.data.sql.AnnouncementsTable;
import org.l2jmobius.gameserver.data.sql.NpcTable;
import org.l2jmobius.gameserver.model.DropCategory;
import org.l2jmobius.gameserver.model.DropData;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
import org.l2jmobius.gameserver.model.announce.Announcement;
import org.l2jmobius.gameserver.model.announce.AnnouncementType;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EngineInterface;
import org.l2jmobius.gameserver.script.EventDroplist;
/**
* @author Luis Arias
*/
public class FaenorInterface implements EngineInterface
{
protected static final Logger LOGGER = Logger.getLogger(FaenorInterface.class.getName());
public static FaenorInterface getInstance()
{
return SingletonHolder.INSTANCE;
}
public List<?> getAllPlayers()
{
return null;
}
/**
* Adds a new Quest Drop to an NPC
*/
@Override
public void addQuestDrop(int npcID, int itemID, int min, int max, int chance, String questID, String[] states)
{
final NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID);
if (npc == null)
{
throw new NullPointerException();
}
final DropData drop = new DropData();
drop.setItemId(itemID);
drop.setMinDrop(min);
drop.setMaxDrop(max);
drop.setChance(chance);
drop.setQuestID(questID);
drop.addStates(states);
addDrop(npc, drop, false);
}
/**
* Adds a new Drop to an NPC
* @param npcID
* @param itemID
* @param min
* @param max
* @param sweep
* @param chance
*/
public void addDrop(int npcID, int itemID, int min, int max, boolean sweep, int chance)
{
final NpcTemplate npc = NpcTable.getInstance().getTemplate(npcID);
if (npc == null)
{
throw new NullPointerException();
}
final DropData drop = new DropData();
drop.setItemId(itemID);
drop.setMinDrop(min);
drop.setMaxDrop(max);
drop.setChance(chance);
addDrop(npc, drop, sweep);
}
/**
* Adds a new drop to an NPC. If the drop is sweep, it adds it to the NPC's Sweep category If the drop is non-sweep, it creates a new category for this drop.
* @param npc
* @param drop
* @param sweep
*/
public void addDrop(NpcTemplate npc, DropData drop, boolean sweep)
{
if (sweep)
{
addDrop(npc, drop, -1);
}
else
{
int maxCategory = -1;
if (npc.getDropData() != null)
{
for (DropCategory cat : npc.getDropData())
{
if (maxCategory < cat.getCategoryType())
{
maxCategory = cat.getCategoryType();
}
}
}
maxCategory++;
npc.addDropData(drop, maxCategory);
}
}
/**
* Adds a new drop to an NPC, in the specified category. If the category does not exist, it is created.
* @param npc
* @param drop
* @param category
*/
public void addDrop(NpcTemplate npc, DropData drop, int category)
{
npc.addDropData(drop, category);
}
@Override
public void addEventDrop(int[] items, int[] count, double chance, DateRange range)
{
EventDroplist.getInstance().addGlobalDrop(items, count, (int) (chance * 1000000), range);
}
@Override
public void onPlayerLogin(String[] message, DateRange validDateRange)
{
if (!validDateRange.isValid() || validDateRange.isWithinRange(new Date()))
{
for (String element : message)
{
AnnouncementsTable.getInstance().addAnnouncement(new Announcement(AnnouncementType.CRITICAL, element, ""), false);
}
}
}
private static class SingletonHolder
{
protected static final FaenorInterface INSTANCE = new FaenorInterface();
}
}

View File

@ -1,127 +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.script.faenor;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.l2jmobius.gameserver.script.Parser;
/**
* @author Luis Arias
*/
public abstract class FaenorParser extends Parser
{
protected static FaenorInterface _bridge = FaenorInterface.getInstance();
protected final DateFormat DATE_FORMAT = new SimpleDateFormat("dd MMM yyyy", Locale.US);
public static String attribute(Node node, String attributeName)
{
return attribute(node, attributeName, null);
}
public static String element(Node node, String elementName)
{
return element(node, elementName, null);
}
public static String attribute(Node node, String attributeName, String defaultValue)
{
try
{
return node.getAttributes().getNamedItem(attributeName).getNodeValue();
}
catch (Exception e)
{
if (defaultValue != null)
{
return defaultValue;
}
throw new NullPointerException(e.getMessage());
}
}
public static String element(Node parentNode, String elementName, String defaultValue)
{
try
{
final NodeList list = parentNode.getChildNodes();
for (int i = 0; i < list.getLength(); i++)
{
final Node node = list.item(i);
if (node.getNodeName().equalsIgnoreCase(elementName))
{
return node.getTextContent();
}
}
}
catch (Exception e)
{
}
if (defaultValue != null)
{
return defaultValue;
}
throw new NullPointerException();
}
public static boolean isNodeName(Node node, String name)
{
return node.getNodeName().equalsIgnoreCase(name);
}
public Date getDate(String date) throws ParseException
{
return DATE_FORMAT.parse(date);
}
public static double getPercent(String percent)
{
return (Double.parseDouble(percent.split("%")[0]) / 100.0);
}
protected static int getInt(String number)
{
return Integer.parseInt(number);
}
protected static double getDouble(String number)
{
return Double.parseDouble(number);
}
protected static float getFloat(String number)
{
return Float.parseFloat(number);
}
protected static String getParserName(String name)
{
return "faenor.Faenor" + name + "Parser";
}
@Override
public abstract void parseScript(Node node, ScriptContext context);
}

View File

@ -1,110 +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.script.faenor;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserFactory;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorQuestParser extends FaenorParser
{
protected static final Logger LOGGER = Logger.getLogger(FaenorQuestParser.class.getName());
@Override
public void parseScript(Node questNode, ScriptContext context)
{
final String questID = attribute(questNode, "ID");
for (Node node = questNode.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DROPLIST"))
{
parseQuestDropList(node.cloneNode(true), questID);
}
else if (isNodeName(node, "DIALOG WINDOWS"))
{
// parseDialogWindows(node.cloneNode(true));
}
else if (isNodeName(node, "INITIATOR"))
{
// parseInitiator(node.cloneNode(true));
}
else if (isNodeName(node, "STATE"))
{
// parseState(node.cloneNode(true));
}
}
}
private void parseQuestDropList(Node dropList, String questID)
{
for (Node node = dropList.getFirstChild(); node != null; node = node.getNextSibling())
{
if (isNodeName(node, "DROP"))
{
parseQuestDrop(node.cloneNode(true), questID);
}
}
}
private void parseQuestDrop(Node drop, String questID)
{
int npcID;
int itemID;
int min;
int max;
int chance;
String[] states;
try
{
npcID = getInt(attribute(drop, "NpcID"));
itemID = getInt(attribute(drop, "ItemID"));
min = getInt(attribute(drop, "Min"));
max = getInt(attribute(drop, "Max"));
chance = getInt(attribute(drop, "Chance"));
states = (attribute(drop, "States")).split(",");
}
catch (NullPointerException e)
{
throw new NullPointerException("Incorrect Drop Data");
}
_bridge.addQuestDrop(npcID, itemID, min, max, chance, questID, states);
}
static class FaenorQuestParserFactory extends ParserFactory
{
@Override
public Parser create()
{
return (new FaenorQuestParser());
}
}
static
{
ScriptEngine.parserFactories.put(getParserName("Quest"), new FaenorQuestParserFactory());
}
}

View File

@ -1,105 +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.script.faenor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import org.w3c.dom.Node;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.file.filter.XMLFilter;
import org.l2jmobius.gameserver.script.Parser;
import org.l2jmobius.gameserver.script.ParserNotCreatedException;
import org.l2jmobius.gameserver.script.ScriptDocument;
import org.l2jmobius.gameserver.script.ScriptEngine;
/**
* @author Luis Arias
*/
public class FaenorScriptEngine extends ScriptEngine
{
private static final Logger LOGGER = Logger.getLogger(FaenorScriptEngine.class.getName());
public static final String PACKAGE_DIRECTORY = "data/faenor/";
protected FaenorScriptEngine()
{
final File packDirectory = new File(Config.DATAPACK_ROOT, PACKAGE_DIRECTORY);
final File[] files = packDirectory.listFiles(new XMLFilter());
if (files != null)
{
for (File file : files)
{
try (InputStream in = new FileInputStream(file))
{
parseScript(new ScriptDocument(file.getName(), in), null);
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
}
}
}
public void parseScript(ScriptDocument script, ScriptContext context)
{
final Node node = script.getDocument().getFirstChild();
final String parserClass = "faenor.Faenor" + node.getNodeName() + "Parser";
Parser parser = null;
try
{
parser = createParser(parserClass);
}
catch (ParserNotCreatedException e)
{
LOGGER.log(Level.WARNING, "ERROR: No parser registered for Script: " + parserClass + ": " + e.getMessage());
}
if (parser == null)
{
LOGGER.warning("Unknown Script Type: " + script.getName());
return;
}
try
{
parser.parseScript(node, context);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + script.getName() + " successfully.");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Script Parsing Failed: " + e.getMessage());
}
}
public static FaenorScriptEngine getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final FaenorScriptEngine INSTANCE = new FaenorScriptEngine();
}
}

View File

@ -17,11 +17,13 @@
package org.l2jmobius.gameserver.util;
import org.l2jmobius.gameserver.data.xml.ZoneData;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Player;
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.IClientOutgoingPacket;
import org.l2jmobius.gameserver.network.serverpackets.RelationChanged;
@ -194,6 +196,16 @@ public class Broadcast
}
}
public static void toAllOnlinePlayers(String text)
{
toAllOnlinePlayers(text, false);
}
public static void toAllOnlinePlayers(String text, boolean isCritical)
{
toAllOnlinePlayers(new CreatureSay(0, isCritical ? ChatType.CRITICAL_ANNOUNCE : ChatType.ANNOUNCEMENT, null, text));
}
/**
* Send a packet to all players in a specific zone type.
* @param <T> ZoneType.