commit 4e465be59a4a6174c7c00f05d8e8363e7bd410f0 Author: Bronson Graansma Date: Fri Jul 28 14:06:43 2017 -0400 First commit diff --git a/assets/client/favicon.png b/assets/client/favicon.png new file mode 100644 index 0000000..8aa2d98 Binary files /dev/null and b/assets/client/favicon.png differ diff --git a/assets/client/text-font.ttf b/assets/client/text-font.ttf new file mode 100755 index 0000000..c13e6d2 Binary files /dev/null and b/assets/client/text-font.ttf differ diff --git a/assets/item/abyssal_whip.png b/assets/item/abyssal_whip.png new file mode 100644 index 0000000..a595601 Binary files /dev/null and b/assets/item/abyssal_whip.png differ diff --git a/assets/mob/abyssal_demon.png b/assets/mob/abyssal_demon.png new file mode 100644 index 0000000..78d62c1 Binary files /dev/null and b/assets/mob/abyssal_demon.png differ diff --git a/assets/mob/abyssal_sire.png b/assets/mob/abyssal_sire.png new file mode 100644 index 0000000..015544e Binary files /dev/null and b/assets/mob/abyssal_sire.png differ diff --git a/assets/mob/commander_zilyana.png b/assets/mob/commander_zilyana.png new file mode 100644 index 0000000..5f2dc77 Binary files /dev/null and b/assets/mob/commander_zilyana.png differ diff --git a/assets/mob/general_graardor.png b/assets/mob/general_graardor.png new file mode 100644 index 0000000..ee8749b Binary files /dev/null and b/assets/mob/general_graardor.png differ diff --git a/assets/mob/k'ril_tsutsaroth.png b/assets/mob/k'ril_tsutsaroth.png new file mode 100644 index 0000000..95d75c9 Binary files /dev/null and b/assets/mob/k'ril_tsutsaroth.png differ diff --git a/assets/mob/kree'arra.png b/assets/mob/kree'arra.png new file mode 100644 index 0000000..6ab63a9 Binary files /dev/null and b/assets/mob/kree'arra.png differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..878c9dd --- /dev/null +++ b/makefile @@ -0,0 +1,13 @@ +build: + javac -d . src/*.java + jar cfe OSRS_Loot_Simulator.jar Main *.class assets/ + rm -f *.class + +app: OSRS_Loot_Simulator.jar + javapackager -deploy -native -outdir application -outfile OSRS_Loot_Simulator -srcfiles OSRS_Loot_Simulator.jar -appclass Main -name "OSRS Loot Simulator" -title "OSRS Loot Simulator" -Bicon="assets/client/favicon.png" + +exec: + java -jar OSRS_Loot_Simulator.jar + +clean: + rm -rf OSRS_Loot_Simulator.jar application/* diff --git a/src/GUI.java b/src/GUI.java new file mode 100644 index 0000000..0da1d46 --- /dev/null +++ b/src/GUI.java @@ -0,0 +1,371 @@ +import java.util.List; +import java.util.Random; +import java.util.HashMap; +import java.util.ArrayList; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JButton; +import javax.swing.JToggleButton; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.SpringLayout; +import javax.swing.UIManager; +import javax.swing.JToolTip; +import javax.swing.BorderFactory; +import javax.swing.JProgressBar; +import javax.swing.SwingUtilities; +import javax.swing.JCheckBox; +import javax.imageio.ImageIO; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.ActionEvent; +import java.awt.event.WindowEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.GridLayout; +import java.awt.FlowLayout; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Font; +import java.awt.image.BufferedImage; +import java.awt.Image; +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; +import java.text.NumberFormat; +import java.math.BigInteger; + +class GUI extends JFrame { + private JLabel loading; + private boolean ringWealth; + private List lastList; + private String fontFace; + + private Color primary; + private Color secondary; + private Color tertiary; + + private long kills; + private Mob selection; + + private int screenWidth; + private int screenHeight; + + private JPanel content; + private JPanel options; + private JTextField killsEntry; + private JCheckBox row; + private JButton start; + private JScrollPane loot; + private JPanel lootPane; + private List items; + private JPanel summary; + private JLabel totalVal; + private JPanel sideBar; + private JTextField search; + private JScrollPane bosses; + private List bossButtons; + private List mobs; + private HashMap bossIcons; + + GUI(List mobs, List items, Image img, JProgressBar progress, Font font) { + super("OSRS Loot Simulator"); + setIconImage(img); + this.mobs = mobs; + this.items = items; + this.kills = 1L; + this.ringWealth = false; + this.fontFace = font.getName(); + + primary = new Color(153, 124, 88); + secondary = new Color(249, 241, 220); + tertiary = new Color(113, 92, 65); + + GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = genv.getDefaultScreenDevice(); + genv.registerFont(font); + screenWidth = gd.getDisplayMode().getWidth(); + screenHeight = gd.getDisplayMode().getHeight(); + + UIManager.put("ScrollBar.thumb", tertiary); + UIManager.put("ScrollBar.track", primary); + UIManager.put("ToggleButton.select", tertiary); + UIManager.put("CheckBox.focus", secondary); + UIManager.put("CheckBox.select", tertiary); + + loading = new JLabel(" Loading - please wait. "); + loading.setForeground(Color.white); + loading.setBackground(Color.black); + loading.setBorder(BorderFactory.createLineBorder(Color.white)); + loading.setOpaque(true); + + selection = null; + setLayout(new BorderLayout()); + + initSideBar(); + initContent(); + + getContentPane().setBackground(primary); + + setLocationRelativeTo(null); + setDefaultCloseOperation(EXIT_ON_CLOSE); + + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + screenWidth = getWidth(); + screenHeight = getHeight(); + loot.setPreferredSize(new Dimension((int)(screenWidth*0.8), (int)(screenHeight*0.8))); + } + }); + + search(""); + pack(); + setVisible(true); + } + + private void search(String criteria) { + selection = null; + enableOptions(false); + List bossList = new ArrayList<>(); + for(Mob mob : mobs) { + if(mob.getName().toLowerCase().contains(criteria.toLowerCase())) { + bossList.add(mob); + } + } + if(bossList.size() == 0) { + enableOptions(true); + } else { + sideBar.remove(bosses); + genBosses(bossList); + } + } + + private void genBosses(List bossList) { + lastList = new ArrayList<>(bossList); + JPanel bossesPane = new JPanel(); + bossesPane.setBackground(primary); + bossButtons = new ArrayList<>(); + bossesPane.setLayout(new BoxLayout(bossesPane, BoxLayout.Y_AXIS)); + + for(Mob boss : bossList) { + JToggleButton bossButton = new JToggleButton(bossIcons.get(boss)); + bossButton.setBorderPainted(false); + bossButton.setBackground(primary); + bossButton.setToolTipText(""+boss.getName()+" "); + bossButton.setForeground(Color.orange); + bossButton.setOpaque(true); + bossButton.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + if(e.getStateChange() == ItemEvent.DESELECTED) { + selection = null; + enableOptions(false); + } else { + for(JToggleButton tmp : bossButtons) { + if(!tmp.getToolTipText().equals(bossButton.getToolTipText())) { + tmp.setSelected(false); + } + } + selection = boss; + enableOptions(true); + } + } + }); + bossesPane.add(bossButton); + bossesPane.setBackground(primary); + bossButtons.add(bossButton); // array + } + bosses = new JScrollPane(bossesPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + bosses.setBackground(primary); + sideBar.add(bosses, BorderLayout.CENTER); + } + + private void initSideBar() { + bossIcons = new HashMap<>(); + for(Mob boss : mobs) { + try { + BufferedImage img = ImageIO.read(getClass().getResource(boss.getIcon())); + int dim = (int)(screenWidth*0.1); + ImageIcon icon = new ImageIcon(img.getScaledInstance(dim,dim,Image.SCALE_SMOOTH)); + bossIcons.put(boss, icon); + } catch(Exception ex) { + ex.printStackTrace(); + //use some default icon?? + } + } + sideBar = new JPanel(); + sideBar.setLayout(new BorderLayout()); + search = new JTextField(); + search.setBackground(secondary); + search.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + search(search.getText()); + sideBar.revalidate(); + } + }); + sideBar.setBackground(primary); + sideBar.add(search, BorderLayout.NORTH); + genBosses(mobs); + add(sideBar, BorderLayout.WEST); + } + + private void simulateDrops() { + Random random = new Random(); + HashMap drops = new HashMap<>(); + + if(selection != null) { + for(int i=0; i"+drop.getName()+"
quantity: "+NumberFormat.getIntegerInstance().format(drops.get(drop))+"
value: "+NumberFormat.getIntegerInstance().format(drop.getValue())+"
total: "+print(total)+""; + BufferedImage img = ImageIO.read(getClass().getResource(drop.getIcon())); + ImageIcon icon = new ImageIcon(img.getScaledInstance(50,50,Image.SCALE_SMOOTH)); //scale to lootpane??? todo lol + JLabel itemLabel = new JLabel(icon); + itemLabel.setToolTipText(tipText); + + if(drops.get(drop) < 100_000) { + itemLabel.setForeground(Color.yellow); + itemLabel.setText(""+drops.get(drop)); + } else if(drops.get(drop) < 10_000_000) { + itemLabel.setForeground(Color.white); + itemLabel.setText((int)(drops.get(drop)/1_000)+"k"); + } else { + itemLabel.setForeground(Color.green); + itemLabel.setText((int)(drops.get(drop)/1_000_000)+"M"); + } + totalValue = totalValue.add(total); + + itemLabel.setIconTextGap(-50); + itemLabel.setHorizontalTextPosition(JLabel.RIGHT); + itemLabel.setVerticalTextPosition(JLabel.TOP); + itemLabel.setBackground(primary); + lootPane.add(itemLabel); + } catch(Exception ex) { + ex.printStackTrace(); + //use some default. + } + } + totalVal.setText("Total value: "+print(totalValue)+" "); + } + + private void initContent() { + content = new JPanel(); + content.setLayout(new BorderLayout()); + content.setBackground(primary); + options = new JPanel(new GridLayout()); + killsEntry = new JTextField(); + killsEntry.setBackground(secondary); + row = new JCheckBox("Ring of Wealth"); + row.setForeground(Color.orange); + + row.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + ringWealth = e.getStateChange() == ItemEvent.SELECTED; + } + }); + + options.add(killsEntry); + options.add(row); + options.setBackground(primary); + start = new JButton("simulate"); + start.setForeground(Color.orange); + start.setBackground(tertiary); + enableOptions(false); + options.add(start); + content.add(options, BorderLayout.NORTH); + lootPane = new JPanel(new SpringLayout()); + + start.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + kills = Long.valueOf(killsEntry.getText()); + } catch(Exception ex) { + kills = 1L; + } + + try { + Thread th = new Thread() { + @Override + public void run() { + enableOptions(false); + lootPane.removeAll(); + totalVal.setText("Total value: 0 "); + lootPane.add(loading); + lootPane.revalidate(); + lootPane.repaint(); + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + simulateDrops(); + } + }); + } catch(Exception ex) { + ex.printStackTrace(); + } + lootPane.remove(loading); + lootPane.revalidate(); + lootPane.repaint(); + enableOptions(true); + } + }; + th.start(); + } catch(Exception ex) { + ex.printStackTrace(); + } + } + }); + lootPane.setBackground(new Color(153, 132, 109)); + loot = new JScrollPane(lootPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + loot.setPreferredSize(new Dimension((int)(screenWidth*0.8), (int)(screenHeight*0.8))); + loot.setBackground(new Color(153, 132, 109)); + content.add(loot, BorderLayout.CENTER); + summary = new JPanel(new FlowLayout()); + totalVal = new JLabel("Total value: 0 "); + totalVal.setBackground(primary); + totalVal.setForeground(Color.orange); + summary.add(totalVal); + summary.setBackground(primary); + content.add(summary, BorderLayout.SOUTH); + add(content, BorderLayout.CENTER); + } + + private void enableOptions(boolean enable) { + start.setEnabled(enable); + killsEntry.setEnabled(enable); + row.setEnabled(enable); + } + + private String print(BigInteger val) { + StringBuilder formatted = new StringBuilder(val.toString()); + String backwards = formatted.reverse().toString(); + formatted = new StringBuilder(); + for(int i=0; i 0 && i%3 == 0) { + formatted.append(","); + } + formatted.append(backwards.charAt(i)); + } + return formatted.reverse().toString(); + } +} diff --git a/src/Item.java b/src/Item.java new file mode 100644 index 0000000..7fc3599 --- /dev/null +++ b/src/Item.java @@ -0,0 +1,39 @@ +class Item { + private int value; + private String name; + private String icon; + private boolean stackable; + + Item() { + this("nothing", 0, "/dev/null", true); + } + + Item(String n) { + name = n; + } + + Item(String n, int val, String ico, boolean stacks) { + this(n); + value = val; + icon = ico; + stackable = stacks; + } + + public String getName() { + return name; + } + public String getIcon() { + return icon; + } + public int getValue() { + return value; + } + + @Override + public boolean equals(Object other) { + if(other instanceof Item) { + return name.equals(((Item)other).name); + } + return false; + } +} diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..2ac26f9 --- /dev/null +++ b/src/Main.java @@ -0,0 +1,138 @@ +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.io.File; +import javax.imageio.ImageIO; +import javax.swing.JProgressBar; +import javax.swing.JFrame; +import javax.swing.UIManager; +import java.awt.image.BufferedImage; +import java.awt.Color; +import java.awt.Font; +import java.io.InputStream; +import javax.swing.BorderFactory; +import java.awt.Dimension; + +// If I ever make an info page for bosses/items, consider JTabbedPane +public class Main { + /* In mob/ + mogrify -resize 512x512 -background none -gravity center -extent 512x512 *.png + */ + /* In item/ + mogrify -resize 64x64 -background none -gravity center -extent 64x64 *.png + */ + // Find out how to have quantities[] with probabilities on drop() i.e: coins x 1000, 2000 + + public static void main(String[] args) { + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch(Exception ex) { + ex.printStackTrace(); + } + Font font; + + try { + InputStream ttf = new Main().getClass().getResource("assets/client/text-font.ttf").openStream(); + font = Font.createFont(Font.TRUETYPE_FONT, ttf).deriveFont(18f); + ttf.close(); + setFont(font); + } catch(Exception ex) { + System.out.println("Failed to load font."); + font = new Font(null, Font.PLAIN, 16); + } + + UIManager.put("ProgressBar.selectionForeground", Color.white); + UIManager.put("ProgressBar.selectionBackground", Color.white); + + JFrame loader = new JFrame("loading - please wait."); + loader.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + loader.setLocationRelativeTo(null); + + JProgressBar progress = new JProgressBar(0, 100); + progress.setValue(50); // remove this later, and increment this as it loads + progress.setStringPainted(true); + progress.setOpaque(true); + progress.setForeground(new Color(128,0,0)); + progress.setBackground(Color.black); + progress.setBorder(BorderFactory.createLineBorder(new Color(128,0,0))); + progress.setPreferredSize(new Dimension(250,40)); + + loader.setBackground(Color.black); + loader.add(progress); + loader.pack(); + loader.setVisible(true); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + setFont(font); + } catch(Exception ex) { + ex.printStackTrace(); + } + + BufferedImage img; + try { //Windows / Linux? + img = ImageIO.read(new Main().getClass().getResource("assets/client/favicon.png")); + try {//Mac + String className = "com.apple.eawt.Application"; + Class cls = Class.forName(className); + + Object application = cls.newInstance().getClass().getMethod("getApplication").invoke(null); + application.getClass().getMethod("setDockIconImage", java.awt.Image.class).invoke(application, img); + System.setProperty("apple.awt.application.name", "OSRS Loot Simulator"); + } catch(Exception ex) { + ex.printStackTrace(); + } + + new GUI(initMobs(), initItems(), img, progress, font); + } catch(Exception ex) { + ex.printStackTrace(); + } + loader.dispose(); + } + +//have a json file with items, use org.json to parse + private static List initItems() { + ArrayList items = new ArrayList<>(); + + // get items from some config file - either manual entry + // or read from wikipedia or find some api + // maybe if stuff is read dynamically from api or wiki + // just do it once in a while and keep a local file + + return items; + } + +//bosses + //Start w/ gwd bosses +//demi bosses +//raids/barrows +//popular slayer tasks +//popular off task +//all + private static List initMobs() { + ArrayList mobs = new ArrayList<>(); + + Item item = new Item("Abyssal Whip", 1952290, "assets/item/abyssal_whip.png", false); + Mob mob = new Mob("Abyssal Demon", "Zeah Catacombs", "assets/mob/abyssal_demon.png"); + HashMap dropTable = new HashMap<>(); + dropTable.put(0.001953125, item); //real + mob.setDropTable(dropTable); + mobs.add(mob); + + mobs.add(new Mob("Abyssal Sire", "The Abyss", "assets/mob/abyssal_sire.png")); + mobs.add(new Mob("General Graardor", "The God Wars Dungeon", "assets/mob/general_graardor.png")); + mobs.add(new Mob("Kree'Arra", "The God Wars Dungeon", "assets/mob/kree'arra.png")); + mobs.add(new Mob("K'ril Tsutsaroth", "The God Wars Dungeon", "assets/mob/k'ril_tsutsaroth.png")); + mobs.add(new Mob("Commander Zilyana", "The God Wars Dungeon", "assets/mob/commander_zilyana.png")); + + return mobs; + } + + private static void setFont(Font font) { + for(Object key : UIManager.getLookAndFeel().getDefaults().keySet()) { + if(key instanceof String && ((String)key).toLowerCase().contains("font")) { + UIManager.put(key, font); + } + } + } +} diff --git a/src/Mob.java b/src/Mob.java new file mode 100644 index 0000000..243f820 --- /dev/null +++ b/src/Mob.java @@ -0,0 +1,62 @@ +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.Map; + +//NOTE: hava a hashmap of item to another hashmap of probabilities to quantity +//that way a mob can drop 100gp, 200gp etc, and have seperate probabilities for each quantity. +// you'd get the item drop, then roll again and select quantities.get(item).get(prob) = quantity +class Mob { + private SortedMap dropTable; + private Map> quantities; //NOTE here + private String name; + private String location; + private String icon; + + Mob(String n, String loc, String ico) { + name = n; + location = loc; + icon = ico; + } + + String getName() { + return name; + } + String getIcon() { + return icon; + } + + void setDropTable(Map drops) { + dropTable = new TreeMap<>(); + double rate = 0.0; + for(Double key : drops.keySet()) { + rate += key; + dropTable.put(rate, drops.get(key)); + } + if(rate != 1.0) { + System.out.println(rate+" is not 100%."); + } + } + + boolean rareDropTable() { + return dropTable.containsValue(new Item("rare drop table")); + } + + Item drop(double rate) { + for(Double key : dropTable.keySet()) { + if(key >= rate) { + return dropTable.get(key); + } + } + return new Item(); + } + + // somehow worry about acheivement diaries affecting drop rate + + @Override + public boolean equals(Object other) { + if(other instanceof Mob) { + return name.equals(((Mob)other).name) && location.equals(((Mob)other).location); + } + return false; + } +}