diff --git a/runelite-client/src/main/java/net/runelite/client/game/LootManager.java b/runelite-client/src/main/java/net/runelite/client/game/LootManager.java index a2c10cf04b..ddd8157502 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/LootManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/LootManager.java @@ -38,12 +38,13 @@ import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.AnimationID; import net.runelite.api.Client; -import net.runelite.api.TileItem; import net.runelite.api.ItemID; import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; import net.runelite.api.NpcID; import net.runelite.api.Player; import net.runelite.api.Tile; +import net.runelite.api.TileItem; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; @@ -51,6 +52,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.ItemDespawned; import net.runelite.api.events.ItemQuantityChanged; import net.runelite.api.events.ItemSpawned; +import net.runelite.api.events.NpcChanged; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.PlayerDespawned; import net.runelite.client.eventbus.EventBus; @@ -73,6 +75,9 @@ public class LootManager private WorldPoint playerLocationLastTick; private WorldPoint krakenPlayerLocation; + private NPC delayedLootNpc; + private int delayedLootTickLimit; + @Inject private LootManager(EventBus eventBus, Client client) { @@ -84,6 +89,13 @@ public class LootManager public void onNpcDespawned(NpcDespawned npcDespawned) { final NPC npc = npcDespawned.getNpc(); + + if (npc == delayedLootNpc) + { + delayedLootNpc = null; + delayedLootTickLimit = 0; + } + if (!npc.isDead()) { int id = npc.getId(); @@ -219,14 +231,61 @@ public class LootManager } } + @Subscribe + public void onNpcChanged(NpcChanged npcChanged) + { + final NPC npc = npcChanged.getNpc(); + if (npc.getId() == NpcID.THE_NIGHTMARE_9433) + { + delayedLootNpc = npc; + delayedLootTickLimit = 15; + } + } + @Subscribe public void onGameTick(GameTick gameTick) { + if (delayedLootNpc != null && delayedLootTickLimit-- > 0) + { + processDelayedLoot(); + } + playerLocationLastTick = client.getLocalPlayer().getWorldLocation(); + itemSpawns.clear(); killPoints.clear(); } + private void processDelayedLoot() + { + final WorldPoint adjacentLootTile = getAdjacentSquareLootTile(delayedLootNpc); + final LocalPoint localPoint = LocalPoint.fromWorld(client, adjacentLootTile); + + if (localPoint == null) + { + log.debug("Scene changed away from delayed loot location"); + delayedLootNpc = null; + delayedLootTickLimit = 0; + return; + } + + final int sceneX = localPoint.getSceneX(); + final int sceneY = localPoint.getSceneY(); + final int packed = sceneX << 8 | sceneY; + final List itemStacks = itemSpawns.get(packed); + if (itemStacks.isEmpty()) + { + // no loot yet + return; + } + + log.debug("Got delayed loot stack from {}: {}", delayedLootNpc.getName(), itemStacks); + eventBus.post(new NpcLootReceived(delayedLootNpc, itemStacks)); + + delayedLootNpc = null; + delayedLootTickLimit = 0; + } + private void processNpcLoot(NPC npc) { final LocalPoint location = LocalPoint.fromWorld(client, getDropLocation(npc, npc.getWorldLocation())); @@ -316,4 +375,32 @@ public class LootManager return worldLocation; } + + private WorldPoint getAdjacentSquareLootTile(NPC npc) + { + final NPCComposition composition = npc.getComposition(); + final WorldPoint worldLocation = npc.getWorldLocation(); + int x = worldLocation.getX(); + int y = worldLocation.getY(); + + if (playerLocationLastTick.getX() < x) + { + x -= 1; + } + else + { + x += Math.min(playerLocationLastTick.getX() - x, composition.getSize()); + } + + if (playerLocationLastTick.getY() < y) + { + y -= 1; + } + else + { + y += Math.min(playerLocationLastTick.getY() - y, composition.getSize()); + } + + return new WorldPoint(x, y, worldLocation.getPlane()); + } }