Merge remote-tracking branch 'runelite/master'

This commit is contained in:
Owain van Brakel
2021-07-21 19:16:23 +02:00
41 changed files with 1877 additions and 78 deletions

View File

@@ -179,6 +179,18 @@ public interface ChatCommandsConfig extends Config
@ConfigItem(
position = 13,
keyName = "pets",
name = "Pets Command",
description = "Configures whether the player pet list command is enabled<br> !pets<br>" +
" Note: Update your pet list by looking at the All Pets tab in the Collection Log"
)
default boolean pets()
{
return true;
}
@ConfigItem(
position = 20,
keyName = "clearSingleWord",
name = "Clear Single Word",
description = "Enable hot key to clear single word at a time"
@@ -189,7 +201,7 @@ public interface ChatCommandsConfig extends Config
}
@ConfigItem(
position = 14,
position = 21,
keyName = "clearEntireChatBox",
name = "Clear Chat Box",
description = "Enable hotkey to clear entire chat box"

View File

@@ -28,14 +28,23 @@ package net.runelite.client.plugins.chatcommands;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
@@ -43,6 +52,7 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.IconID;
import net.runelite.api.IndexedSprite;
import net.runelite.api.ItemComposition;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
@@ -57,9 +67,11 @@ import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.vars.AccountType;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetID.ADVENTURE_LOG_ID;
import static net.runelite.api.widgets.WidgetID.COLLECTION_LOG_ID;
import static net.runelite.api.widgets.WidgetID.GENERIC_SCROLL_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.KILL_LOGS_GROUP_ID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatCommandManager;
import net.runelite.client.chat.ChatMessageBuilder;
@@ -72,6 +84,7 @@ import net.runelite.client.game.ItemManager;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.QuantityFormatter;
import net.runelite.client.util.Text;
import net.runelite.http.api.chat.ChatClient;
@@ -112,6 +125,7 @@ public class ChatCommandsPlugin extends Plugin
"(?:<br>Overall time: <col=ff0000>(?<otime>[0-9:]+(?:\\.[0-9]+)?)</col>(?: \\(new personal best\\)|. Personal best: (?<opb>[0-9:]+(?:\\.[0-9]+)?)))?");
private static final Pattern HS_KC_FLOOR_PATTERN = Pattern.compile("You have completed Floor (\\d) of the Hallowed Sepulchre! Total completions: <col=ff0000>([0-9,]+)</col>\\.");
private static final Pattern HS_KC_GHC_PATTERN = Pattern.compile("You have opened the Grand Hallowed Coffin <col=ff0000>([0-9,]+)</col> times?!");
private static final Pattern COLLECTION_LOG_ITEM_PATTERN = Pattern.compile("New item added to your collection log: (.*)");
private static final String TOTAL_LEVEL_COMMAND_STRING = "!total";
private static final String PRICE_COMMAND_STRING = "!price";
@@ -128,9 +142,11 @@ public class ChatCommandsPlugin extends Plugin
private static final String DUEL_ARENA_COMMAND = "!duels";
private static final String LEAGUE_POINTS_COMMAND = "!lp";
private static final String SOUL_WARS_ZEAL_COMMAND = "!sw";
private static final String PET_LIST_COMMAND = "!pets";
@VisibleForTesting
static final int ADV_LOG_EXPLOITS_TEXT_INDEX = 1;
static final int COL_LOG_ENTRY_HEADER_TITLE_INDEX = 0;
private static final Map<String, String> KILLCOUNT_RENAMES = ImmutableMap.of(
"Barrows chest", "Barrows Chests"
@@ -139,15 +155,20 @@ public class ChatCommandsPlugin extends Plugin
private boolean bossLogLoaded;
private boolean advLogLoaded;
private boolean scrollInterfaceLoaded;
private boolean collectionLogLoaded;
private String pohOwner;
private HiscoreEndpoint hiscoreEndpoint; // hiscore endpoint for current player
private String lastBossKill;
private int lastBossTime = -1;
private double lastPb = -1;
private int modIconIdx = -1;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ChatCommandsConfig config;
@@ -181,6 +202,9 @@ public class ChatCommandsPlugin extends Plugin
@Inject
private RuneLiteConfig runeLiteConfig;
@Inject
private Gson gson;
@Override
public void startUp()
{
@@ -201,6 +225,9 @@ public class ChatCommandsPlugin extends Plugin
chatCommandManager.registerCommandAsync(GC_COMMAND_STRING, this::gambleCountLookup, this::gambleCountSubmit);
chatCommandManager.registerCommandAsync(DUEL_ARENA_COMMAND, this::duelArenaLookup, this::duelArenaSubmit);
chatCommandManager.registerCommandAsync(SOUL_WARS_ZEAL_COMMAND, this::soulWarsZealLookup);
chatCommandManager.registerCommandAsync(PET_LIST_COMMAND, this::petListLookup, this::petListSubmit);
clientThread.invoke(this::loadPetIcons);
}
@Override
@@ -226,6 +253,7 @@ public class ChatCommandsPlugin extends Plugin
chatCommandManager.unregisterCommand(GC_COMMAND_STRING);
chatCommandManager.unregisterCommand(DUEL_ARENA_COMMAND);
chatCommandManager.unregisterCommand(SOUL_WARS_ZEAL_COMMAND);
chatCommandManager.unregisterCommand(PET_LIST_COMMAND);
}
@Provides
@@ -272,6 +300,69 @@ public class ChatCommandsPlugin extends Plugin
return personalBest == null ? 0 : personalBest;
}
private void loadPetIcons()
{
final IndexedSprite[] modIcons = client.getModIcons();
if (modIconIdx != -1 || modIcons == null)
{
return;
}
final Pet[] pets = Pet.values();
final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + pets.length);
modIconIdx = modIcons.length;
for (int i = 0; i < pets.length; i++)
{
final Pet pet = pets[i];
final BufferedImage image = ImageUtil.resizeImage(itemManager.getImage(pet.getIconID()), 18, 16);
final IndexedSprite sprite = ImageUtil.getImageIndexedSprite(image, client);
newModIcons[modIconIdx + i] = sprite;
}
client.setModIcons(newModIcons);
}
/**
* Sets the list of owned pets for the local player
*
* @param petList The total list of owned pets for the local player
*/
private void setPetList(List<Pet> petList)
{
if (petList == null)
{
return;
}
configManager.setRSProfileConfiguration("chatcommands", "pets",
gson.toJson(petList));
}
/**
* Looks up the list of owned pets for the local player
*/
private List<Pet> getPetList()
{
String petListJson = configManager.getRSProfileConfiguration("chatcommands", "pets",
String.class);
List<Pet> petList;
try
{
// CHECKSTYLE:OFF
petList = gson.fromJson(petListJson, new TypeToken<List<Pet>>(){}.getType());
// CHECKSTYLE:ON
}
catch (JsonSyntaxException ex)
{
return Collections.emptyList();
}
return petList != null ? petList : Collections.emptyList();
}
@Subscribe
public void onChatMessage(ChatMessage chatMessage)
{
@@ -431,6 +522,24 @@ public class ChatCommandsPlugin extends Plugin
lastBossKill = null;
lastBossTime = -1;
}
matcher = COLLECTION_LOG_ITEM_PATTERN.matcher(message);
if (matcher.find())
{
String item = matcher.group(1);
Pet pet = Pet.findPet(item);
if (pet != null)
{
List<Pet> petList = new ArrayList<>(getPetList());
if (!petList.contains(pet))
{
log.debug("New pet added: {}", pet);
petList.add(pet);
setPetList(petList);
}
}
}
}
@VisibleForTesting
@@ -490,6 +599,39 @@ public class ChatCommandsPlugin extends Plugin
}
}
if (collectionLogLoaded && (pohOwner == null || pohOwner.equals(client.getLocalPlayer().getName())))
{
collectionLogLoaded = false;
Widget collectionLogEntryHeader = client.getWidget(WidgetInfo.COLLECTION_LOG_ENTRY_HEADER);
if (collectionLogEntryHeader != null && collectionLogEntryHeader.getChildren() != null)
{
Widget entryTitle = collectionLogEntryHeader.getChild(COL_LOG_ENTRY_HEADER_TITLE_INDEX);
// Make sure that the player is looking in the All Pets tab of the collection log
if (entryTitle.getText().equals("All Pets"))
{
Widget collectionLogEntryItems = client.getWidget(WidgetInfo.COLLECTION_LOG_ENTRY_ITEMS);
if (collectionLogEntryItems != null && collectionLogEntryItems.getChildren() != null)
{
List<Pet> petList = new ArrayList<>();
for (Widget child : collectionLogEntryItems.getChildren())
{
if (child.getOpacity() == 0)
{
Pet pet = Pet.findPet(Text.removeTags(child.getName()));
if (pet != null)
{
petList.add(pet);
}
}
}
setPetList(petList);
}
}
}
}
if (bossLogLoaded && (pohOwner == null || pohOwner.equals(client.getLocalPlayer().getName())))
{
bossLogLoaded = false;
@@ -566,6 +708,9 @@ public class ChatCommandsPlugin extends Plugin
case ADVENTURE_LOG_ID:
advLogLoaded = true;
break;
case COLLECTION_LOG_ID:
collectionLogLoaded = true;
break;
case KILL_LOGS_GROUP_ID:
bossLogLoaded = true;
break;
@@ -583,6 +728,10 @@ public class ChatCommandsPlugin extends Plugin
case LOADING:
case HOPPING:
pohOwner = null;
break;
case LOGGED_IN:
loadPetIcons();
break;
}
}
@@ -999,6 +1148,103 @@ public class ChatCommandsPlugin extends Plugin
return true;
}
/**
* Looks up the pet list for the player who triggered !pets
*
* @param chatMessage The chat message containing the command.
* @param message The chat message in string format
* <p>
*/
private void petListLookup(ChatMessage chatMessage, String message)
{
if (!config.pets())
{
return;
}
ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATECHATOUT))
{
player = client.getLocalPlayer().getName();
}
else
{
player = Text.sanitize(chatMessage.getName());
}
Set<Integer> playerPetList;
try
{
playerPetList = chatClient.getPetList(player);
}
catch (IOException ex)
{
log.debug("unable to lookup pet list", ex);
if (player.equals(client.getLocalPlayer().getName()))
{
String response = "Open the 'All Pets' tab in the Collection Log to update your pet list";
log.debug("Setting response {}", response);
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setValue(response);
client.refreshChat();
}
return;
}
ChatMessageBuilder responseBuilder = new ChatMessageBuilder().append("Pets: ")
.append("(" + playerPetList.size() + ")");
// Append pets that the player owns
Pet[] pets = Pet.values();
for (Pet pet : pets)
{
if (playerPetList.contains(pet.getIconID()))
{
responseBuilder.append(" ").img(modIconIdx + pet.ordinal());
}
}
String response = responseBuilder.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setValue(response);
client.refreshChat();
}
/**
* Submits the pet list for the local player
*
* @param chatInput The chat message containing the command.
* @param value The chat message
*/
private boolean petListSubmit(ChatInput chatInput, String value)
{
final String playerName = client.getLocalPlayer().getName();
executor.execute(() ->
{
try
{
List<Integer> petList = getPetList().stream().map(Pet::getIconID).collect(Collectors.toList());
chatClient.submitPetList(playerName, petList);
}
catch (Exception ex)
{
log.warn("unable to submit pet list", ex);
}
finally
{
chatInput.resume();
}
});
return true;
}
/**
* Looks up the item price and changes the original message to the
* response.

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2021, Illya Myshakov <https://github.com/IllyaMyshakov>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.chatcommands;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
@AllArgsConstructor
@Getter
enum Pet
{
ABYSSAL_ORPHAN("Abyssal orphan", ItemID.ABYSSAL_ORPHAN),
IKKLE_HYDRA("Ikkle hydra", ItemID.IKKLE_HYDRA),
CALLISTO_CUB("Callisto cub", ItemID.CALLISTO_CUB),
HELLPUPPY("Hellpuppy", ItemID.HELLPUPPY),
PET_CHAOS_ELEMENTAL("Pet chaos elemental", ItemID.PET_CHAOS_ELEMENTAL),
PET_ZILYANA("Pet zilyana", ItemID.PET_ZILYANA),
PET_DARK_CORE("Pet dark core", ItemID.PET_DARK_CORE),
PET_DAGANNOTH_PRIME("Pet dagannoth prime", ItemID.PET_DAGANNOTH_PRIME),
PET_DAGANNOTH_SUPREME("Pet dagannoth supreme", ItemID.PET_DAGANNOTH_SUPREME),
PET_DAGANNOTH_REX("Pet dagannoth rex", ItemID.PET_DAGANNOTH_REX),
TZREKJAD("Tzrek-jad", ItemID.TZREKJAD),
PET_GENERAL_GRAARDOR("Pet general graardor", ItemID.PET_GENERAL_GRAARDOR),
BABY_MOLE("Baby mole", ItemID.BABY_MOLE),
NOON("Noon", ItemID.NOON),
JALNIBREK("Jal-nib-rek", ItemID.JALNIBREK),
KALPHITE_PRINCESS("Kalphite princess", ItemID.KALPHITE_PRINCESS),
PRINCE_BLACK_DRAGON("Prince black dragon", ItemID.PRINCE_BLACK_DRAGON),
PET_KRAKEN("Pet kraken", ItemID.PET_KRAKEN),
PET_KREEARRA("Pet kree'arra", ItemID.PET_KREEARRA),
PET_KRIL_TSUTSAROTH("Pet k'ril tsutsaroth", ItemID.PET_KRIL_TSUTSAROTH),
SCORPIAS_OFFSPRING("Scorpia's offspring", ItemID.SCORPIAS_OFFSPRING),
SKOTOS("Skotos", ItemID.SKOTOS),
PET_SMOKE_DEVIL("Pet smoke devil", ItemID.PET_SMOKE_DEVIL),
VENENATIS_SPIDERLING("Venenatis spiderling", ItemID.VENENATIS_SPIDERLING),
VETION_JR("Vet'ion jr.", ItemID.VETION_JR),
VORKI("Vorki", ItemID.VORKI),
PHOENIX("Phoenix", ItemID.PHOENIX),
PET_SNAKELING("Pet snakeling", ItemID.PET_SNAKELING),
OLMLET("Olmlet", ItemID.OLMLET),
LIL_ZIK("Lil' zik", ItemID.LIL_ZIK),
BLOODHOUND("Bloodhound", ItemID.BLOODHOUND),
PET_PENANCE_QUEEN("Pet penance queen", ItemID.PET_PENANCE_QUEEN),
HERON("Heron", ItemID.HERON),
ROCK_GOLEM("Rock golem", ItemID.ROCK_GOLEM),
BEAVER("Beaver", ItemID.BEAVER),
BABY_CHINCHOMPA("Baby chinchompa", ItemID.BABY_CHINCHOMPA),
GIANT_SQUIRREL("Giant squirrel", ItemID.GIANT_SQUIRREL),
TANGLEROOT("Tangleroot", ItemID.TANGLEROOT),
ROCKY("Rocky", ItemID.ROCKY),
RIFT_GUARDIAN("Rift guardian", ItemID.RIFT_GUARDIAN),
HERBI("Herbi", ItemID.HERBI),
CHOMPY_CHICK("Chompy chick", ItemID.CHOMPY_CHICK),
SRARACHA("Sraracha", ItemID.SRARACHA),
SMOLCANO("Smolcano", ItemID.SMOLCANO),
YOUNGLLEF("Youngllef", ItemID.YOUNGLLEF),
LITTLE_NIGHTMARE("Little nightmare", ItemID.LITTLE_NIGHTMARE),
LIL_CREATOR("Lil' creator", ItemID.LIL_CREATOR),
TINY_TEMPOR("Tiny tempor", ItemID.TINY_TEMPOR);
private final String name;
private final Integer iconID;
static Pet findPet(String petName)
{
for (Pet pet : values())
{
if (pet.name.equals(petName))
{
return pet;
}
}
return null;
}
}

View File

@@ -207,8 +207,8 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLEAN_OR_BANDOSIAN_GUARD))
.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", BANDOSIAN_GUARD))
.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_GUARD))
.put(new WorldPoint(1451, 3509, 0), new CoordinateClueInfo("Ruins of Morra.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
// Master
.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))

View File

@@ -327,7 +327,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
new CrypticClue("Elvish onions.", new WorldPoint(3303, 6092, 0), "Dig in the onion patch east of the Prifddinas allotments."),
new CrypticClue("Dig by the Giant's Den entrance, looking out over Lake Molch.", new WorldPoint(1418, 3591, 0), "South-east of Lake Molch in Zeah, outside the cave entrance."),
new CrypticClue("Search the crates in the fruit store just east of the Hosidius town centre.", CRATES_27533, new WorldPoint(1798, 3612, 0), "Search the crates in the back room of the Hosidius fruit store."),
new CrypticClue("A graceful man of many colours, his crates must be full of many delights.", "Hill Giant", CRATE_42067, new WorldPoint(1506, 3591, 2), "Kill any Hill Giant for a medium key. Then search the crate on the top floor of Osten's clothing shop in Shayzien."),
new CrypticClue("A graceful man of many colours, his crates must be full of many delights.", "Hill Giant", CRATE_42067, new WorldPoint(1506, 3590, 2), "Kill any Hill Giant for a medium key. Then search the crate on the top floor of Osten's clothing shop in Shayzien."),
new CrypticClue("Search the basket of apples in an orchard, south of the unknown grave surrounded by white roses.", APPLE_BASKET, new WorldPoint(1718, 3626, 0), "Search the middle apple basket in the apple orchard north of Hosidius."),
new CrypticClue("Dig in the lair of red wings, within the temple of the Sun and Moon.", new WorldPoint(1820, 9935, 0), "Forthos Dungeon. In the center of the red dragons.")
);

View File

@@ -41,8 +41,12 @@ public enum Enemy
ZAMORAK_WIZARD("Zamorak Wizard"),
//appears for hard clue coordinate steps not in the wilderness
SARADOMIN_WIZARD("Saradomin Wizard"),
//appears for elite clue coordinate steps all areas
//appears for elite clue coordinate steps in most areas
ARMADYLEAN_OR_BANDOSIAN_GUARD("Armadylean OR Bandosian Guard"),
//appears for elite clue coordinate steps on the west side of the Isle of Souls
ARMADYLEAN_GUARD("Armadylean Guard"),
//appears for elite clue coordinate steps on the east side of the Isle of Souls
BANDOSIAN_GUARD("Bandosian Guard"),
//appears for master clue coordinate and hot cold clues when single-way combat
BRASSICAN_MAGE("Brassican Mage"),
//appears for master clue coordinate and hot cold clues when multi-way combat

View File

@@ -29,7 +29,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Builder;
import lombok.Data;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
@Data
@@ -66,11 +65,4 @@ class GroundItem
{
return lootType != LootType.UNKNOWN;
}
@Value
static class GroundItemKey
{
private int itemId;
private WorldPoint location;
}
}

View File

@@ -403,4 +403,26 @@ public interface GroundItemsConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "showLootbeamForHighlighted",
name = "Highlighted item lootbeams",
description = "Configures lootbeams to show for all highlighted items.",
position = 30
)
default boolean showLootbeamForHighlighted()
{
return false;
}
@ConfigItem(
keyName = "showLootbeamTier",
name = "Lootbeam tier",
description = "Configures which price tiers will trigger a lootbeam",
position = 31
)
default HighlightTier showLootbeamTier()
{
return HighlightTier.HIGH;
}
}

View File

@@ -49,6 +49,7 @@ import net.runelite.api.coords.WorldPoint;
import static net.runelite.client.plugins.grounditems.GroundItemsPlugin.MAX_QUANTITY;
import net.runelite.client.plugins.grounditems.config.DespawnTimerMode;
import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU;
import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.NONE;
import net.runelite.client.plugins.grounditems.config.PriceDisplayMode;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -107,7 +108,8 @@ public class GroundItemsOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || plugin.isHideAll()) && !plugin.isHotKeyPressed();
final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || config.itemHighlightMode() == NONE
|| plugin.isHideAll()) && !plugin.isHotKeyPressed();
if (dontShowOverlay && !config.highlightTiles())
{

View File

@@ -28,7 +28,9 @@ package net.runelite.client.plugins.grounditems;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.EvictingQueue;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Table;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.Rectangle;
@@ -38,7 +40,7 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
@@ -71,6 +73,7 @@ import net.runelite.api.events.ItemSpawned;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
@@ -83,7 +86,7 @@ import net.runelite.client.input.MouseManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.grounditems.config.HighlightTier;
import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.OVERLAY;
import net.runelite.client.plugins.grounditems.config.ItemHighlightMode;
import net.runelite.client.plugins.grounditems.config.MenuHighlightMode;
import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.BOTH;
import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.NAME;
@@ -158,6 +161,9 @@ public class GroundItemsPlugin extends Plugin
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ItemManager itemManager;
@@ -177,12 +183,13 @@ public class GroundItemsPlugin extends Plugin
private ScheduledExecutorService executor;
@Getter
private final Map<GroundItem.GroundItemKey, GroundItem> collectedGroundItems = new LinkedHashMap<>();
private final Table<WorldPoint, Integer, GroundItem> collectedGroundItems = HashBasedTable.create();
private List<PriceHighlight> priceChecks = ImmutableList.of();
private LoadingCache<NamedQuantity, Boolean> highlightedItems;
private LoadingCache<NamedQuantity, Boolean> hiddenItems;
private final Queue<Integer> droppedItemQueue = EvictingQueue.create(16); // recently dropped items
private int lastUsedItem;
private final Map<WorldPoint, Lootbeam> lootbeams = new HashMap<>();
@Provides
GroundItemsConfig provideConfig(ConfigManager configManager)
@@ -213,6 +220,7 @@ public class GroundItemsPlugin extends Plugin
hiddenItemList = null;
highlightedItemsList = null;
collectedGroundItems.clear();
clientThread.invokeLater(this::removeAllLootbeams);
}
@Subscribe
@@ -230,6 +238,7 @@ public class GroundItemsPlugin extends Plugin
if (event.getGameState() == GameState.LOADING)
{
collectedGroundItems.clear();
lootbeams.clear();
}
}
@@ -240,19 +249,23 @@ public class GroundItemsPlugin extends Plugin
Tile tile = itemSpawned.getTile();
GroundItem groundItem = buildGroundItem(tile, item);
GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation());
GroundItem existing = collectedGroundItems.putIfAbsent(groundItemKey, groundItem);
GroundItem existing = collectedGroundItems.get(tile.getWorldLocation(), item.getId());
if (existing != null)
{
existing.setQuantity(existing.getQuantity() + groundItem.getQuantity());
// The spawn time remains set at the oldest spawn
}
else
{
collectedGroundItems.put(tile.getWorldLocation(), item.getId(), groundItem);
}
if (!config.onlyShowLoot())
{
notifyHighlightedItem(groundItem);
}
handleLootbeam(tile.getWorldLocation());
}
@Subscribe
@@ -261,8 +274,7 @@ public class GroundItemsPlugin extends Plugin
TileItem item = itemDespawned.getItem();
Tile tile = itemDespawned.getTile();
GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation());
GroundItem groundItem = collectedGroundItems.get(groundItemKey);
GroundItem groundItem = collectedGroundItems.get(tile.getWorldLocation(), item.getId());
if (groundItem == null)
{
return;
@@ -270,7 +282,7 @@ public class GroundItemsPlugin extends Plugin
if (groundItem.getQuantity() <= item.getQuantity())
{
collectedGroundItems.remove(groundItemKey);
collectedGroundItems.remove(tile.getWorldLocation(), item.getId());
}
else
{
@@ -280,6 +292,8 @@ public class GroundItemsPlugin extends Plugin
// time
groundItem.setSpawnTime(null);
}
handleLootbeam(tile.getWorldLocation());
}
@Subscribe
@@ -291,12 +305,13 @@ public class GroundItemsPlugin extends Plugin
int newQuantity = itemQuantityChanged.getNewQuantity();
int diff = newQuantity - oldQuantity;
GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation());
GroundItem groundItem = collectedGroundItems.get(groundItemKey);
GroundItem groundItem = collectedGroundItems.get(tile.getWorldLocation(), item.getId());
if (groundItem != null)
{
groundItem.setQuantity(groundItem.getQuantity() + diff);
}
handleLootbeam(tile.getWorldLocation());
}
@Subscribe
@@ -366,8 +381,7 @@ public class GroundItemsPlugin extends Plugin
for (ItemStack itemStack : items)
{
WorldPoint location = WorldPoint.fromLocal(client, itemStack.getLocation());
GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemStack.getId(), location);
GroundItem groundItem = collectedGroundItems.get(groundItemKey);
GroundItem groundItem = collectedGroundItems.get(location, itemStack.getId());
if (groundItem != null)
{
groundItem.setLootType(lootType);
@@ -460,12 +474,14 @@ public class GroundItemsPlugin extends Plugin
}
priceChecks = priceCheckBuilder.build();
clientThread.invokeLater(this::handleLootbeams);
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
if (config.itemHighlightMode() != OVERLAY)
if (config.itemHighlightMode() == ItemHighlightMode.MENU || config.itemHighlightMode() == ItemHighlightMode.BOTH)
{
final boolean telegrabEntry = event.getOption().equals("Cast") && event.getTarget().startsWith(TELEGRAB_TEXT) && event.getType() == CAST_ON_ITEM;
if (!(event.getOption().equals("Take") && event.getType() == THIRD_OPTION) && !telegrabEntry)
@@ -481,8 +497,7 @@ public class GroundItemsPlugin extends Plugin
MenuEntry lastEntry = menuEntries[menuEntries.length - 1];
final WorldPoint worldPoint = WorldPoint.fromScene(client, sceneX, sceneY, client.getPlane());
GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemId, worldPoint);
GroundItem groundItem = collectedGroundItems.get(groundItemKey);
GroundItem groundItem = collectedGroundItems.get(worldPoint, itemId);
int quantity = groundItem.getQuantity();
final int gePrice = groundItem.getGePrice();
@@ -705,4 +720,103 @@ public class GroundItemsPlugin extends Plugin
lastUsedItem = clickedItem.getId();
}
}
private void handleLootbeam(WorldPoint worldPoint)
{
/*
* Return and remove the lootbeam from this location if lootbeam are disabled
* Lootbeam can be at this location if the config was just changed
*/
if (!(config.showLootbeamForHighlighted() || config.showLootbeamTier() != HighlightTier.OFF))
{
removeLootbeam(worldPoint);
return;
}
int price = -1;
Collection<GroundItem> groundItems = collectedGroundItems.row(worldPoint).values();
for (GroundItem groundItem : groundItems)
{
if ((config.onlyShowLoot() && !groundItem.isMine()))
{
continue;
}
/*
* highlighted items have the highest priority so if an item is highlighted at this location
* we can early return
*/
NamedQuantity item = new NamedQuantity(groundItem);
if (config.showLootbeamForHighlighted()
&& TRUE.equals(highlightedItems.getUnchecked(item)))
{
addLootbeam(worldPoint, config.highlightedColor());
return;
}
// Explicit hide takes priority over implicit highlight
if (TRUE.equals(hiddenItems.getUnchecked(item)))
{
continue;
}
int itemPrice = getValueByMode(groundItem.getGePrice(), groundItem.getHaPrice());
price = Math.max(itemPrice, price);
}
if (config.showLootbeamTier() != HighlightTier.OFF)
{
for (PriceHighlight highlight : priceChecks)
{
if (price > highlight.getPrice() && price > config.showLootbeamTier().getValueFromTier(config))
{
addLootbeam(worldPoint, highlight.color);
return;
}
}
}
removeLootbeam(worldPoint);
}
private void handleLootbeams()
{
for (WorldPoint worldPoint : collectedGroundItems.rowKeySet())
{
handleLootbeam(worldPoint);
}
}
private void removeAllLootbeams()
{
for (Lootbeam lootbeam : lootbeams.values())
{
lootbeam.remove();
}
lootbeams.clear();
}
private void addLootbeam(WorldPoint worldPoint, Color color)
{
Lootbeam lootbeam = lootbeams.get(worldPoint);
if (lootbeam == null)
{
lootbeam = new Lootbeam(client, worldPoint, color);
lootbeams.put(worldPoint, lootbeam);
}
else
{
lootbeam.setColor(color);
}
}
private void removeLootbeam(WorldPoint worldPoint)
{
Lootbeam lootbeam = lootbeams.remove(worldPoint);
if (lootbeam != null)
{
lootbeam.remove();
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2021, Trevor <https://github.com/Trevor159>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.grounditems;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.JagexColor;
import net.runelite.api.RuneLiteObject;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import java.awt.Color;
class Lootbeam
{
private static final int RAID_LIGHT_MODEL = 5809;
private static final short RAID_LIGHT_FIND_COLOR = 6371;
private final RuneLiteObject runeLiteObject;
private final Client client;
private Color color;
public Lootbeam(Client client, WorldPoint worldPoint, Color color)
{
this.client = client;
runeLiteObject = client.createRuneLiteObject();
setColor(color);
runeLiteObject.setAnimation(client.loadAnimation(AnimationID.RAID_LIGHT_ANIMATION));
runeLiteObject.setShouldLoop(true);
LocalPoint lp = LocalPoint.fromWorld(client, worldPoint);
runeLiteObject.setLocation(lp, client.getPlane());
runeLiteObject.setActive(true);
}
public void setColor(Color color)
{
if (this.color != null && this.color.equals(color))
{
return;
}
this.color = color;
runeLiteObject.setModel(client.loadModel(
RAID_LIGHT_MODEL,
new short[]{RAID_LIGHT_FIND_COLOR},
new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)}
));
}
public void remove()
{
runeLiteObject.setActive(false);
}
}

