1package com.osroyale.game.world.entity.mob.npc.drop;
3import com.osroyale.Config;
4import com.osroyale.content.CrystalChest;
5import com.osroyale.content.ItemCreation;
6import com.osroyale.content.achievement.AchievementHandler;
7import com.osroyale.content.achievement.AchievementKey;
8import com.osroyale.content.collectionlog.CollectionLog;
9import com.osroyale.content.pet.PetData;
10import com.osroyale.content.pet.Pets;
11import com.osroyale.content.skill.impl.prayer.AshData;
12import com.osroyale.content.skill.impl.prayer.BoneData;
13import com.osroyale.game.world.World;
14import com.osroyale.game.world.entity.mob.npc.Npc;
15import com.osroyale.game.world.entity.mob.player.Player;
16import com.osroyale.game.world.entity.mob.player.PlayerRight;
17import com.osroyale.game.world.entity.skill.Skill;
18import com.osroyale.game.world.items.Item;
19import com.osroyale.game.world.items.ground.GroundItem;
20import com.osroyale.game.world.position.Position;
21import com.osroyale.net.discord.DiscordPlugin;
22import com.osroyale.net.packet.out.SendMessage;
23import com.osroyale.net.packet.out.SendScreenshot;
24import com.osroyale.util.Items;
25import com.osroyale.util.RandomGen;
26import com.osroyale.util.Utility;
27import plugin.itemon.item.LootingBagPlugin;
29import java.util.Arrays;
30import java.util.HashMap;
70* The manager
class which holds the static entries of drop tables and has
71 * a method to execute a drop table from the specified npc.
73 * @author <a href=
"http://www.rune-server.org/members/stand+up/">Stand Up</a>
76public final class NpcDropManager {
81 public static final Map<Integer, NpcDropTable> NPC_DROPS =
new HashMap<>();
86 private static final int[] ALTERNATIVE_POSITION = {2044, 2043, 2042, 494, 8060};
89 private static final boolean USE_NEW_SYSTEM =
true;
94 public static void drop(Player killer, Npc npc) {
103 if (USE_NEW_SYSTEM) {
104 rollDrop(killer, npc);
105 AchievementHandler.activate(killer, AchievementKey.NPCS);
109 NpcDropTable table = NPC_DROPS.get(npc.id);
115 RandomGen gen =
new RandomGen();
116 List<NpcDrop> npc_drops = table.generate(killer,
false);
117 Position dropPosition = npc.getPosition().copy();
120 if (checkAlternativePosition(npc.id)) {
121 dropPosition = killer.getPosition().copy();
125 if (npc.getMaximumHealth() > 50 && Utility.random(150) <= 5) {
126 Item crystal_key = Utility.randomElement(CrystalChest.KEY_HALVES);
127 GroundItem.create(killer, crystal_key, dropPosition);
128 killer.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + crystal_key.getName()));
129 AchievementHandler.activate(killer, AchievementKey.RARE_DROPS);
133 if (npc.getMaximumHealth() > 10 && Utility.random(200) <= 10) {
134 Item casket =
new Item(405);
135 GroundItem.create(killer, casket, dropPosition);
136 killer.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + casket.getName(),
true));
137 AchievementHandler.activate(killer, AchievementKey.RARE_DROPS);
141 for (NpcDrop drop : npc_drops) {
142 Item item = drop.toItem(gen);
144 if (item.getId() == 11941 && (killer.playerAssistant.contains(
new Item(LootingBagPlugin.OPENED_ID)) || killer.playerAssistant.contains(item))) {
145 killer.message(
true,
"You have missed out on " + Utility.getAOrAn(item.getName()) +
" " + item.getName() +
" since you already have on on your account.");
154 if (killer.settings.dropNotification && item.getValue() > 1_000_000) {
155 String name = item.getName();
156 killer.send(
new SendMessage(
"<col=BA383E>Exotic Drop Notification: </col>" + name +
" (" + Utility.formatDigits(item.getValue()) +
" coins)"));
157 World.sendMessage(
"<col=BA383E>Tarnish: <col=" + killer.right.getColor() +
">" + killer.getName() +
" </col>has just received " + Utility.getAOrAn(name) +
" <col=BA383E>" + name +
" </col>from <col=BA383E>" + npc.getName() +
"</col>!");
158 DiscordPlugin.sendSimpleMessage(killer.getName() +
" has just received " + Utility.getAOrAn(name) +
" " + name +
" from " + npc.getName() +
"!");
159 if (killer.settings.screenshotKill) {
160 killer.getPlayer().send(
new SendScreenshot());
162 }
else if (killer.settings.dropNotification && item.getValue() > 100_000) {
163 String name = item.getName();
164 killer.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + name +
" (" + Utility.formatDigits(item.getValue()) +
" coins)"));
165 AchievementHandler.activate(killer, AchievementKey.RARE_DROPS);
166 }
else if (killer.settings.untradeableNotification && !item.isTradeable()) {
167 killer.send(
new SendMessage(
"<col=F5424B>Untradeable Drop Notification: </col>" + item.getName()));
170 CollectionLog.checkItemDrop(killer, npc.id, item.getId(), item.getAmount());
172 if (npc.id == 494 && item.getId() == 11907) {
173 tridentRunes(killer, dropPosition);
176 if (!item.isStackable()) {
177 Item single = item.createWithAmount(1);
178 for (
int i = 0; i < item.getAmount(); i++)
179 GroundItem.create(killer, single, dropPosition);
181 GroundItem.create(killer, item, dropPosition);
186 private static void tridentRunes(Player killer, Position dropPosition) {
187 List<Item> fullChargeItems = Arrays.asList(
188 new Item(Items.DEATH_RUNE, 2500),
new Item(Items.CHAOS_RUNE, 2500),
189 new Item(Items.FIRE_RUNE, 12500),
new Item(Items.COINS, 25000)
192 fullChargeItems.forEach(item -> GroundItem.create(killer, item, dropPosition));
195 private static void handleBoneCrusher(Player player, BoneData bone) {
196 if (bone ==
null) {
return; }
198 var exp = (bone.getExperience() * Config.PRAYER_MODIFICATION);
199 player.skills.addExperience(Skill.PRAYER, exp);
200 AchievementHandler.activate(player, AchievementKey.BURY_BONES, 1);
202 if (player.equipment.hasAmulet() && player.equipment.getAmuletSlot().getId() == 22111) {
203 int current = player.skills.getLevel(Skill.PRAYER);
204 int maximum = player.skills.getMaxLevel(Skill.PRAYER);
206 if (current < maximum) {
207 int points = bone.getBoneAmulet();
209 if (current + points > maximum) {
210 points = maximum - current;
213 player.skills.get(Skill.PRAYER).addLevel(points);
214 player.skills.refresh(Skill.PRAYER);
215 player.message(
"You feel your " + player.equipment.getAmuletSlot().getName() +
" vibrate as you bury the bone.");
220 private static void handleAshSanctifier(Player player, AshData ashes) {
221 if (ashes ==
null) {
return; }
222 var exp = (ashes.getExperience() * Config.PRAYER_MODIFICATION);
223 player.skills.addExperience(Skill.PRAYER, exp);
226 private static NpcDrop rollDrop(Player player, Npc npc) {
228 NpcDropTable table = NPC_DROPS.get(npc.id);
229 Position dropPos = npc.getPosition().copy();
230 if (checkAlternativePosition(npc.id)) {
231 dropPos = player.getPosition().copy();
236 handleMiscDrops(player, npc);
237 NpcDrop[] drops = table.drops;
238 for (NpcDrop drop : drops) {
239 if (drop.getWeight() == 0) {
240 Item item = drop.toItem(
new RandomGen());
241 if (BoneData.forId(item.getId()).isPresent() && !item.isNoted() && player.inventory.contains(Items.BONECRUSHER)) {
242 handleBoneCrusher(player, BoneData.forId(item.getId()).get());
245 if (AshData.forId(item.getId()).isPresent() && !item.isNoted() && player.inventory.contains(25781)) {
246 handleAshSanctifier(player, AshData.forId(item.getId()).get());
252 if(PetData.forItem(item.getId()).isPresent()) {
253 Pets.onReward(player, item.getId());
255 GroundItem.create(player, item, dropPos);
259 WeightedCollection<NpcDrop> rc =
new WeightedCollection<>();
260 for (NpcDrop drop : drops) {
261 double drOffset = 1 + (PlayerRight.getDropRateBonus(player) / 100.0);
262 int weightMultiplier = 1;
263 double dropChance = (drop.getWeight() * weightMultiplier) / drOffset;
264 if (dropChance < 1) {
267 double weight = 1.0 / dropChance;
268 if (drop.getWeight() != 0) {
269 rc.add(weight, drop);
273 double weightSum = rc.getTotal();
275 if (Math.random() <= weightSum) {
276 NpcDrop selectedDrop = rc.next();
277 Item item = selectedDrop.toItem(
new RandomGen());
278 handleMessages(player, npc, item);
282 if (npc.id == 494 && item.getId() == 11907) {
283 tridentRunes(player, dropPos);
285 if(PetData.forItem(item.getId()).isPresent()) {
286 Pets.onReward(player, item.getId());
288 GroundItem.create(player, item, dropPos);
290 CollectionLog.checkItemDrop(player, npc.id, item.getId(), item.getAmount());
297 private static void handleMiscDrops(Player player, Npc npc) {
298 Position dropPosition = npc.getPosition().copy();
299 if (checkAlternativePosition(npc.id)) {
300 dropPosition = player.getPosition().copy();
302 if (npc.getMaximumHealth() > 50 && Utility.random(150) <= 5) {
303 Item crystal_key = Utility.randomElement(CrystalChest.KEY_HALVES);
304 GroundItem.create(player, crystal_key, dropPosition);
305 player.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + crystal_key.getName()));
306 AchievementHandler.activate(player, AchievementKey.RARE_DROPS);
310 if (npc.getMaximumHealth() > 10 && Utility.random(200) <= 10) {
311 Item casket =
new Item(405);
312 GroundItem.create(player, casket, dropPosition);
313 player.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + casket.getName(),
true));
314 AchievementHandler.activate(player, AchievementKey.RARE_DROPS);
318 private static void handleMessages(Player player, Npc npc, Item item) {
319 if (item.getId() == 11941 && (player.playerAssistant.contains(
new Item(LootingBagPlugin.OPENED_ID)) || player.playerAssistant.contains(item))) {
320 player.message(
"You have missed out on " + Utility.getAOrAn(item.getName()) +
" " + item.getName() +
" since you already have on on your account.");
324 if (player.settings.dropNotification && item.getValue() > 1_000_000) {
325 String name = item.getName();
326 player.send(
new SendMessage(
"<col=BA383E>Exotic Drop Notification: </col>" + name +
" (" + Utility.formatDigits(item.getValue()) +
" coins)"));
327 World.sendMessage(
"<col=BA383E>Tarnish: <col=" + player.right.getColor() +
">" + player.getName() +
" </col>has just received " + Utility.getAOrAn(name) +
" <col=BA383E>" + name +
" </col>from <col=BA383E>" + npc.getName() +
"</col>!");
328 DiscordPlugin.sendSimpleMessage(
"Exotic drop: " + player.getName() +
" has just received " + Utility.getAOrAn(name) +
" " + name +
" from " + npc.getName() +
"!");
329 AchievementHandler.activate(player, AchievementKey.RARE_DROPS);
330 if (player.settings.screenshotKill) {
331 player.getPlayer().send(
new SendScreenshot());
333 }
else if (player.settings.dropNotification && item.getValue() > 100_000) {
334 String name = item.getName();
335 player.send(
new SendMessage(
"<col=BA383E>Rare Drop Notification: </col>" + name +
" (" + Utility.formatDigits(item.getValue()) +
" coins)"));
336 AchievementHandler.activate(player, AchievementKey.RARE_DROPS);
337 }
else if (player.settings.untradeableNotification && !item.isTradeable()) {
338 player.send(
new SendMessage(
"<col=F5424B>Untradeable Drop Notification: </col>" + item.getName()));
342 private static boolean checkAlternativePosition(
int npc) {
343 for (
int alternative : ALTERNATIVE_POSITION) {
344 if (alternative == npc)