Merge pull request #698 from SomeoneWithAnInternetConnection/ge-squashed
GE Offer tracking plugin
This commit is contained in:
@@ -138,6 +138,8 @@ public interface Client extends GameEngine
|
||||
|
||||
HashTable getComponentTable();
|
||||
|
||||
GrandExchangeOffer[] getGrandExchangeOffers();
|
||||
|
||||
boolean isPrayerActive(Prayer prayer);
|
||||
|
||||
int getSkillExperience(Skill skill);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* 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.api;
|
||||
|
||||
public interface GrandExchangeOffer
|
||||
{
|
||||
int getQuantitySold();
|
||||
|
||||
int getItemId();
|
||||
|
||||
int getTotalQuantity();
|
||||
|
||||
int getPrice();
|
||||
|
||||
int getSpent();
|
||||
|
||||
GrandExchangeOfferState getState();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* 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.api;
|
||||
|
||||
/**
|
||||
* Describes the state of a Grand Exchange offer
|
||||
*/
|
||||
public enum GrandExchangeOfferState
|
||||
{
|
||||
/**
|
||||
* An empty slot.
|
||||
*/
|
||||
EMPTY,
|
||||
/**
|
||||
* Any offer that's been cancelled
|
||||
*/
|
||||
CANCELLED,
|
||||
/**
|
||||
* A buy offer that is currently in progress.
|
||||
*/
|
||||
BUYING,
|
||||
/**
|
||||
* A buy offer that has completed.
|
||||
*/
|
||||
BOUGHT,
|
||||
/**
|
||||
* A sell offer that is currently in progress.
|
||||
*/
|
||||
SELLING,
|
||||
/**
|
||||
* A sell offer that has completed.
|
||||
*/
|
||||
SOLD;
|
||||
}
|
||||
@@ -74,4 +74,11 @@ public interface ItemComposition
|
||||
* @return true if members-only, false otherwise.
|
||||
*/
|
||||
boolean isMembers();
|
||||
|
||||
/**
|
||||
* Returns whether or not the item stacks in the players' inventories
|
||||
*
|
||||
* @return true if stackable, false otherwise
|
||||
*/
|
||||
boolean isStackable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* 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.api.events;
|
||||
|
||||
import lombok.Data;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
|
||||
@Data
|
||||
public class GrandExchangeOfferChanged
|
||||
{
|
||||
private GrandExchangeOffer offer;
|
||||
private int slot;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.grandexchange;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.Color;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import static net.runelite.api.GrandExchangeOfferState.EMPTY;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
|
||||
@Slf4j
|
||||
public class GrandExchangeOfferSlot extends JPanel
|
||||
{
|
||||
private static final Color GE_INPROGRESS_ORANGE = new Color(0xd8, 0x80, 0x20).brighter();
|
||||
private static final Color GE_FINISHED_GREEN = new Color(0, 0x5f, 0);
|
||||
private static final Color GE_CANCELLED_RED = new Color(0x8f, 0, 0);
|
||||
|
||||
private static final String INFO_CARD = "INFO_CARD";
|
||||
private static final String EMPTY_CARD = "EMPTY_CARD";
|
||||
|
||||
private final ItemManager itemManager;
|
||||
|
||||
private final CardLayout cardLayout = new CardLayout();
|
||||
private final JLabel itemIcon = new JLabel();
|
||||
private final TitledBorder itemName = BorderFactory.createTitledBorder("Nothing");
|
||||
private final JLabel offerState = new JLabel("Text so the label has height");
|
||||
private final JProgressBar progressBar = new JProgressBar();
|
||||
|
||||
/**
|
||||
* This (sub)panel is used for each GE slot displayed
|
||||
* in the sidebar
|
||||
*/
|
||||
GrandExchangeOfferSlot(ItemManager itemManager)
|
||||
{
|
||||
this.itemManager = itemManager;
|
||||
buildPanel();
|
||||
}
|
||||
|
||||
private void buildPanel()
|
||||
{
|
||||
setBorder(BorderFactory.createCompoundBorder(
|
||||
// Add a margin underneath each slot panel to space them out
|
||||
BorderFactory.createEmptyBorder(0, 0, 3, 0),
|
||||
itemName
|
||||
));
|
||||
|
||||
// The default border color is kind of dark, so we change it to something lighter
|
||||
itemName.setBorder(BorderFactory.createLineBorder(getBackground().brighter()));
|
||||
|
||||
progressBar.setStringPainted(true);
|
||||
|
||||
setLayout(cardLayout);
|
||||
|
||||
// Card for when the slot has an offer in it
|
||||
JPanel infoCard = new JPanel();
|
||||
add(infoCard, INFO_CARD);
|
||||
// Add padding to give the icon and progress bar room to breathe
|
||||
infoCard.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 2));
|
||||
|
||||
infoCard.setLayout(new BoxLayout(infoCard, BoxLayout.X_AXIS));
|
||||
// Icon on the left
|
||||
infoCard.add(itemIcon);
|
||||
|
||||
// Info on the right
|
||||
JPanel offerStatePanel = new JPanel();
|
||||
offerStatePanel.setLayout(new BoxLayout(offerStatePanel, BoxLayout.Y_AXIS));
|
||||
offerStatePanel.add(offerState);
|
||||
offerStatePanel.add(progressBar);
|
||||
infoCard.add(offerStatePanel);
|
||||
|
||||
// Card for when the slot is empty
|
||||
JPanel emptySlotCard = new JPanel();
|
||||
add(emptySlotCard, EMPTY_CARD);
|
||||
// Counteract the height lost to the text at the top of the TitledBorder
|
||||
int itemNameBorderHeight = itemName.getBorderInsets(this).top;
|
||||
emptySlotCard.setBorder(BorderFactory.createEmptyBorder(0, 0, (itemNameBorderHeight - 1) / 2, 0));
|
||||
// Center the "Empty" label horizontally
|
||||
emptySlotCard.setLayout( new BoxLayout(emptySlotCard, BoxLayout.X_AXIS));
|
||||
emptySlotCard.add(Box.createHorizontalGlue());
|
||||
emptySlotCard.add(new JLabel(getNameForState(EMPTY)), BorderLayout.CENTER);
|
||||
emptySlotCard.add(Box.createHorizontalGlue());
|
||||
|
||||
cardLayout.show(this, EMPTY_CARD);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void updateOffer(@Nullable GrandExchangeOffer newOffer)
|
||||
{
|
||||
if (newOffer == null || newOffer.getState() == EMPTY)
|
||||
{
|
||||
cardLayout.show(this, EMPTY_CARD);
|
||||
itemName.setTitle("Nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
cardLayout.show(this, INFO_CARD);
|
||||
|
||||
ItemComposition offerItem = itemManager.getItemComposition(newOffer.getItemId());
|
||||
|
||||
itemName.setTitle(offerItem.getName());
|
||||
|
||||
boolean shouldStack = offerItem.isStackable() || newOffer.getTotalQuantity() > 1;
|
||||
ImageIcon newItemIcon = new ImageIcon(itemManager.getImage(newOffer.getItemId(), newOffer.getTotalQuantity(), shouldStack));
|
||||
itemIcon.setIcon(newItemIcon);
|
||||
|
||||
offerState.setText(getNameForState(newOffer.getState()) + " at " + newOffer.getPrice() + (newOffer.getTotalQuantity() > 1 ? "gp ea" : "gp"));
|
||||
|
||||
progressBar.setMaximum(newOffer.getTotalQuantity());
|
||||
progressBar.setValue(newOffer.getQuantitySold());
|
||||
progressBar.setBackground(getColorForState(newOffer.getState()));
|
||||
progressBar.setString(newOffer.getQuantitySold() + "/" + newOffer.getTotalQuantity());
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
private String getNameForState(GrandExchangeOfferState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CANCELLED:
|
||||
return "Cancelled";
|
||||
case BUYING:
|
||||
return "Buying";
|
||||
case BOUGHT:
|
||||
return "Bought";
|
||||
case SELLING:
|
||||
return "Selling";
|
||||
case SOLD:
|
||||
return "Sold";
|
||||
case EMPTY:
|
||||
default:
|
||||
return "Empty";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Color getColorForState(GrandExchangeOfferState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CANCELLED:
|
||||
return GE_CANCELLED_RED;
|
||||
case BUYING:
|
||||
case SELLING:
|
||||
return GE_INPROGRESS_ORANGE;
|
||||
case BOUGHT:
|
||||
case SOLD:
|
||||
return GE_FINISHED_GREEN;
|
||||
case EMPTY:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.grandexchange;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.BoxLayout;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
@Slf4j
|
||||
class GrandExchangePanel extends PluginPanel
|
||||
{
|
||||
private static final int MAX_OFFERS = 8;
|
||||
|
||||
private GrandExchangeOfferSlot[] offerSlotPanels = new GrandExchangeOfferSlot[MAX_OFFERS];
|
||||
|
||||
@Inject
|
||||
GrandExchangePanel(ItemManager itemManager)
|
||||
{
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
|
||||
for (int i = 0; i < offerSlotPanels.length; ++i)
|
||||
{
|
||||
offerSlotPanels[i] = new GrandExchangeOfferSlot(itemManager);
|
||||
add(offerSlotPanels[i]);
|
||||
}
|
||||
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void updateOffer(GrandExchangeOffer newOffer, int slot)
|
||||
{
|
||||
offerSlotPanels[slot].updateOffer(newOffer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.grandexchange;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.SwingUtilities;
|
||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Grand Exchange offers"
|
||||
)
|
||||
public class GrandExchangePlugin extends Plugin
|
||||
{
|
||||
private NavigationButton button;
|
||||
|
||||
private GrandExchangePanel panel;
|
||||
|
||||
@Inject
|
||||
private ClientUI ui;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws IOException
|
||||
{
|
||||
panel = injector.getInstance(GrandExchangePanel.class);
|
||||
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("ge_icon.png"));
|
||||
button = new NavigationButton("GE Offers", icon, () -> panel);
|
||||
ui.getPluginToolbar().addNavigation(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown()
|
||||
{
|
||||
ui.getPluginToolbar().removeNavigation(button);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
|
||||
{
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
panel.updateOffer(offerEvent.getOffer(), offerEvent.getSlot());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.grandexchange;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GrandExchangeOfferSlotTest
|
||||
{
|
||||
@Mock
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Mock
|
||||
private GrandExchangeOffer offer;
|
||||
|
||||
@Test
|
||||
public void testUpdateOffer()
|
||||
{
|
||||
when(itemManager.getItemComposition(anyInt())).thenReturn(mock(ItemComposition.class));
|
||||
when(itemManager.getImage(anyInt(), anyInt(), anyBoolean())).thenReturn(mock(BufferedImage.class));
|
||||
when(offer.getState()).thenReturn(GrandExchangeOfferState.CANCELLED);
|
||||
|
||||
GrandExchangeOfferSlot offerSlot = new GrandExchangeOfferSlot(itemManager);
|
||||
offerSlot.updateOffer(offer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.ClanMember;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.IndexedSprite;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.MenuAction;
|
||||
@@ -44,6 +45,7 @@ import net.runelite.api.Skill;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.events.ExperienceChanged;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||
import net.runelite.api.events.MapRegionChanged;
|
||||
import net.runelite.api.events.PlayerMenuOptionsChanged;
|
||||
import net.runelite.api.events.ResizeableChanged;
|
||||
@@ -483,6 +485,28 @@ public abstract class RSClientMixin implements RSClient
|
||||
eventBus.post(gameStateChange);
|
||||
}
|
||||
|
||||
@Inject
|
||||
@FieldHook("grandExchangeOffers")
|
||||
public static void onGrandExchangeOffersChanged(int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GrandExchangeOffer internalOffer = client.getGrandExchangeOffers()[idx];
|
||||
|
||||
if (internalOffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GrandExchangeOfferChanged offerChangedEvent = new GrandExchangeOfferChanged();
|
||||
offerChangedEvent.setOffer(internalOffer);
|
||||
offerChangedEvent.setSlot(idx);
|
||||
eventBus.post(offerChangedEvent);
|
||||
}
|
||||
|
||||
@FieldHook("settings")
|
||||
@Inject
|
||||
public static void settingsChanged(int idx)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.mixins;
|
||||
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import static net.runelite.api.GrandExchangeOfferState.BOUGHT;
|
||||
import static net.runelite.api.GrandExchangeOfferState.BUYING;
|
||||
import static net.runelite.api.GrandExchangeOfferState.CANCELLED;
|
||||
import static net.runelite.api.GrandExchangeOfferState.EMPTY;
|
||||
import static net.runelite.api.GrandExchangeOfferState.SELLING;
|
||||
import static net.runelite.api.GrandExchangeOfferState.SOLD;
|
||||
import net.runelite.api.mixins.Inject;
|
||||
import net.runelite.api.mixins.Mixin;
|
||||
import net.runelite.rs.api.RSGrandExchangeOffer;
|
||||
|
||||
@Mixin(RSGrandExchangeOffer.class)
|
||||
public abstract class RSGrandExchangeOfferMixin implements RSGrandExchangeOffer
|
||||
{
|
||||
|
||||
/*
|
||||
Internally a GrandExchangeOffer's state is represented as 4 flags
|
||||
packed into the lower half of a byte. They are:
|
||||
*/
|
||||
|
||||
//Set for sell offers, unset for buy offers
|
||||
private static final int IS_SELLING = 1 << 3; // 0b1000
|
||||
|
||||
|
||||
/*
|
||||
Set for offers that have finished, either because they've
|
||||
been filled, or because they were cancelled
|
||||
*/
|
||||
private static final int COMPLETED = 1 << 2; // 0b0100
|
||||
|
||||
/*
|
||||
Set for offers that are actually live
|
||||
NB: Insta-buy/sell offers will be simultaneously LIVE and LOCAL
|
||||
*/
|
||||
private static final int LIVE = 1 << 1; // 0b0010
|
||||
|
||||
//True for just-made, just-cancelled, completely cancelled, and completed offers
|
||||
private static final int LOCAL = 1;
|
||||
|
||||
@Inject
|
||||
@Override
|
||||
public GrandExchangeOfferState getState()
|
||||
{
|
||||
byte code = getRSState();
|
||||
boolean isSelling = (code & IS_SELLING) == IS_SELLING;
|
||||
boolean isFinished = (code & COMPLETED) == COMPLETED;
|
||||
|
||||
|
||||
if (code == 0)
|
||||
{
|
||||
return EMPTY;
|
||||
}
|
||||
else if (isFinished && getQuantitySold() < getTotalQuantity())
|
||||
{
|
||||
return CANCELLED;
|
||||
}
|
||||
else if (isSelling)
|
||||
{
|
||||
if (isFinished)
|
||||
{
|
||||
return SOLD;
|
||||
}
|
||||
else // if isUnfinished
|
||||
{
|
||||
return SELLING;
|
||||
}
|
||||
}
|
||||
else // if isBuying
|
||||
{
|
||||
if (isFinished)
|
||||
{
|
||||
return BOUGHT;
|
||||
}
|
||||
else // if isUnfinished
|
||||
{
|
||||
return BUYING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* 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.mixins;
|
||||
|
||||
import net.runelite.api.mixins.Inject;
|
||||
import net.runelite.api.mixins.Mixin;
|
||||
import net.runelite.rs.api.RSItemComposition;
|
||||
|
||||
@Mixin(RSItemComposition.class)
|
||||
public abstract class RSItemCompositionMixin implements RSItemComposition
|
||||
{
|
||||
@Inject
|
||||
@Override
|
||||
public boolean isStackable()
|
||||
{
|
||||
return getIsStackable() != 0;
|
||||
}
|
||||
}
|
||||
@@ -24,25 +24,33 @@
|
||||
*/
|
||||
package net.runelite.rs.api;
|
||||
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.mapping.Import;
|
||||
|
||||
public interface RSGrandExchangeOffer
|
||||
public interface RSGrandExchangeOffer extends GrandExchangeOffer
|
||||
{
|
||||
@Import("quantitySold")
|
||||
@Override
|
||||
int getQuantitySold();
|
||||
|
||||
@Import("itemId")
|
||||
@Override
|
||||
int getItemId();
|
||||
|
||||
@Import("totalQuantity")
|
||||
@Override
|
||||
int getTotalQuantity();
|
||||
|
||||
@Import("price")
|
||||
@Override
|
||||
int getPrice();
|
||||
|
||||
@Import("spent")
|
||||
@Override
|
||||
int getSpent();
|
||||
|
||||
@Import("progress")
|
||||
byte getProgress();
|
||||
@Import("state")
|
||||
byte getRSState();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,15 @@ public interface RSItemComposition extends ItemComposition
|
||||
@Override
|
||||
boolean isMembers();
|
||||
|
||||
/**
|
||||
* You probably want {@link #isStackable}
|
||||
* <p>
|
||||
* This is the <b>{@code int}</b> that client code uses internally to represent this true/false value. It appears to only ever be set to 1 or 0
|
||||
* @return 0 when this type of item isn't stackable, 1 otherwise
|
||||
*/
|
||||
@Import("isStackable")
|
||||
int getIsStackable();
|
||||
|
||||
@Import("maleModel")
|
||||
int getMaleModel();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user