View File

@@ -31,6 +31,7 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum ItemHighlightMode
{
NONE("None"),
OVERLAY("Overlay"),
MENU("Right-click menu"),
BOTH("Both");

View File

@@ -748,7 +748,7 @@ public class MusicPlugin extends Plugin
s.update();
s.getChannel().setWindowSlider(s);
}
if (ev.getScriptId() == ScriptID.TOPLEVEL_REDRAW && musicConfig.granularSliders())
{
// we have to set the var to our value so toplevel_redraw doesn't try to set
@@ -857,11 +857,12 @@ public class MusicPlugin extends Plugin
windowSlider.update();
}
}
public void updateVar()
{
int val = getValue();
client.getVarps()[this.var.getId()] = val * 100 / this.max;
int varVal = Math.round((float) val / (max / 100.f));
client.getVarps()[this.var.getId()] = varVal;
}
public void shutDown()

View File

@@ -27,11 +27,14 @@ package net.runelite.client.plugins.statusbars;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Units;
import net.runelite.client.plugins.statusbars.config.BarMode;
@ConfigGroup("statusbars")
@ConfigGroup(StatusBarsConfig.GROUP)
public interface StatusBarsConfig extends Config
{
String GROUP = "statusbars";
@ConfigItem(
keyName = "enableCounter",
name = "Show counters",
@@ -81,4 +84,15 @@ public interface StatusBarsConfig extends Config
{
return BarMode.PRAYER;
}
@ConfigItem(
keyName = "hideAfterCombatDelay",
name = "Hide after combat delay",
description = "Amount of ticks before hiding status bars after no longer in combat. 0 = always show status bars."
)
@Units(Units.TICKS)
default int hideAfterCombatDelay()
{
return 0;
}
}

View File

@@ -80,6 +80,7 @@ class StatusBarsOverlay extends Overlay
private static final int MAX_RUN_ENERGY_VALUE = 100;
private final Client client;
private final StatusBarsPlugin plugin;
private final StatusBarsConfig config;
private final ItemStatChangesService itemStatService;
private final SpriteManager spriteManager;
@@ -94,11 +95,12 @@ class StatusBarsOverlay extends Overlay
private final Map<BarMode, BarRenderer> barRenderers = new EnumMap<>(BarMode.class);
@Inject
private StatusBarsOverlay(Client client, StatusBarsConfig config, SkillIconManager skillIconManager, ItemStatChangesService itemstatservice, SpriteManager spriteManager)
private StatusBarsOverlay(Client client, StatusBarsPlugin plugin, StatusBarsConfig config, SkillIconManager skillIconManager, ItemStatChangesService itemstatservice, SpriteManager spriteManager)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
this.config = config;
this.itemStatService = itemstatservice;
this.spriteManager = spriteManager;
@@ -216,6 +218,11 @@ class StatusBarsOverlay extends Overlay
@Override
public Dimension render(Graphics2D g)
{
if (!plugin.isBarsDisplayed())
{
return null;
}
Viewport curViewport = null;
Widget curWidget = null;

View File

@@ -26,12 +26,24 @@ package net.runelite.client.plugins.statusbars;
import javax.inject.Inject;
import com.google.inject.Provides;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.Player;
import net.runelite.api.Varbits;
import net.runelite.api.events.GameTick;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDependency;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.itemstats.ItemStatPlugin;
import net.runelite.client.ui.overlay.OverlayManager;
import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "Status Bars",
@@ -47,9 +59,24 @@ public class StatusBarsPlugin extends Plugin
@Inject
private OverlayManager overlayManager;
@Inject
private Client client;
@Inject
private StatusBarsConfig config;
@Inject
private ClientThread clientThread;
@Getter(AccessLevel.PACKAGE)
private boolean barsDisplayed;
private int lastCombatActionTickCount;
@Override
protected void startUp() throws Exception
{
clientThread.invokeLater(this::checkStatusBars);
overlayManager.add(overlay);
}
@@ -57,6 +84,7 @@ public class StatusBarsPlugin extends Plugin
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
barsDisplayed = false;
}
@Provides
@@ -64,4 +92,45 @@ public class StatusBarsPlugin extends Plugin
{
return configManager.getConfig(StatusBarsConfig.class);
}
@Subscribe
public void onGameTick(GameTick gameTick)
{
checkStatusBars();
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (StatusBarsConfig.GROUP.equals(event.getGroup()) && event.getKey().equals("hideAfterCombatDelay"))
{
clientThread.invokeLater(this::checkStatusBars);
}
}
private void checkStatusBars()
{
final Player localPlayer = client.getLocalPlayer();
if (localPlayer == null)
{
return;
}
final Actor interacting = localPlayer.getInteracting();
if (config.hideAfterCombatDelay() == 0)
{
barsDisplayed = true;
}
else if ((interacting instanceof NPC && ArrayUtils.contains(((NPC) interacting).getComposition().getActions(), "Attack"))
|| (interacting instanceof Player && client.getVar(Varbits.PVP_SPEC_ORB) == 1))
{
lastCombatActionTickCount = client.getTickCount();
barsDisplayed = true;
}
else if (client.getTickCount() - lastCombatActionTickCount >= config.hideAfterCombatDelay())
{
barsDisplayed = false;
}
}
}

