Empty messages, minLevel, maxLevel and monsterIds LongTimeEvent parameters.

This commit is contained in:
MobiusDevelopment 2019-11-19 00:10:54 +00:00
parent e847e61cd5
commit ead417a1bf
102 changed files with 2254 additions and 2693 deletions

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -67,6 +66,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1097,12 +1097,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -65,6 +64,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1082,12 +1082,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -65,6 +64,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1082,12 +1082,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -65,6 +64,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1082,12 +1082,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -65,6 +64,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1090,12 +1090,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -35,7 +35,6 @@ import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.ai.FortSiegeGuardAI;
import org.l2jmobius.gameserver.ai.SiegeGuardAI;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -61,6 +60,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1044,18 +1044,28 @@ public class Attackable extends Npc
final PlayerInstance player = lastAttacker.getActingPlayer();
// Don't drop anything if the last attacker or owner isn't PlayerInstance
if ((player == null) || ((player.getLevel() - getLevel()) > 9))
if (player == null)
{
return;
}
if ((player.getLevel() - getLevel()) > 9)
{
return;
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -43,7 +43,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -57,8 +57,9 @@ public class LongTimeEvent extends Quest
private String _eventName;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -67,7 +68,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -169,7 +170,20 @@ public class LongTimeEvent extends Quest
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 int finalChance = !chance.isEmpty() && chance.endsWith("%") ? Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000 : 0;
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)
{
@ -183,13 +197,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -293,18 +307,17 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
final long currentTime = System.currentTimeMillis();
// Add drop
if ((_dropList != null) && (currentTime < _dropPeriod.getEndDate().getTime()))
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - currentTime;
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
for (NpcSpawn spawn : _spawnList)
@ -313,13 +326,19 @@ public class LongTimeEvent extends Quest
}
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -363,8 +382,18 @@ public class LongTimeEvent extends Quest
{
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -382,7 +411,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -35,7 +35,6 @@ import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.ai.FortSiegeGuardAI;
import org.l2jmobius.gameserver.ai.SiegeGuardAI;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -61,6 +60,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.attackable.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1044,18 +1044,28 @@ public class Attackable extends Npc
final PlayerInstance player = lastAttacker.getActingPlayer();
// Don't drop anything if the last attacker or owner isn't PlayerInstance
if ((player == null) || ((player.getLevel() - getLevel()) > 9))
if (player == null)
{
return;
}
if ((player.getLevel() - getLevel()) > 9)
{
return;
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -43,7 +43,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -57,8 +57,9 @@ public class LongTimeEvent extends Quest
private String _eventName;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -67,7 +68,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -169,7 +170,20 @@ public class LongTimeEvent extends Quest
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 int finalChance = !chance.isEmpty() && chance.endsWith("%") ? Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000 : 0;
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)
{
@ -183,13 +197,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -293,18 +307,17 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
final long currentTime = System.currentTimeMillis();
// Add drop
if ((_dropList != null) && (currentTime < _dropPeriod.getEndDate().getTime()))
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - currentTime;
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
for (NpcSpawn spawn : _spawnList)
@ -313,13 +326,19 @@ public class LongTimeEvent extends Quest
}
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -363,8 +382,18 @@ public class LongTimeEvent extends Quest
{
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -382,7 +411,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -68,6 +67,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1115,12 +1115,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -68,6 +67,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1115,12 +1115,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -68,6 +67,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1115,12 +1115,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

View File

@ -42,7 +42,7 @@ import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.announce.EventAnnouncement;
import org.l2jmobius.gameserver.model.holders.DropHolder;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.util.Broadcast;
@ -58,8 +58,9 @@ public class LongTimeEvent extends Quest
boolean _enableShrines = false;
// Messages
protected String _onEnterMsg = "Event is in process";
protected String _endMsg = "Event ends!";
protected String _onEnterMsg = "";
protected String _endMsg = "";
private int _enterAnnounceId = -1;
protected DateRange _eventPeriod = null;
protected DateRange _dropPeriod;
@ -68,7 +69,7 @@ public class LongTimeEvent extends Quest
protected final List<NpcSpawn> _spawnList = new ArrayList<>();
// Drop data for event
protected final List<DropHolder> _dropList = new ArrayList<>();
protected final List<EventDropHolder> _dropList = new ArrayList<>();
// Items to destroy when event ends.
protected final List<Integer> _destoyItemsOnEnd = new ArrayList<>();
@ -165,8 +166,7 @@ public class LongTimeEvent extends Quest
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today))
{
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
// Loading droplist
if (n.getNodeName().equalsIgnoreCase("droplist"))
@ -181,11 +181,19 @@ public class LongTimeEvent extends Quest
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();
int finalChance = 0;
if (!chance.isEmpty() && chance.endsWith("%"))
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)
{
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000;
for (String id : monsterIdsNode.getNodeValue().split(","))
{
monsterIds.add(Integer.parseInt(id));
}
}
if (ItemTable.getInstance().getTemplate(itemId) == null)
@ -200,13 +208,13 @@ public class LongTimeEvent extends Quest
continue;
}
if ((finalChance < 10000) || (finalChance > 1000000))
if ((finalChance < 0) || (finalChance > 100))
{
LOGGER.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist");
continue;
}
_dropList.add(new DropHolder(null, itemId, minCount, maxCount, finalChance));
_dropList.add(new EventDropHolder(itemId, minCount, maxCount, finalChance, minLevel, maxLevel, monsterIds));
}
catch (NumberFormatException nfe)
{
@ -272,8 +280,7 @@ public class LongTimeEvent extends Quest
}
// Load destroy item list at all times.
final Node first = doc.getDocumentElement().getFirstChild();
for (Node n = first; n != null; n = n.getNextSibling())
for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeName().equalsIgnoreCase("destoyItemsOnEnd"))
{
@ -309,16 +316,16 @@ public class LongTimeEvent extends Quest
*/
protected void startEvent()
{
// Add drop
// Add drop.
if (_dropList != null)
{
for (DropHolder drop : _dropList)
for (EventDropHolder drop : _dropList)
{
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod);
EventDroplist.getInstance().addGlobalDrop(_dropPeriod, drop);
}
}
// Add spawns
// Add spawns.
final Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis();
if (_spawnList != null)
{
@ -328,19 +335,25 @@ public class LongTimeEvent extends Quest
}
}
// Enable town shrines
// Enable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(true);
}
// Send message on begin
Broadcast.toAllOnlinePlayers(_onEnterMsg);
// 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();
}
// Add announce for entering players
AnnouncementsTable.getInstance().addAnnouncement(new EventAnnouncement(_eventPeriod, _onEnterMsg));
// Schedule event end (now only for message sending)
// Schedule event end.
ThreadPool.schedule(new ScheduleEnd(), millisToEventEnd);
}
@ -382,15 +395,26 @@ public class LongTimeEvent extends Quest
@Override
public void run()
{
// Disable town shrines
// Disable town shrines.
if (_enableShrines)
{
EventShrineManager.getInstance().setEnabled(false);
}
// Destroy items that must exist only on event period.
destoyItemsOnEnd();
// Send message on end
Broadcast.toAllOnlinePlayers(_endMsg);
// Send message on end.
if (!_endMsg.isEmpty())
{
Broadcast.toAllOnlinePlayers(_endMsg);
}
// Remove announce for entering players.
if (_enterAnnounceId != -1)
{
AnnouncementsTable.getInstance().deleteAnnouncement(_enterAnnounceId);
}
}
}
@ -408,7 +432,7 @@ public class LongTimeEvent extends Quest
player.destroyItemByItemId(_eventName, itemId, -1, player, true);
}
}
// Update database
// Update database.
try (Connection con = DatabaseFactory.getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE item_id=?"))
{

View File

@ -1,79 +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;
/**
* @author Zoey76
*/
public class EventDrop
{
private final int[] _itemIdList;
private final long _minCount;
private final long _maxCount;
private final int _dropChance;
public EventDrop(int[] itemIdList, long min, long max, int dropChance)
{
_itemIdList = itemIdList;
_minCount = min;
_maxCount = max;
_dropChance = dropChance;
}
public EventDrop(int itemId, long minCount, long maxCount, int dropChance)
{
_itemIdList = new int[]
{
itemId
};
_minCount = minCount;
_maxCount = maxCount;
_dropChance = dropChance;
}
/**
* @return the _itemId
*/
public int[] getItemIdList()
{
return _itemIdList;
}
/**
* @return the _minCount
*/
public long getMinCount()
{
return _minCount;
}
/**
* @return the _maxCount
*/
public long getMaxCount()
{
return _maxCount;
}
/**
* @return the _dropChance
*/
public int getDropChance()
{
return _dropChance;
}
}

View File

@ -12,6 +12,9 @@
<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>

View File

@ -16,14 +16,13 @@
*/
package org.l2jmobius.gameserver.datatables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.script.DateRange;
import org.l2jmobius.gameserver.script.EventDrop;
/**
* This class manage drop of Special Events created by GM for a defined period.<br>
@ -38,28 +37,22 @@ public class EventDroplist
*/
private static final Collection<DateDrop> ALL_NPC_DATE_DROPS = ConcurrentHashMap.newKeySet();
public static class DateDrop
private static final class DateDrop
{
protected final DateRange _dateRange;
private final EventDrop _eventDrop;
private final DateRange _dateRange;
private final EventDropHolder _eventDrop;
public DateDrop(DateRange dateRange, EventDrop eventDrop)
public DateDrop(DateRange dateRange, EventDropHolder eventDrop)
{
_dateRange = dateRange;
_eventDrop = eventDrop;
}
/**
* @return the _eventDrop
*/
public EventDrop getEventDrop()
public EventDropHolder getEventDrop()
{
return _eventDrop;
}
/**
* @return the _dateRange
*/
public DateRange getDateRange()
{
return _dateRange;
@ -67,51 +60,26 @@ public class EventDroplist
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .
* @param itemIdList 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 dateRange The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] itemIdList, int[] count, int chance, DateRange dateRange)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemIdList, count[0], count[1], chance)));
}
/**
* @param itemId the item Id for the drop
* @param min the minimum drop count
* @param max the maximum drop count
* @param chance the drop chance
* @param dateRange the event drop rate range
* @param drop the event drop
*/
public void addGlobalDrop(int itemId, long min, long max, int chance, DateRange dateRange)
public void addGlobalDrop(DateRange dateRange, EventDropHolder drop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, new EventDrop(itemId, min, max, chance)));
}
/**
* Adds an event drop for a given date range.
* @param dateRange the date range.
* @param eventDrop the event drop.
*/
public void addGlobalDrop(DateRange dateRange, EventDrop eventDrop)
{
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, eventDrop));
ALL_NPC_DATE_DROPS.add(new DateDrop(dateRange, drop));
}
/**
* @return all DateDrop of EventDroplist allNpcDateDrops within the date range.
*/
public List<DateDrop> getAllDrops()
public Collection<EventDropHolder> getAllDrops()
{
final List<DateDrop> list = new LinkedList<>();
final Collection<EventDropHolder> list = new ArrayList<>();
final Date currentDate = new Date();
for (DateDrop drop : ALL_NPC_DATE_DROPS)
{
if (drop._dateRange.isWithinRange(currentDate))
if (drop.getDateRange().isWithinRange(currentDate))
{
list.add(drop);
list.add(drop.getEventDrop());
}
}
return list;

View File

@ -38,7 +38,6 @@ import org.l2jmobius.gameserver.ai.CtrlEvent;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import org.l2jmobius.gameserver.datatables.EventDroplist;
import org.l2jmobius.gameserver.datatables.EventDroplist.DateDrop;
import org.l2jmobius.gameserver.datatables.ItemTable;
import org.l2jmobius.gameserver.enums.ChatType;
import org.l2jmobius.gameserver.enums.DropType;
@ -66,6 +65,7 @@ import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAggroRangeEnter;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableAttack;
import org.l2jmobius.gameserver.model.events.impl.creature.npc.OnAttackableKill;
import org.l2jmobius.gameserver.model.holders.EventDropHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.items.Item;
@ -1093,12 +1093,17 @@ public class Attackable extends Npc
}
// Go through DateDrop of EventDroplist allNpcDateDrops within the date range
for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
for (EventDropHolder drop : EventDroplist.getInstance().getAllDrops())
{
if (Rnd.get(1000000) < drop.getEventDrop().getDropChance())
if (!drop.getMonsterIds().isEmpty() && !drop.getMonsterIds().contains(getId()))
{
final int itemId = drop.getEventDrop().getItemIdList()[Rnd.get(drop.getEventDrop().getItemIdList().length)];
final long itemCount = Rnd.get(drop.getEventDrop().getMinCount(), drop.getEventDrop().getMaxCount());
continue;
}
final int monsterLevel = getLevel();
if ((monsterLevel >= drop.getMinLevel()) && (monsterLevel <= drop.getMaxLevel()) && (Rnd.get(100d) < drop.getChance()))
{
final int itemId = drop.getItemId();
final long itemCount = Rnd.get(drop.getMin(), drop.getMax());
if (Config.AUTO_LOOT_ITEM_IDS.contains(itemId) || Config.AUTO_LOOT || isFlying())
{
player.doAutoLoot(this, itemId, itemCount); // Give the item(s) to the PlayerInstance that has killed the Attackable

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;
import java.util.Collection;
/**
* @author Mobius
*/
public class EventDropHolder extends DropHolder
{
private final int _minLevel;
private final int _maxLevel;
private final Collection<Integer> _monsterIds;
public EventDropHolder(int itemId, long min, long max, double chance, int minLevel, int maxLevel, Collection<Integer> monsterIds)
{
super(null, itemId, min, max, chance);
_minLevel = minLevel;
_maxLevel = maxLevel;
_monsterIds = monsterIds;
}
public int getMinLevel()
{
return _minLevel;
}
public int getMaxLevel()
{
return _maxLevel;
}
public Collection<Integer> getMonsterIds()
{
return _monsterIds;
}
}

Some files were not shown because too many files have changed in this diff Show More