RuneHive-Game
Loading...
Searching...
No Matches
NpcDropManager.java
Go to the documentation of this file.
1package com.runehive.game.world.entity.mob.npc.drop;
2
3import com.runehive.Config;
4import com.runehive.content.CrystalChest;
5import com.runehive.content.ItemCreation;
6import com.runehive.content.achievement.AchievementHandler;
7import com.runehive.content.achievement.AchievementKey;
8import com.runehive.content.collectionlog.CollectionLog;
9import com.runehive.content.pet.PetData;
10import com.runehive.content.pet.Pets;
11import com.runehive.content.skill.impl.prayer.AshData;
12import com.runehive.content.skill.impl.prayer.BoneData;
13import com.runehive.game.world.World;
14import com.runehive.game.world.entity.mob.npc.Npc;
15import com.runehive.game.world.entity.mob.player.Player;
16import com.runehive.game.world.entity.mob.player.PlayerRight;
17import com.runehive.game.world.entity.skill.Skill;
18import com.runehive.game.world.items.Item;
19import com.runehive.game.world.items.ground.GroundItem;
20import com.runehive.game.world.position.Position;
21import com.runehive.net.packet.out.SendMessage;
22import com.runehive.net.packet.out.SendScreenshot;
23import com.runehive.util.Items;
24import com.runehive.util.RandomGen;
25import com.runehive.util.Utility;
26import plugin.itemon.item.LootingBagPlugin;
27
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.List;
31import java.util.Map;
32
33/**
34 * The manager class which holds the static entries of drop tables and has
35 * a method to execute a drop table from the specified npc.
36 *
37 * @author <a href="https://runehive.com">Stand Up</a>
38 * @since 29-1-2017.
39 */
40public final class NpcDropManager {
41
42 /**
43 * The collection of npc ids by their representative drop tables.
44 */
45 public static final Map<Integer, NpcDropTable> NPC_DROPS = new HashMap<>();
46
47 /**
48 * Alternative drop positions for mobs (i.e kraken, zulrah)
49 */
50 private static final int[] ALTERNATIVE_POSITION = {2044, 2043, 2042, 494, 8060};
51
52 // use new drop system
53 private static final boolean USE_NEW_SYSTEM = true;
54
55 /**
56 * Attempts to drop the drop table which belongs to {@code npc#id}.
57 */
58 public static void drop(Player killer, Npc npc) {
59 if (killer == null) {
60 return;
61 }
62
63 if (npc == null) {
64 return;
65 }
66
67 if (USE_NEW_SYSTEM) {
68 rollDrop(killer, npc);
70 return;
71 }
72
73 NpcDropTable table = NPC_DROPS.get(npc.id);
74
75 if (table == null) {
76 return;
77 }
78
79 RandomGen gen = new RandomGen();
80 List<NpcDrop> npc_drops = table.generate(killer, false);
81 Position dropPosition = npc.getPosition().copy();
82
83 // special drop positions
85 dropPosition = killer.getPosition().copy();
86 }
87
88 // crystal key drop
89 if (npc.getMaximumHealth() > 50 && Utility.random(150) <= 5) {
91 GroundItem.create(killer, crystal_key, dropPosition);
92 killer.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + crystal_key.getName()));
94 }
95
96 // casket drop
97 if (npc.getMaximumHealth() > 10 && Utility.random(200) <= 10) {
98 Item casket = new Item(405);
99 GroundItem.create(killer, casket, dropPosition);
100 killer.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + casket.getName(), true));
102 }
103
104 // drop table
105 for (NpcDrop drop : npc_drops) {
106 Item item = drop.toItem(gen);
107
108 if (item.getId() == 11941 && (killer.playerAssistant.contains(new Item(LootingBagPlugin.OPENED_ID)) || killer.playerAssistant.contains(item))) { // looting bag
109 killer.message(true, "You have missed out on " + Utility.getAOrAn(item.getName()) + " " + item.getName() + " since you already have on on your account.");
110 continue;
111 }
112
113// if (killer.clanChannel != null && killer.clanChannel.lootshareEnabled()) {
114// killer.forClan(channel -> channel.splitLoot(killer, npc, item));
115// return;
116// }
117
118 if (killer.settings.dropNotification && item.getValue() > 1_000_000) {
119 String name = item.getName();
120 killer.send(new SendMessage("<col=BA383E>Exotic Drop Notification: </col>" + name + " (" + Utility.formatDigits(item.getValue()) + " coins)"));
121 World.sendMessage("<col=BA383E>osroyale: <col=" + killer.right.getColor() + ">" + killer.getName() + " </col>has just received " + Utility.getAOrAn(name) + " <col=BA383E>" + name + " </col>from <col=BA383E>" + npc.getName() + "</col>!");
122 // DiscordPlugin.sendSimpleMessage(killer.getName() + " has just received " + Utility.getAOrAn(name) + " " + name + " from " + npc.getName() + "!");
123 if (killer.settings.screenshotKill) {
124 killer.getPlayer().send(new SendScreenshot());
125 }
126 } else if (killer.settings.dropNotification && item.getValue() > 100_000) {
127 String name = item.getName();
128 killer.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + name + " (" + Utility.formatDigits(item.getValue()) + " coins)"));
130 } else if (killer.settings.untradeableNotification && !item.isTradeable()) {
131 killer.send(new SendMessage("<col=F5424B>Untradeable Drop Notification: </col>" + item.getName()));
132 }
133
134 CollectionLog.checkItemDrop(killer, npc.id, item.getId(), item.getAmount());
135
136 if (npc.id == 494 && item.getId() == 11907) {
137 tridentRunes(killer, dropPosition);
138 }
139
140 if (!item.isStackable()) {
141 Item single = item.createWithAmount(1);
142 for (int i = 0; i < item.getAmount(); i++)
143 GroundItem.create(killer, single, dropPosition);
144 } else {
145 GroundItem.create(killer, item, dropPosition);
146 }
147 }
148 }
149
150 private static void tridentRunes(Player killer, Position dropPosition) {
151 List<Item> fullChargeItems = Arrays.asList(
152 new Item(Items.DEATH_RUNE, 2500), new Item(Items.CHAOS_RUNE, 2500),
153 new Item(Items.FIRE_RUNE, 12500), new Item(Items.COINS, 25000)
154 );
155
156 fullChargeItems.forEach(item -> GroundItem.create(killer, item, dropPosition));
157 }
158
159 private static void handleBoneCrusher(Player player, BoneData bone) {
160 if (bone == null) { return; }
161
162 var exp = (bone.getExperience() * Config.PRAYER_MODIFICATION);
163 player.skills.addExperience(Skill.PRAYER, exp);
165
166 if (player.equipment.hasAmulet() && player.equipment.getAmuletSlot().getId() == 22111) {
167 int current = player.skills.getLevel(Skill.PRAYER);
168 int maximum = player.skills.getMaxLevel(Skill.PRAYER);
169
170 if (current < maximum) {
171 int points = bone.getBoneAmulet();
172
173 if (current + points > maximum) {
174 points = maximum - current;
175 }
176
177 player.skills.get(Skill.PRAYER).addLevel(points);
178 player.skills.refresh(Skill.PRAYER);
179 player.message("You feel your " + player.equipment.getAmuletSlot().getName() + " vibrate as you bury the bone.");
180 }
181 }
182 }
183
184 private static void handleAshSanctifier(Player player, AshData ashes) {
185 if (ashes == null) { return; }
186 var exp = (ashes.getExperience() * Config.PRAYER_MODIFICATION);
187 player.skills.addExperience(Skill.PRAYER, exp);
188 }
189
190 private static NpcDrop rollDrop(Player player, Npc npc) {
191 // player.send(new SendMessage("Called rollDrop"));
192 NpcDropTable table = NPC_DROPS.get(npc.id);
193 Position dropPos = npc.getPosition().copy();
195 dropPos = player.getPosition().copy();
196 }
197 if (table == null) {
198 return null;
199 }
201 NpcDrop[] drops = table.drops;
202 for (NpcDrop drop : drops) {
203 if (drop.getWeight() == 0) {
204 Item item = drop.toItem(new RandomGen());
205 if (BoneData.forId(item.getId()).isPresent() && !item.isNoted() && player.inventory.contains(Items.BONECRUSHER)) {
207 continue;
208 }
209 if (AshData.forId(item.getId()).isPresent() && !item.isNoted() && player.inventory.contains(25781)) {
211 continue;
212 }
213 /**
214 * Handle the pet roll if the item is a pet
215 */
216 if(PetData.forItem(item.getId()).isPresent()) {
217 Pets.onReward(player, item.getId());
218 } else {
219 GroundItem.create(player, item, dropPos);
220 }
221 }
222 }
224 for (NpcDrop drop : drops) {
225 double drOffset = 1 + (PlayerRight.getDropRateBonus(player) / 100.0); // dr bonus is in percent, conversion is 1 + (percent / 100.0)
226 int weightMultiplier = 1;
227 double dropChance = (drop.getWeight() * weightMultiplier) / drOffset;
228 if (dropChance < 1) {
229 dropChance = 1;
230 }
231 double weight = 1.0 / dropChance;
232 if (drop.getWeight() != 0) {
233 rc.add(weight, drop);
234 }
235 }
236
237 double weightSum = rc.getTotal();
238
239 if (Math.random() <= weightSum) {
240 NpcDrop selectedDrop = rc.next();
241 Item item = selectedDrop.toItem(new RandomGen());
242 handleMessages(player, npc, item);
243 /**
244 * Handle the pet roll if the item is a pet
245 */
246 if (npc.id == 494 && item.getId() == 11907) {
247 tridentRunes(player, dropPos);
248 }
249 if(PetData.forItem(item.getId()).isPresent()) {
250 Pets.onReward(player, item.getId());
251 } else {
252 GroundItem.create(player, item, dropPos);
253 }
255 return selectedDrop;
256 }
257
258 return null;
259 }
260
261 private static void handleMiscDrops(Player player, Npc npc) {
262 Position dropPosition = npc.getPosition().copy();
264 dropPosition = player.getPosition().copy();
265 }
266 if (npc.getMaximumHealth() > 50 && Utility.random(150) <= 5) {
268 GroundItem.create(player, crystal_key, dropPosition);
269 player.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + crystal_key.getName()));
271 }
272
273 // casket drop
274 if (npc.getMaximumHealth() > 10 && Utility.random(200) <= 10) {
275 Item casket = new Item(405);
276 GroundItem.create(player, casket, dropPosition);
277 player.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + casket.getName(), true));
279 }
280 }
281
282 private static void handleMessages(Player player, Npc npc, Item item) {
283 if (item.getId() == 11941 && (player.playerAssistant.contains(new Item(LootingBagPlugin.OPENED_ID)) || player.playerAssistant.contains(item))) { // looting bag
284 player.message("You have missed out on " + Utility.getAOrAn(item.getName()) + " " + item.getName() + " since you already have on on your account.");
285 return;
286 }
287
288 if (player.settings.dropNotification && item.getValue() > 1_000_000) {
289 String name = item.getName();
290 player.send(new SendMessage("<col=BA383E>Exotic Drop Notification: </col>" + name + " (" + Utility.formatDigits(item.getValue()) + " coins)"));
291 World.sendMessage("<col=BA383E>osroyale: <col=" + player.right.getColor() + ">" + player.getName() + " </col>has just received " + Utility.getAOrAn(name) + " <col=BA383E>" + name + " </col>from <col=BA383E>" + npc.getName() + "</col>!");
292 // DiscordPlugin.sendSimpleMessage("Exotic drop: " + player.getName() + " has just received " + Utility.getAOrAn(name) + " " + name + " from " + npc.getName() + "!");
294 if (player.settings.screenshotKill) {
295 player.getPlayer().send(new SendScreenshot());
296 }
297 } else if (player.settings.dropNotification && item.getValue() > 100_000) {
298 String name = item.getName();
299 player.send(new SendMessage("<col=BA383E>Rare Drop Notification: </col>" + name + " (" + Utility.formatDigits(item.getValue()) + " coins)"));
301 } else if (player.settings.untradeableNotification && !item.isTradeable()) {
302 player.send(new SendMessage("<col=F5424B>Untradeable Drop Notification: </col>" + item.getName()));
303 }
304 }
305
306 private static boolean checkAlternativePosition(int npc) {
307 for (int alternative : ALTERNATIVE_POSITION) {
308 if (alternative == npc)
309 return true;
310 }
311 return false;
312 }
313}
The class that contains setting-related constants for the server.
Definition Config.java:24
static final double PRAYER_MODIFICATION
The experience modification for prayer.
Definition Config.java:274
Handles opening the crystal chest.
static final Item[] KEY_HALVES
The two item key halves.
static void activate(Player player, AchievementKey achievement)
Activates the achievement for the individual player.
static void checkItemDrop(Player player, int npcId, int itemId, int amount)
Handles spawning, rewarding and picking up of pets.
Definition Pets.java:27
static void onReward(Player player, int item, int chance)
Handles calculating the chance of a player receiving a skilling pet.
Definition Pets.java:33
Represents the game world.
Definition World.java:46
static void sendMessage(String... messages)
Sends a global message.
Definition World.java:396
Represents a non-player character in the in-game world.
Definition Npc.java:29
Item toItem(RandomGen gen)
Converts this NpcDrop to an item.
Definition NpcDrop.java:37
The manager class which holds the static entries of drop tables and has a method to execute a drop ta...
static void drop(Player killer, Npc npc)
Attempts to drop the drop table which belongs to npc#id.
static void tridentRunes(Player killer, Position dropPosition)
static final int[] ALTERNATIVE_POSITION
Alternative drop positions for mobs (i.e kraken, zulrah)
static void handleMessages(Player player, Npc npc, Item item)
static void handleAshSanctifier(Player player, AshData ashes)
static final Map< Integer, NpcDropTable > NPC_DROPS
The collection of npc ids by their representative drop tables.
static void handleBoneCrusher(Player player, BoneData bone)
The class which represents a npc drop table.
final NpcDrop[] drops
The cached array of NpcDrops.
List< NpcDrop > generate(Player player, boolean simulated)
WeightedCollection< E > add(double weight, E result)
This class represents a character controlled by a player.
Definition Player.java:125
String getName()
Gets the name of this entity.
Definition Player.java:774
boolean untradeableNotification
The untradeable notification flag.
Definition Settings.java:21
boolean dropNotification
The drop notification flag.
Definition Settings.java:19
Represents a trainable and usable skill.
Definition Skill.java:18
static final int PRAYER
The prayer skill id.
Definition Skill.java:36
The container class that represents an item that can be interacted with.
Definition Item.java:21
final int getId()
Gets the identification of this item.
Definition Item.java:324
final int getAmount()
Gets the quantity of this item.
Definition Item.java:342
int getValue(PriceType type)
Gets the value for this item.
Definition Item.java:98
Item createWithAmount(int newAmount)
Creates a new item with newAmount and the same identifier as this instance.
Definition Item.java:158
Represents a single Ground item on the world map.
static GroundItem create(Player player, Item item)
Creates a new GroundItem object for a player and an item.
Represents a single tile on the game world.
Definition Position.java:14
Position copy()
Creates a deep copy of this location.
The OutgoingPacket that sends a message to a Players chatbox in the client.
static final int BONECRUSHER
Definition Items.java:13121
static final int CHAOS_RUNE
Definition Items.java:567
static final int COINS
Definition Items.java:1000
static final int DEATH_RUNE
Definition Items.java:565
static final int FIRE_RUNE
Definition Items.java:559
The ThreadLocalRandom wrapper that provides additional functionality for generating pseudo-random num...
Handles miscellaneous methods.
Definition Utility.java:27
static int random(int bound)
Definition Utility.java:239
static String formatDigits(final int amount)
Formats digits for integers.
Definition Utility.java:41
static< T > T randomElement(Collection< T > collection)
Picks a random element out of any array type.
Definition Utility.java:248
static String getAOrAn(String nextWord)
A or an.
Definition Utility.java:116
Holds the data for pets.
Definition PetData.java:14
static Optional< PetData > forItem(int id)
Gets the pet data based on the given item identification.
Definition PetData.java:485
static Optional< AshData > forId(int id)
Definition AshData.java:32
static Optional< BoneData > forId(int id)
Gets the bone data based on the item.
Definition BoneData.java:59
double getExperience()
Gets the experience of the bone.
Definition BoneData.java:50