View File

@@ -31,10 +31,10 @@ import java.time.Instant;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.timetracking.clocks.ClockManager;
import net.runelite.client.plugins.timetracking.farming.CropState;
import net.runelite.client.plugins.timetracking.farming.FarmingContractManager;
import net.runelite.client.plugins.timetracking.farming.FarmingTracker;
import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker;
@@ -124,14 +124,13 @@ class OverviewTabPanel extends TabContentPanel
}
farmingOverviews.forEach((patchType, panel) ->
updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType), null));
updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType)));
updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime(), null);
updateItemPanel(farmingContractOverview, farmingContractManager.getSummary(), farmingContractManager.getCompletionTime(),
farmingContractManager.getContractName());
updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime());
updateContractPanel();
}
private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime, @Nullable String farmingContract)
private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime)
{
switch (summary)
{
@@ -151,10 +150,7 @@ class OverviewTabPanel extends TabContentPanel
break;
}
case EMPTY:
panel.updateStatus(farmingContract == null ? "Empty" : farmingContract, Color.GRAY);
break;
case OCCUPIED:
panel.updateStatus(farmingContract == null ? "" : farmingContract, Color.RED);
panel.updateStatus("Empty", Color.GRAY);
break;
case UNKNOWN:
default:
@@ -162,4 +158,45 @@ class OverviewTabPanel extends TabContentPanel
break;
}
}
private void updateContractPanel()
{
switch (farmingContractManager.getSummary())
{
case COMPLETED:
case IN_PROGRESS:
switch (farmingContractManager.getContractCropState())
{
case HARVESTABLE:
case GROWING:
long duration = farmingContractManager.getCompletionTime() - Instant.now().getEpochSecond();
if (duration <= 0)
{
farmingContractOverview.updateStatus("Ready", ColorScheme.PROGRESS_COMPLETE_COLOR);
return;
}
farmingContractOverview.updateStatus("Ready " + getFormattedEstimate(duration, config.timeFormatMode()), Color.GRAY);
return;
case DISEASED:
farmingContractOverview.updateStatus("Diseased", CropState.DISEASED.getColor());
return;
case DEAD:
farmingContractOverview.updateStatus("Dead", CropState.DEAD.getColor());
return;
}
// fallthrough
case UNKNOWN:
default:
farmingContractOverview.updateStatus("Unknown", Color.GRAY);
return;
case EMPTY:
farmingContractOverview.updateStatus(farmingContractManager.getContractName(), Color.GRAY);
return;
case OCCUPIED:
farmingContractOverview.updateStatus(farmingContractManager.getContractName(), Color.RED);
return;
}
}
}

