Drop calculation related cleanup.
This commit is contained in:
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1104,6 +1104,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1141,6 +1142,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1086,6 +1086,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1123,6 +1124,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1086,6 +1086,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1123,6 +1124,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1086,6 +1086,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1123,6 +1124,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1097,6 +1097,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1134,6 +1135,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1097,6 +1097,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1134,6 +1135,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -614,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // Lucky drops are added to normal drops and calculated later
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+2
@@ -1097,6 +1097,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1134,6 +1135,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -204,8 +206,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -226,12 +228,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -102,16 +102,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -632,6 +632,7 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
@@ -722,11 +723,11 @@ public class NpcData implements IXmlReader
|
|||||||
public List<NpcTemplate> getTemplates(Predicate<NpcTemplate> filter)
|
public List<NpcTemplate> getTemplates(Predicate<NpcTemplate> filter)
|
||||||
{
|
{
|
||||||
final List<NpcTemplate> result = new ArrayList<>();
|
final List<NpcTemplate> result = new ArrayList<>();
|
||||||
for (NpcTemplate template : _npcs.values())
|
for (NpcTemplate npcTemplate : _npcs.values())
|
||||||
{
|
{
|
||||||
if (filter.test(template))
|
if (filter.test(npcTemplate))
|
||||||
{
|
{
|
||||||
result.add(template);
|
result.add(npcTemplate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1058,6 +1058,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1096,6 +1097,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-34
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -607,58 +606,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -670,19 +660,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+1
-1
@@ -196,7 +196,7 @@ public class PlayerTemplate extends CreatureTemplate
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param slotId id of inventory slot to return value
|
* @param slotId id of inventory slot to return value
|
||||||
* @return defence value of charactert for EMPTY given slot
|
* @return defense value of character for EMPTY given slot
|
||||||
*/
|
*/
|
||||||
public int getBaseDefBySlot(int slotId)
|
public int getBaseDefBySlot(int slotId)
|
||||||
{
|
{
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -204,8 +206,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -226,12 +228,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -102,16 +102,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -632,6 +632,7 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
@@ -722,11 +723,11 @@ public class NpcData implements IXmlReader
|
|||||||
public List<NpcTemplate> getTemplates(Predicate<NpcTemplate> filter)
|
public List<NpcTemplate> getTemplates(Predicate<NpcTemplate> filter)
|
||||||
{
|
{
|
||||||
final List<NpcTemplate> result = new ArrayList<>();
|
final List<NpcTemplate> result = new ArrayList<>();
|
||||||
for (NpcTemplate template : _npcs.values())
|
for (NpcTemplate npcTemplate : _npcs.values())
|
||||||
{
|
{
|
||||||
if (filter.test(template))
|
if (filter.test(npcTemplate))
|
||||||
{
|
{
|
||||||
result.add(template);
|
result.add(npcTemplate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1058,6 +1058,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1096,6 +1097,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-34
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -607,58 +606,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -670,19 +660,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+1
-1
@@ -196,7 +196,7 @@ public class PlayerTemplate extends CreatureTemplate
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param slotId id of inventory slot to return value
|
* @param slotId id of inventory slot to return value
|
||||||
* @return defence value of charactert for EMPTY given slot
|
* @return defense value of character for EMPTY given slot
|
||||||
*/
|
*/
|
||||||
public int getBaseDefBySlot(int slotId)
|
public int getBaseDefBySlot(int slotId)
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-27
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -421,16 +421,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -440,16 +441,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -461,16 +461,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -624,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -643,9 +634,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -654,7 +643,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
+2
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -669,52 +668,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -726,19 +722,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -769,7 +782,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -808,14 +821,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -421,16 +421,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -440,16 +441,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -461,16 +461,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -624,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -643,9 +634,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -654,7 +643,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -669,52 +668,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -726,19 +722,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -769,7 +782,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -808,14 +821,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-27
@@ -204,10 +204,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -421,16 +421,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -440,16 +441,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -461,16 +461,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -624,12 +614,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -643,9 +634,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -654,7 +643,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
+2
@@ -1100,6 +1100,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1137,6 +1138,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -669,52 +668,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -726,19 +722,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -769,7 +782,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -808,14 +821,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-27
@@ -207,10 +207,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -424,16 +424,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -443,16 +444,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -464,16 +464,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -627,12 +617,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -646,9 +637,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -657,7 +646,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
+2
@@ -1121,6 +1121,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1158,6 +1159,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -684,52 +683,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -741,19 +737,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -784,7 +797,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -823,14 +836,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
L2J_Mobius_Classic_2.4_SecretOfEmpire/dist/game/data/scripts/handlers/bypasshandlers/NpcViewMod.java
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-27
@@ -207,10 +207,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -424,16 +424,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -443,16 +444,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -464,16 +464,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -627,12 +617,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -646,9 +637,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -657,7 +646,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
+2
@@ -1121,6 +1121,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1158,6 +1159,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -684,52 +683,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -741,19 +737,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -784,7 +797,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -823,14 +836,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
L2J_Mobius_Classic_3.0_TheKamael/dist/game/data/scripts/handlers/communityboard/DropSearchBoard.java
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-27
@@ -207,10 +207,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -424,16 +424,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -443,16 +444,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -464,16 +464,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -627,12 +617,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -646,9 +637,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -657,7 +646,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
+2
@@ -1121,6 +1121,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1158,6 +1159,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-31
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -684,52 +683,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -741,19 +737,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
@@ -784,7 +797,7 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
return calculatedDrops;
|
return calculatedDrops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
|
private void processVipDrops(List<ItemHolder> items, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = new ArrayList<>();
|
final List<DropHolder> dropList = new ArrayList<>();
|
||||||
if (killer.getActingPlayer() != null)
|
if (killer.getActingPlayer() != null)
|
||||||
@@ -823,14 +836,12 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calculateDrop(dropItem, victim, killer);
|
return calculateDrop(dropItem, victim, killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
|
||||||
{
|
{
|
||||||
final double levelGapChanceToDrop;
|
final double levelGapChanceToDrop;
|
||||||
|
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
||||||
{
|
{
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
||||||
|
|||||||
Vendored
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,10 +206,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -423,16 +423,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -442,17 +443,16 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
final Item item = ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id"));
|
||||||
final Item item = ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id"));
|
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -471,16 +471,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -634,12 +624,13 @@ public class NpcData implements IXmlReader
|
|||||||
|
|
||||||
if (dropLists != null)
|
if (dropLists != null)
|
||||||
{
|
{
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -653,9 +644,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -664,7 +653,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
@@ -1104,6 +1104,7 @@ public class Attackable extends Npc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1141,6 +1142,7 @@ public class Attackable extends Npc
|
|||||||
broadcastPacket(sm);
|
broadcastPacket(sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deathItems.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-35
@@ -17,7 +17,6 @@
|
|||||||
package org.l2jmobius.gameserver.model.actor.templates;
|
package org.l2jmobius.gameserver.model.actor.templates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -668,59 +667,49 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
_dropListSpoil.add(dropHolder);
|
_dropListSpoil.add(dropHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DropHolder> getDropList(DropType dropType)
|
public List<DropHolder> getDropList()
|
||||||
{
|
|
||||||
switch (dropType)
|
|
||||||
{
|
|
||||||
case DROP:
|
|
||||||
case LUCKY: // never happens
|
|
||||||
{
|
{
|
||||||
return _dropListDeath;
|
return _dropListDeath;
|
||||||
}
|
}
|
||||||
case SPOIL:
|
|
||||||
|
public List<DropHolder> getSpoilList()
|
||||||
{
|
{
|
||||||
return _dropListSpoil;
|
return _dropListSpoil;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
public List<ItemHolder> calculateDrops(DropType dropType, Creature victim, Creature killer)
|
||||||
{
|
{
|
||||||
final List<DropHolder> templateList = getDropList(dropType);
|
final List<DropHolder> dropList = dropType == DropType.SPOIL ? _dropListSpoil : _dropListDeath;
|
||||||
if (templateList == null)
|
if (dropList == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
// level difference calculations
|
||||||
|
|
||||||
// randomize drop order
|
|
||||||
Collections.shuffle(dropList);
|
|
||||||
|
|
||||||
final int levelDifference = victim.getLevel() - killer.getLevel();
|
final int levelDifference = victim.getLevel() - killer.getLevel();
|
||||||
|
final double levelGapChanceToDropAdena = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
final double levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100d);
|
||||||
|
|
||||||
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
int dropOccurrenceCounter = victim.isRaid() ? Config.DROP_MAX_OCCURRENCES_RAIDBOSS : Config.DROP_MAX_OCCURRENCES_NORMAL;
|
||||||
Collection<ItemHolder> calculatedDrops = null;
|
List<ItemHolder> calculatedDrops = null;
|
||||||
|
List<ItemHolder> randomDrops = null;
|
||||||
|
ItemHolder replacedItem = null;
|
||||||
|
if (dropOccurrenceCounter > 0)
|
||||||
|
{
|
||||||
for (DropHolder dropItem : dropList)
|
for (DropHolder dropItem : dropList)
|
||||||
{
|
{
|
||||||
// check if maximum drop occurrences have been reached
|
// check if maximum drop occurrences have been reached
|
||||||
// items that have 100% drop chance without server rate multipliers drop normally
|
// items that have 100% drop chance without server rate multipliers drop normally
|
||||||
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100))
|
if ((dropOccurrenceCounter == 0) && (dropItem.getChance() < 100) && (randomDrops != null) && (calculatedDrops != null))
|
||||||
{
|
{
|
||||||
continue;
|
// remove a random existing drop (temporarily if not other item replaces it)
|
||||||
|
dropOccurrenceCounter++;
|
||||||
|
replacedItem = randomDrops.remove(Rnd.get(randomDrops.size()));
|
||||||
|
calculatedDrops.remove(replacedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check level gap that may prevent drop this item
|
// check level gap that may prevent to drop item
|
||||||
final double levelGapChanceToDrop;
|
if ((Rnd.nextDouble() * 100) > (dropItem.getItemId() == Inventory.ADENA_ID ? levelGapChanceToDropAdena : levelGapChanceToDrop))
|
||||||
if (dropItem.getItemId() == Inventory.ADENA_ID)
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
|
|
||||||
}
|
|
||||||
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,19 +721,36 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create list
|
// create lists
|
||||||
|
if (randomDrops == null)
|
||||||
|
{
|
||||||
|
randomDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
|
}
|
||||||
if (calculatedDrops == null)
|
if (calculatedDrops == null)
|
||||||
{
|
{
|
||||||
calculatedDrops = new ArrayList<>();
|
calculatedDrops = new ArrayList<>(dropOccurrenceCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally
|
// finally
|
||||||
if (dropItem.getChance() < 100)
|
if (dropItem.getChance() < 100)
|
||||||
{
|
{
|
||||||
dropOccurrenceCounter--;
|
dropOccurrenceCounter--;
|
||||||
|
randomDrops.add(drop);
|
||||||
}
|
}
|
||||||
calculatedDrops.add(drop);
|
calculatedDrops.add(drop);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// add temporarily removed item when not replaced
|
||||||
|
if ((dropOccurrenceCounter > 0) && (replacedItem != null) && (calculatedDrops != null))
|
||||||
|
{
|
||||||
|
calculatedDrops.add(replacedItem);
|
||||||
|
}
|
||||||
|
// clear random drops
|
||||||
|
if (randomDrops != null)
|
||||||
|
{
|
||||||
|
randomDrops.clear();
|
||||||
|
randomDrops = null;
|
||||||
|
}
|
||||||
|
|
||||||
// champion extra drop
|
// champion extra drop
|
||||||
if (victim.isChampion())
|
if (victim.isChampion())
|
||||||
|
|||||||
+9
-4
@@ -17,6 +17,8 @@
|
|||||||
package handlers.bypasshandlers;
|
package handlers.bypasshandlers;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -324,8 +326,8 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
private static String getDropListButtons(Npc npc)
|
private static String getDropListButtons(Npc npc)
|
||||||
{
|
{
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList(DropType.DROP);
|
final List<DropHolder> dropListDeath = npc.getTemplate().getDropList();
|
||||||
final List<DropHolder> dropListSpoil = npc.getTemplate().getDropList(DropType.SPOIL);
|
final List<DropHolder> dropListSpoil = npc.getTemplate().getSpoilList();
|
||||||
if ((dropListDeath != null) || (dropListSpoil != null))
|
if ((dropListDeath != null) || (dropListSpoil != null))
|
||||||
{
|
{
|
||||||
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
sb.append("<table width=275 cellpadding=0 cellspacing=0><tr>");
|
||||||
@@ -346,12 +348,15 @@ public class NpcViewMod implements IBypassHandler
|
|||||||
|
|
||||||
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
private void sendNpcDropList(PlayerInstance player, Npc npc, DropType dropType, int pageValue)
|
||||||
{
|
{
|
||||||
final List<DropHolder> dropList = npc.getTemplate().getDropList(dropType);
|
final List<DropHolder> templateList = dropType == DropType.SPOIL ? npc.getTemplate().getSpoilList() : npc.getTemplate().getDropList();
|
||||||
if (dropList == null)
|
if (templateList == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<DropHolder> dropList = new ArrayList<>(templateList);
|
||||||
|
Collections.sort(dropList, (d1, d2) -> Integer.valueOf(d1.getItemId()).compareTo(Integer.valueOf(d2.getItemId())));
|
||||||
|
|
||||||
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
int pages = dropList.size() / DROP_LIST_ITEMS_PER_PAGE;
|
||||||
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
if ((DROP_LIST_ITEMS_PER_PAGE * pages) < dropList.size())
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -104,16 +104,16 @@ public class DropSearchBoard implements IParseBoardHandler
|
|||||||
|
|
||||||
private void buildDropIndex()
|
private void buildDropIndex()
|
||||||
{
|
{
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.DROP) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getDropList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.DROP))
|
for (DropHolder dropHolder : npcTemplate.getDropList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NpcData.getInstance().getTemplates(npc -> npc.getDropList(DropType.SPOIL) != null).forEach(npcTemplate ->
|
NpcData.getInstance().getTemplates(npc -> npc.getSpoilList() != null).forEach(npcTemplate ->
|
||||||
{
|
{
|
||||||
for (DropHolder dropHolder : npcTemplate.getDropList(DropType.SPOIL))
|
for (DropHolder dropHolder : npcTemplate.getSpoilList())
|
||||||
{
|
{
|
||||||
addToDropList(npcTemplate, dropHolder);
|
addToDropList(npcTemplate, dropHolder);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-29
@@ -98,7 +98,7 @@ public class NpcData implements IXmlReader
|
|||||||
final StatSet set = new StatSet(new HashMap<>());
|
final StatSet set = new StatSet(new HashMap<>());
|
||||||
final int npcId = parseInteger(attrs, "id");
|
final int npcId = parseInteger(attrs, "id");
|
||||||
final int level = parseInteger(attrs, "level", 85);
|
final int level = parseInteger(attrs, "level", 85);
|
||||||
final String type;
|
final String type = parseString(attrs, "type");
|
||||||
Map<String, Object> parameters = null;
|
Map<String, Object> parameters = null;
|
||||||
Map<Integer, Skill> skills = null;
|
Map<Integer, Skill> skills = null;
|
||||||
Set<Integer> clans = null;
|
Set<Integer> clans = null;
|
||||||
@@ -107,7 +107,6 @@ public class NpcData implements IXmlReader
|
|||||||
set.set("id", npcId);
|
set.set("id", npcId);
|
||||||
set.set("displayId", parseInteger(attrs, "displayId"));
|
set.set("displayId", parseInteger(attrs, "displayId"));
|
||||||
set.set("level", level);
|
set.set("level", level);
|
||||||
type = parseString(attrs, "type");
|
|
||||||
set.set("type", type);
|
set.set("type", type);
|
||||||
set.set("name", parseString(attrs, "name"));
|
set.set("name", parseString(attrs, "name"));
|
||||||
set.set("usingServerSideName", parseBoolean(attrs, "usingServerSideName"));
|
set.set("usingServerSideName", parseBoolean(attrs, "usingServerSideName"));
|
||||||
@@ -211,10 +210,10 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "attribute":
|
case "attribute":
|
||||||
{
|
{
|
||||||
for (Node attribute_node = statsNode.getFirstChild(); attribute_node != null; attribute_node = attribute_node.getNextSibling())
|
for (Node attributeNode = statsNode.getFirstChild(); attributeNode != null; attributeNode = attributeNode.getNextSibling())
|
||||||
{
|
{
|
||||||
attrs = attribute_node.getAttributes();
|
attrs = attributeNode.getAttributes();
|
||||||
switch (attribute_node.getNodeName().toLowerCase())
|
switch (attributeNode.getNodeName().toLowerCase())
|
||||||
{
|
{
|
||||||
case "attack":
|
case "attack":
|
||||||
{
|
{
|
||||||
@@ -428,16 +427,17 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
case "droplists":
|
case "droplists":
|
||||||
{
|
{
|
||||||
for (Node drop_lists_node = npcNode.getFirstChild(); drop_lists_node != null; drop_lists_node = drop_lists_node.getNextSibling())
|
for (Node dropListsNode = npcNode.getFirstChild(); dropListsNode != null; dropListsNode = dropListsNode.getNextSibling())
|
||||||
{
|
{
|
||||||
DropType dropType = null;
|
DropType dropType = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dropType = Enum.valueOf(DropType.class, drop_lists_node.getNodeName().toUpperCase());
|
dropType = Enum.valueOf(DropType.class, dropListsNode.getNodeName().toUpperCase());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
// Handled bellow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropType != null)
|
if (dropType != null)
|
||||||
@@ -447,16 +447,15 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists = new ArrayList<>();
|
dropLists = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Node drop_node = drop_lists_node.getFirstChild(); drop_node != null; drop_node = drop_node.getNextSibling())
|
for (Node dropNode = dropListsNode.getFirstChild(); dropNode != null; dropNode = dropNode.getNextSibling())
|
||||||
{
|
{
|
||||||
final NamedNodeMap drop_attrs = drop_node.getAttributes();
|
final NamedNodeMap dropAttrs = dropNode.getAttributes();
|
||||||
if ("item".equals(drop_node.getNodeName().toLowerCase()))
|
if ("item".equalsIgnoreCase(dropNode.getNodeName()))
|
||||||
{
|
{
|
||||||
final double chance = parseDouble(drop_attrs, "chance");
|
final DropHolder dropItem = new DropHolder(dropType, parseInteger(dropAttrs, "id"), parseLong(dropAttrs, "min"), parseLong(dropAttrs, "max"), parseDouble(dropAttrs, "chance"));
|
||||||
final DropHolder dropItem = new DropHolder(dropType, parseInteger(drop_attrs, "id"), parseLong(drop_attrs, "min"), parseLong(drop_attrs, "max"), dropType == DropType.LUCKY ? chance / 100 : chance);
|
if (ItemTable.getInstance().getTemplate(parseInteger(dropAttrs, "id")) == null)
|
||||||
if (ItemTable.getInstance().getTemplate(parseInteger(drop_attrs, "id")) == null)
|
|
||||||
{
|
{
|
||||||
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(drop_attrs, "id") + ".");
|
LOGGER.warning("DropListItem: Could not find item with id " + parseInteger(dropAttrs, "id") + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -468,16 +467,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "extenddrop":
|
|
||||||
{
|
|
||||||
final List<Integer> extendDrop = new ArrayList<>();
|
|
||||||
forEach(npcNode, "id", idNode ->
|
|
||||||
{
|
|
||||||
extendDrop.add(Integer.parseInt(idNode.getTextContent()));
|
|
||||||
});
|
|
||||||
set.set("extendDrop", extendDrop);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "collision":
|
case "collision":
|
||||||
{
|
{
|
||||||
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
for (Node collisionNode = npcNode.getFirstChild(); collisionNode != null; collisionNode = collisionNode.getNextSibling())
|
||||||
@@ -643,6 +632,7 @@ public class NpcData implements IXmlReader
|
|||||||
dropLists.add(new DropHolder(DropType.DROP, Inventory.LCOIN_ID, Config.LCOIN_MIN_QUANTITY, Config.LCOIN_MAX_QUANTITY, Config.LCOIN_DROP_CHANCE));
|
dropLists.add(new DropHolder(DropType.DROP, Inventory.LCOIN_ID, Config.LCOIN_MIN_QUANTITY, Config.LCOIN_MAX_QUANTITY, Config.LCOIN_DROP_CHANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collections.shuffle(dropLists);
|
||||||
for (DropHolder dropHolder : dropLists)
|
for (DropHolder dropHolder : dropLists)
|
||||||
{
|
{
|
||||||
// Drop materials for random craft configuration.
|
// Drop materials for random craft configuration.
|
||||||
@@ -654,7 +644,7 @@ public class NpcData implements IXmlReader
|
|||||||
switch (dropHolder.getDropType())
|
switch (dropHolder.getDropType())
|
||||||
{
|
{
|
||||||
case DROP:
|
case DROP:
|
||||||
case LUCKY: // TODO: Luck is added to death drops.
|
case LUCKY: // Lucky drops are added to normal drops and calculated later.
|
||||||
{
|
{
|
||||||
template.addDrop(dropHolder);
|
template.addDrop(dropHolder);
|
||||||
break;
|
break;
|
||||||
@@ -668,9 +658,7 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!template.getParameters().getMinionList("Privates").isEmpty())
|
if (!template.getParameters().getMinionList("Privates").isEmpty() && (template.getParameters().getSet().get("SummonPrivateRate") == null))
|
||||||
{
|
|
||||||
if (template.getParameters().getSet().get("SummonPrivateRate") == null)
|
|
||||||
{
|
{
|
||||||
_masterMonsterIDs.add(template.getId());
|
_masterMonsterIDs.add(template.getId());
|
||||||
}
|
}
|
||||||
@@ -679,7 +667,6 @@ public class NpcData implements IXmlReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a clan id if it doesnt exists.
|
* Gets or creates a clan id if it doesnt exists.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user