View File

@@ -24,13 +24,16 @@
*/
package net.runelite.client.plugins.timetracking;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.util.Locale;
import javax.swing.JPanel;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public abstract class TabContentPanel extends JPanel
{
private static final DateTimeFormatter DATETIME_FORMATTER_24H = DateTimeFormatter.ofPattern("HH:mm");
@@ -72,17 +75,25 @@ public abstract class TabContentPanel extends JPanel
}
else
{
StringBuilder sb = new StringBuilder();
LocalDateTime endTime = LocalDateTime.now().plus(remainingSeconds, ChronoUnit.SECONDS);
LocalDateTime currentTime = LocalDateTime.now();
if (endTime.getDayOfWeek() != currentTime.getDayOfWeek())
try
{
sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault())).append(" ");
}
sb.append("at ");
sb.append(formatter.format(endTime));
StringBuilder sb = new StringBuilder();
LocalDateTime endTime = LocalDateTime.now().plus(remainingSeconds, ChronoUnit.SECONDS);
LocalDateTime currentTime = LocalDateTime.now();
if (endTime.getDayOfWeek() != currentTime.getDayOfWeek())
{
sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault())).append(" ");
}
sb.append("at ");
sb.append(formatter.format(endTime));
return sb.toString();
return sb.toString();
}
catch (DateTimeException e)
{
log.warn("error formatting absolute time: now + {}", remainingSeconds, e);
return "Invalid";
}
}
}

View File

@@ -90,7 +90,7 @@ public class CustomScrollBarUI extends BasicScrollBarUI
{
JScrollBar bar = (JScrollBar) c;
bar.setUnitIncrement(16);
bar.setPreferredSize(new Dimension(7, 0));
bar.setPreferredSize(new Dimension(7, 7));
return new CustomScrollBarUI();
}

View File

@@ -130,7 +130,7 @@ public class WorldMapOverlay extends Overlay
Area currentClip = null;
Point mousePos = client.getMouseCanvasPosition();
if (!canvasViewArea.contains(mousePos.getX(), mousePos.getY()))
if (!mapViewArea.contains(mousePos.getX(), mousePos.getY()))
{
mousePos = null;
}

View File

@@ -3765,7 +3765,13 @@
23072,
23082,
25753,
25820
25820,
25920,
25921,
25922,
25923,
25924,
25925
],
"herb tea mix": [
4464,
@@ -7528,7 +7534,16 @@
25185,
25187,
25189,
25191
25191,
25898,
25900,
25902,
25904,
25906,
25908,
25910,
25912,
25914
],
"slayer ring": [
11866,
@@ -8641,6 +8656,11 @@
21009,
21206
],
"dragon hunter crossbow": [
21012,
25916,
25918
],
"ancestral hat": [
21018,
25518
@@ -9884,5 +9904,21 @@
25892,
25894,
25896
],
"ghommals hilt": [
25926,
25928,
25930,
25932,
25934,
25936
],
"anim offhand": [
25938,
25941,
25944,
25947,
25950,
25953
]
}

View File

@@ -552,7 +552,7 @@
"rx2": 50,
"ry2": 29,
"z1": 0,
"z2": 0
"z2": 2
},
{
"rx1": 13,
@@ -724,6 +724,14 @@
}
],
"10288": [ // Yanille East
{
"rx1": 27,
"ry1": 12,
"rx2": 33,
"ry2": 19,
"z1": 1,
"z2": 1
},
{
"rx1": 47,
"ry1": 19,
@@ -2167,5 +2175,243 @@
"z1": 0,
"z2": 2
}
],
"11310": [ // Shilo Village
{
"rx1": 26,
"ry1": 52,
"rx2": 28,
"ry2": 54,
"z1": 0,
"z2": 0
},
{
"rx1": 26,
"ry1": 58,
"rx2": 28,
"ry2": 60,
"z1": 0,
"z2": 0
},
{
"rx1": 27,
"ry1": 55,
"rx2": 27,
"ry2": 57,
"z1": 0,
"z2": 0
},
{
"rx1": 33,
"ry1": 52,
"rx2": 35,
"ry2": 54,
"z1": 0,
"z2": 0
},
{
"rx1": 29,
"ry1": 53,
"rx2": 32,
"ry2": 53,
"z1": 0,
"z2": 0
},
{
"rx1": 44,
"ry1": 49,
"rx2": 46,
"ry2": 57,
"z1": 0,
"z2": 0
},
{
"rx1": 43,
"ry1": 50,
"rx2": 47,
"ry2": 56,
"z1": 0,
"z2": 0
},
{
"rx1": 42,
"ry1": 51,
"rx2": 48,
"ry2": 55,
"z1": 0,
"z2": 0
},
{
"rx1": 41,
"ry1": 52,
"rx2": 49,
"ry2": 54,
"z1": 0,
"z2": 0
},
{
"rx1": 36,
"ry1": 53,
"rx2": 40,
"ry2": 53,
"z1": 0,
"z2": 0
},
{
"rx1": 43,
"ry1": 44,
"rx2": 47,
"ry2": 46,
"z1": 0,
"z2": 0
},
{
"rx1": 45,
"ry1": 43,
"rx2": 45,
"ry2": 48,
"z1": 0,
"z2": 0
},
{
"rx1": 53,
"ry1": 51,
"rx2": 55,
"ry2": 55,
"z1": 0,
"z2": 0
},
{
"rx1": 50,
"ry1": 53,
"rx2": 56,
"ry2": 53,
"z1": 0,
"z2": 0
},
{
"rx1": 52,
"ry1": 37,
"rx2": 54,
"ry2": 39,
"z1": 0,
"z2": 0
},
{
"rx1": 8,
"ry1": 18,
"rx2": 9,
"ry2": 19,
"z1": 0,
"z2": 0
},
{
"rx1": 53,
"ry1": 29,
"rx2": 53,
"ry2": 36,
"z1": 0,
"z2": 0
}
],
"12340": [ // Draynor Manor
{
"rx1": 30,
"ry1": 24,
"rx2": 43,
"ry2": 24,
"z1": 0,
"z2": 0
}
],
"9265": [ // Lletya
{
"rx1": 23,
"ry1": 34,
"rx2": 23,
"ry2": 37,
"z1": 0,
"z2": 0
}
],
"15148": [ // Harmony Island
{
"rx1": 30,
"ry1": 24,
"rx2": 40,
"ry2": 32,
"z1": 0,
"z2": 0
},
{
"rx1": 41,
"ry1": 18,
"rx2": 48,
"ry2": 36,
"z1": 0,
"z2": 0
},
{
"rx1": 41,
"ry1": 37,
"rx2": 45,
"ry2": 38,
"z1": 0,
"z2": 0
},
{
"rx1": 34,
"ry1": 57,
"rx2": 38,
"ry2": 57,
"z1": 0,
"z2": 0
}
],
"11423": [ // NW Keldagrim
{
"rx1": 60,
"ry1": 11,
"rx2": 63,
"ry2": 36,
"z1": 0,
"z2": 1
}
],
"11678": [ // SE Keldagrim
{
"rx1": 49,
"ry1": 46,
"rx2": 49,
"ry2": 51,
"z1": 0,
"z2": 0
},
{
"rx1": 50,
"ry1": 56,
"rx2": 51,
"ry2": 63,
"z1": 0,
"z2": 0
}
],
"11679": [ // NE Keldagrim
{
"rx1": 50,
"ry1": 0,
"rx2": 51,
"ry2": 1,
"z1": 0,
"z2": 0
},
{
"rx1": 0,
"ry1": 11,
"rx2": 3,
"ry2": 36,
"z1": 0,
"z2": 1
}
]
}

View File

@@ -1 +1 @@
2FE66C1A3B63EEF10142A955C927054613F59A34C4A929C8AC79DBE0F1B06C30
9D5F23C8B25B79FF2B23F6AE449EDF74645E808B67ECF0E389B626966E86B1BD

View File

@@ -273,7 +273,7 @@ LABEL226:
iload 6 ; prefix length
iload 5 ; chat type
sconst "preChatSendpublic"
runelite_callback
runelite_callback
istore 5 ; chat type
istore 6 ; prefix length
get_varc_string 335 ; load input string
@@ -565,7 +565,7 @@ LABEL441:
if_icmpeq LABEL445
jump LABEL490
LABEL445:
iconst 40697935
iconst 40697936
iconst 1
cc_find
iconst 1

View File

@@ -111,6 +111,8 @@ public class GroundItemsPluginTest
when(client.getLocalPlayer()).thenReturn(mock(Player.class));
when(config.getHiddenItems()).thenReturn("");
when(config.showLootbeamForHighlighted()).thenReturn(false);
when(config.showLootbeamTier()).thenReturn(HighlightTier.OFF);
}
@Test