From ee9d803005c41d98f1a3d27a86fd3252859b9ea1 Mon Sep 17 00:00:00 2001 From: Nijiko Yonskai Date: Fri, 4 Mar 2011 11:48:21 -0500 Subject: [PATCH] Cleaned and Fixed some issues, Rewrote hook system for iConomy and Permissions --- plugin.yml | 4 +- .../DynamicMarket/DatabaseCore.java | 391 +-- .../DynamicMarket/DynamicMarket.java | 478 ++-- .../haloinverse/DynamicMarket/ItemClump.java | 249 +- .../haloinverse/DynamicMarket/Items.java | 427 ++-- .../haloinverse/DynamicMarket/MarketItem.java | 1815 +++++++------- .../haloinverse/DynamicMarket/Messaging.java | 158 +- .../haloinverse/DynamicMarket/SQLHandler.java | 544 ++-- .../DynamicMarket/TransactionLogger.java | 122 +- .../haloinverse/DynamicMarket/iListen.java | 2231 ++++++++--------- .../haloinverse/DynamicMarket/iProperty.java | 379 ++- 11 files changed, 3075 insertions(+), 3723 deletions(-) diff --git a/plugin.yml b/plugin.yml index ddcc0bf..d4f518f 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,7 +1,7 @@ name: DynamicMarket main: com.gmail.haloinverse.DynamicMarket.DynamicMarket -version: 0.4.8 -author: HaloInverse +version: 0.4.8.1 +authors: [HaloInverse, Nijikokun] description: > A shop plugin building towards an interesting and flexible market system. commands: diff --git a/src/com/gmail/haloinverse/DynamicMarket/DatabaseCore.java b/src/com/gmail/haloinverse/DynamicMarket/DatabaseCore.java index 3fa9721..6226a74 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/DatabaseCore.java +++ b/src/com/gmail/haloinverse/DynamicMarket/DatabaseCore.java @@ -1,276 +1,131 @@ package com.gmail.haloinverse.DynamicMarket; - import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; - -public abstract class DatabaseCore -{ - public Type databaseType = null; - public String tableName; // default: SimpleMarket - public DynamicMarket plugin = null; - public String engine = "MyISAM"; - - public DatabaseCore(Type databaseType, String tableAccessed, String thisEngine, DynamicMarket thisPlugin) { - this.databaseType = databaseType; - this.tableName = tableAccessed; - if (thisEngine != null) - engine = thisEngine; - plugin = thisPlugin; - initialize(); - } - - protected boolean initialize() - { - return initialize(""); - } - - protected boolean initialize(String tableSuffix) { - if (!(checkTable(tableSuffix))) { - plugin.log.info("[" + plugin.name + "] Creating database."); - if (createTable(tableSuffix)) - { - plugin.log.info("[" + plugin.name + "] Database Created."); - return true; - } - else - { - plugin.log.severe("[" + plugin.name + "] Database creation *failed*."); - return false; - } - } - return false; - } - - protected boolean deleteDatabase() - { - return deleteDatabase(""); - } - - protected boolean deleteDatabase(String tableSuffix) - { - SQLHandler myQuery = new SQLHandler(this); - myQuery.executeStatement("DROP TABLE " + tableName+tableSuffix + ";"); - myQuery.close(); - if (myQuery.isOK) - plugin.log.info("[" + plugin.name + "] Database table successfully deleted."); - else - plugin.log.severe("[" + plugin.name + "] Database table could not be deleted."); - return myQuery.isOK; - } - - public boolean resetDatabase() - { - return resetDatabase(""); - } - - public boolean resetDatabase(String tableSuffix) - { - deleteDatabase(tableSuffix); - return initialize(tableSuffix); - } - - - protected Connection connection() throws ClassNotFoundException, SQLException { - //CHANGED: Sets connections to auto-commit, rather than emergency commit-on-close behaviour. - Connection newConn; - if (this.databaseType.equals(Type.SQLITE)) { -/* 52 */ Class.forName("org.sqlite.JDBC"); -/* 53 */ newConn = DriverManager.getConnection(DynamicMarket.sqlite); - return newConn; -/* */ } -/* 55 */ Class.forName("com.mysql.jdbc.Driver"); -/* 56 */ newConn = DriverManager.getConnection(DynamicMarket.mysql, DynamicMarket.mysql_user, DynamicMarket.mysql_pass); - newConn.setAutoCommit(true); - return newConn; - } - - protected String dbTypeString() - { - return ((this.databaseType.equals(Type.SQLITE)) ? "sqlite" : "mysql"); - } - - protected void logSevereException(String exDesc, Exception exDetail) - { - plugin.log.severe("[" + plugin.name + "]: " + exDesc + ": " + exDetail); - } - - protected void logSevereException(String exDesc) - { - plugin.log.severe("[" + plugin.name + "]: " + exDesc); - } - - protected boolean checkTable(String tableSuffix) - { - SQLHandler myQuery = new SQLHandler(this); - - boolean bool; - bool = myQuery.checkTable(tableName+tableSuffix); - myQuery.close(); - return bool; - } - - protected boolean checkTable() - { - return checkTable(""); - } - - protected abstract boolean createTable(String tableSuffix); - - protected boolean createTable() - { - return createTable(""); - } - /* - { - //SQLHandler myQuery = new SQLHandler(this); - //if (this.database.equals(Type.SQLITE)) - // myQuery.executeStatement("CREATE TABLE " + tableName+shopLabel + " ( id INT ( 255 ) PRIMARY KEY , item INT ( 255 ) NOT NULL, type INT ( 255 ) NOT NULL, buy INT ( 255 ) NOT NULL, sell INT ( 255 ) NOT NULL, per INT ( 255 ) NOT NULL);CREATE INDEX itemIndex on balances (item);CREATE INDEX typeIndex on balances (type);CREATE INDEX buyIndex on iBalances (buy);CREATE INDEX sellIndex on iBalances (sell);CREATE INDEX perIndex on iBalances (per);"); - //else - // myQuery.executeStatement("CREATE TABLE " + tableName+shopLabel + " ( id INT( 255 ) NOT NULL AUTO_INCREMENT, item INT( 255 ) NOT NULL, type INT( 255 ) NOT NULL, buy INT( 255 ) NOT NULL, sell INT( 255 ) NOT NULL, per INT( 255 ) NOT NULL ,PRIMARY KEY ( id ), INDEX ( item, type, buy, sell, per )) ENGINE = MYISAM;"); - //myQuery.close(); - //return myQuery.isOK; - return false; - } - */ - - public abstract boolean add(Object newObject); - /* - { - - SQLHandler myQuery = new SQLHandler(this); - myQuery.inputList.add(newItem.itemId); - myQuery.inputList.add(newItem.subType); - myQuery.inputList.add(newItem.buy); - myQuery.inputList.add(newItem.sell); - myQuery.inputList.add(newItem.count); - myQuery.prepareStatement("INSERT INTO " + tableName + " (item,type,buy,sell,per) VALUES (?,?,?,?,?)"); - myQuery.executeUpdate(); - - myQuery.close(); - return (myQuery.isOK); - - return false; - } - */ - - public abstract boolean update(Object updateRef); - /* - { - //CHANGED: Shouldn't need to alter item subtypes in existing records. New item+type records should be added instead. - SQLHandler myQuery = new SQLHandler(this); - - myQuery.inputList.add(updated.buy); - myQuery.inputList.add(updated.sell); - myQuery.inputList.add(updated.count); - myQuery.inputList.add(updated.itemId); - myQuery.inputList.add(updated.subType); - myQuery.prepareStatement("UPDATE " + tableName + " SET buy = ?, sell = ?, per = ? WHERE item = ? AND type = ?" + ((this.database.equals(Type.SQLITE)) ? "" : " LIMIT 1")); - - myQuery.executeUpdate(); - - myQuery.close(); - return (myQuery.isOK); - } - */ - - public abstract boolean remove(ItemClump removed); - /* - { - // CHANGED: Now accepts an itemType (through use of the ItemClump class). - SQLHandler myQuery = new SQLHandler(this); - - myQuery.inputList.add(removed.itemId); - myQuery.inputList.add(removed.subType); - myQuery.prepareStatement("DELETE FROM " + tableName + " WHERE item = ? AND type = ?" + ((this.database.equals(Type.SQLITE)) ? "" : " LIMIT 1")); - - myQuery.executeUpdate(); - - myQuery.close(); - return myQuery.isOK; - } - */ - - - - public abstract ArrayList list(int pageNum); - /* - { - //CHANGED: This now spits out a list of ShopItems, instead of a list of arrays of ints. - //If pageNum=0, return the entire list. - - //TODO: After incorporating items list into database, do text-matching. - SQLHandler myQuery = new SQLHandler(this); - ArrayList data = new ArrayList(); - int startItem = 0; - int numItems = 9999999; - if (pageNum > 0) - { - startItem = (pageNum - 1) * 8; - numItems = 8; - } - - myQuery.inputList.add(startItem); - myQuery.inputList.add(numItems); - myQuery.prepareStatement("SELECT * FROM " + tableName + " ORDER BY item ASC, type ASC LIMIT ?, ?"); - - myQuery.executeQuery(); - - if (myQuery.isOK) - try { - while (myQuery.rs.next()) - data.add(new ShopItem(myQuery.rs.getInt("item"),myQuery.rs.getInt("type"), myQuery.rs.getInt("buy"), myQuery.rs.getInt("sell"), myQuery.rs.getInt("per") )); - } catch (SQLException ex) { - logSevereException("SQL Error during ArrayList fetch: " + dbTypeString(), ex); - } - - myQuery.close(); - - return data; - } - */ - - - public abstract Object data(ItemClump thisItem); - /* - { - //CHANGED: Returns ShopItems now. - SQLHandler myQuery = new SQLHandler(this); - ShopItem data = null; - - myQuery.inputList.add(thisItem.itemId); - myQuery.inputList.add(thisItem.subType); - myQuery.prepareStatement("SELECT * FROM " + tableName + " WHERE item = ? AND type = ? LIMIT 1"); - - myQuery.executeQuery(); - - try { - if (myQuery.rs != null) - if (myQuery.rs.next()) - data = new ShopItem(myQuery.rs.getInt("item"), myQuery.rs.getInt("type"), myQuery.rs.getInt("buy"), myQuery.rs.getInt("sell"), myQuery.rs.getInt("per")); - } catch (SQLException ex) { - logSevereException("Error retrieving shop item data with " + dbTypeString(), ex); - data = null; - } - - myQuery.close(); - - if (data == null) { data = new ShopItem(); } - return data; - } - */ - - public static enum Type - { - SQLITE, MYSQL, FLATFILE; - } +public abstract class DatabaseCore { + + public Type databaseType = null; + public String tableName; // default: SimpleMarket + public DynamicMarket plugin = null; + public String engine = "MyISAM"; + + public DatabaseCore(Type databaseType, String tableAccessed, String thisEngine, DynamicMarket thisPlugin) { + this.databaseType = databaseType; + this.tableName = tableAccessed; + if (thisEngine != null) { + engine = thisEngine; + } + plugin = thisPlugin; + initialize(); + } + + protected boolean initialize() { + return initialize(""); + } + + protected boolean initialize(String tableSuffix) { + if (!(checkTable(tableSuffix))) { + plugin.log.info("[" + plugin.name + "] Creating database."); + if (createTable(tableSuffix)) { + plugin.log.info("[" + plugin.name + "] Database Created."); + return true; + } else { + plugin.log.severe("[" + plugin.name + "] Database creation *failed*."); + return false; + } + } + return false; + } + + protected boolean deleteDatabase() { + return deleteDatabase(""); + } + + protected boolean deleteDatabase(String tableSuffix) { + SQLHandler myQuery = new SQLHandler(this); + myQuery.executeStatement("DROP TABLE " + tableName + tableSuffix + ";"); + myQuery.close(); + + if (myQuery.isOK) { + plugin.log.info("[" + plugin.name + "] Database table successfully deleted."); + } else { + plugin.log.severe("[" + plugin.name + "] Database table could not be deleted."); + } + + return myQuery.isOK; + } + + public boolean resetDatabase() { + return resetDatabase(""); + } + + public boolean resetDatabase(String tableSuffix) { + deleteDatabase(tableSuffix); + return initialize(tableSuffix); + } + + protected Connection connection() throws ClassNotFoundException, SQLException { + //CHANGED: Sets connections to auto-commit, rather than emergency commit-on-close behaviour. + Connection newConn; + + if (this.databaseType.equals(Type.SQLITE)) { + Class.forName("org.sqlite.JDBC"); + newConn = DriverManager.getConnection(DynamicMarket.sqlite); + return newConn; + } + + Class.forName("com.mysql.jdbc.Driver"); + newConn = DriverManager.getConnection(DynamicMarket.mysql, DynamicMarket.mysql_user, DynamicMarket.mysql_pass); + newConn.setAutoCommit(true); + return newConn; + } + + protected String dbTypeString() { + return ((this.databaseType.equals(Type.SQLITE)) ? "sqlite" : "mysql"); + } + + protected void logSevereException(String exDesc, Exception exDetail) { + plugin.log.severe("[" + plugin.name + "]: " + exDesc + ": " + exDetail); + } + + protected void logSevereException(String exDesc) { + plugin.log.severe("[" + plugin.name + "]: " + exDesc); + } + + protected boolean checkTable(String tableSuffix) { + SQLHandler myQuery = new SQLHandler(this); + + boolean bool; + bool = myQuery.checkTable(tableName + tableSuffix); + myQuery.close(); + return bool; + } + + protected boolean checkTable() { + return checkTable(""); + } + + protected abstract boolean createTable(String tableSuffix); + + protected boolean createTable() { + return createTable(""); + } + + public abstract boolean add(Object newObject); + + public abstract boolean update(Object updateRef); + + public abstract boolean remove(ItemClump removed); + + public abstract ArrayList list(int pageNum); + + public abstract Object data(ItemClump thisItem); + + public static enum Type { + + SQLITE, MYSQL, FLATFILE; + } } - -/* Location: C:\Program Files\eclipse\Bukkit\SimpleShop.jar - * Qualified Name: com.nijikokun.bukkit.SimpleShop.Database - * Java Class Version: 5 (49.0) - * JD-Core Version: 0.5.3 - */ \ No newline at end of file diff --git a/src/com/gmail/haloinverse/DynamicMarket/DynamicMarket.java b/src/com/gmail/haloinverse/DynamicMarket/DynamicMarket.java index 881b06d..e99d54a 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/DynamicMarket.java +++ b/src/com/gmail/haloinverse/DynamicMarket/DynamicMarket.java @@ -1,13 +1,11 @@ package com.gmail.haloinverse.DynamicMarket; - +import com.nijiko.coelho.iConomy.iConomy; import com.nijikokun.bukkit.Permissions.Permissions; -import com.nijikokun.bukkit.iConomy.iConomy; -//import com.haloinverse.AnyConomy.AnyConomy; import java.io.File; import java.util.Timer; import java.util.logging.Logger; -//import org.bukkit.Server; +import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.event.Event; @@ -15,275 +13,207 @@ import org.bukkit.event.server.ServerListener; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; -//import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; - -public class DynamicMarket extends JavaPlugin -{ - public final Logger log = Logger.getLogger("Minecraft"); - - public String name; // = "SimpleMarket"; - public String codename = "Caribou"; - public String version; // = "0.4a"; - - public iListen playerListener = new iListen(this); - //public DMServerListener serverListener = new DMServerListener(this); - public static Permissions Permissions; - public static iProperty Settings; - public static String directory; // = "DynamicMarket" + File.separator; - public String shop_tag = "{BKT}[{}Shop{BKT}]{} "; - protected String currency;// = "Coin"; - protected int max_per_purchase = 64; - protected int max_per_sale = 64; - public String defaultShopAccount = ""; - public boolean defaultShopAccountFree = true; - - protected String database_type = "sqlite"; - protected static String sqlite = "jdbc:sqlite:" + directory + "shop.db"; - protected static String mysql = "jdbc:mysql://localhost:3306/minecraft"; - protected static String mysql_user = "root"; - protected static String mysql_pass = "pass"; - protected static String mysql_dbEngine = "MyISAM"; - protected static Timer timer = null; - protected static String csvFileName; - protected static String csvFilePath; - protected iConomy iC = null; - //protected AnyConomy anyConomy = null; - protected boolean econLoaded = false; - protected EconType econType = EconType.NONE; - protected Items items; - protected String itemsPath = ""; - protected DatabaseMarket db = null; - protected boolean wrapperMode = false; - protected boolean wrapperPermissions = false; - protected boolean simplePermissions = false; - protected PermissionInterface permissionWrapper = null; - protected TransactionLogger transLog = null; - protected String transLogFile = "transactions.log"; - protected boolean transLogAutoFlush = true; - private MyServerListener myServerListener = new MyServerListener(this); - //public static YamlPropFile yamlPropTest; - - private class MyServerListener extends ServerListener { - - private DynamicMarket plugin; - public MyServerListener(DynamicMarket thisPlugin) - { - this.plugin = thisPlugin; - } - - @Override - public void onPluginEnabled(PluginEvent event) - { - // This is called for plugins enabled AFTER this one. - String thisPluginName = event.getPlugin().getDescription().getName(); - if(thisPluginName.equals("iConomy")) - { - plugin.connectEconomy(event.getPlugin()); - } - } - } - - public void onDisable() { - log.info(Messaging.bracketize(name) + " version " + Messaging.bracketize(version) + " (" + codename + ") disabled"); - } - - @Override - public void onEnable() { - PluginDescriptionFile desc = getDescription(); - getDataFolder().mkdir(); - - name = desc.getName(); - version = desc.getVersion(); - - directory = getDataFolder() + File.separator; - sqlite = "jdbc:sqlite:" + directory + "shop.db"; - - setup(); - //setupItems(); //CHANGED: Initialisation moved to Items constructor. - setupEconomy(); - setupPermissions(); - registerEvents(); - log.info(Messaging.bracketize(name) + " version " + Messaging.bracketize(version) + " (" + codename + ") enabled"); - } - - private void registerEvents() - { - PluginManager thisPluginManager = getServer().getPluginManager(); - thisPluginManager.registerEvent(Event.Type.PLAYER_COMMAND, this.playerListener, Event.Priority.Normal, this); - thisPluginManager.registerEvent(Event.Type.PLUGIN_ENABLE, this.myServerListener, Event.Priority.Monitor, this); - } - - @Override - public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) - { - if (!wrapperMode) - { - boolean thisReturn; - thisReturn = this.playerListener.parseCommand(sender, cmd.getName(), args, "", defaultShopAccount, defaultShopAccountFree); - return thisReturn; - } - else - return true; - } - - public boolean wrapperCommand(CommandSender sender, String cmd, String[] args, String shopLabel, String accountName, boolean freeAccount) - { - return this.playerListener.parseCommand(sender, cmd, args, (shopLabel == null ? "" : shopLabel), accountName, freeAccount); - } - - public boolean wrapperCommand(CommandSender sender, String cmd, String[] args, String shopLabel) - { - return wrapperCommand(sender, cmd, args, (shopLabel == null ? "" : shopLabel), defaultShopAccount, defaultShopAccountFree); - } - - public boolean wrapperCommand(CommandSender sender, String cmd, String[] args) - { - return wrapperCommand(sender, cmd, args, ""); - } - - - public void setup() - { - Settings = new iProperty(getDataFolder() + File.separator + name + ".settings"); - - //ItemsFile = new iProperty("items.db"); - itemsPath = Settings.getString("items-db-path", getDataFolder() + File.separator); - items = new Items(itemsPath + "items.db", this); - - shop_tag = Settings.getString("shop-tag", shop_tag); - max_per_purchase = Settings.getInt("max-items-per-purchase", 64); - max_per_sale = Settings.getInt("max-items-per-sale", 64); - - this.database_type = Settings.getString("database-type", "sqlite"); - - mysql = Settings.getString("mysql-db", mysql); - mysql_user = Settings.getString("mysql-user", mysql_user); - mysql_pass = Settings.getString("mysql-pass", mysql_pass); - mysql_dbEngine = Settings.getString("mysql-dbengine", mysql_dbEngine); - - if (this.database_type.equalsIgnoreCase("mysql")) - db = new DatabaseMarket(DatabaseMarket.Type.MYSQL, "Market", items, mysql_dbEngine, this); - else - db = new DatabaseMarket(DatabaseMarket.Type.SQLITE, "Market", items, "", this); - - csvFileName = Settings.getString("csv-file", "shopDB.csv"); - csvFilePath = Settings.getString("csv-file-path", getDataFolder() + File.separator); - wrapperMode = Settings.getBoolean("wrapper-mode", false); - simplePermissions = Settings.getBoolean("simple-permissions", false); - wrapperPermissions = Settings.getBoolean("wrapper-permissions", false); - - Messaging.colNormal = "&" + Settings.getString("text-colour-normal", "e"); - Messaging.colCmd = "&" + Settings.getString("text-colour-command", "f"); - Messaging.colBracket = "&" + Settings.getString("text-colour-bracket", "d"); - Messaging.colParam = "&" + Settings.getString("text-colour-param", "b"); - Messaging.colError = "&" + Settings.getString("text-colour-error", "c"); - - defaultShopAccount = Settings.getString("default-shop-account", ""); - defaultShopAccountFree = Settings.getBoolean("default-shop-account-free", defaultShopAccountFree); - - transLogFile = Settings.getString("transaction-log-file", transLogFile); - transLogAutoFlush = Settings.getBoolean("transaction-log-autoflush", transLogAutoFlush); - if ((transLogFile != null) && (!transLogFile.isEmpty())) - transLog = new TransactionLogger(this, getDataFolder() + File.separator + transLogFile, transLogAutoFlush); - else - transLog = new TransactionLogger(this, null, false); - - String econTypeString = Settings.getString("economy-plugin", "iconomy3"); - if (econTypeString.equalsIgnoreCase("iconomy3")) - econType = EconType.ICONOMY3; - else if (econTypeString.equalsIgnoreCase("anyconomy")) - econType = EconType.ANYCONOMY; - else - { - log.severe(Messaging.bracketize(name) + " Invalid economy setting for 'economy-plugin='."); - econType = EconType.NONE; - } - - //yamlPropTest = new YamlPropFile(getDataFolder() + File.separator + "SimpleMarket.yml"); - //yamlPropTest.load(); - } - - public void setupPermissions() - { - if (simplePermissions) - { - Permissions = null; - log.info(Messaging.bracketize(name) + " Simple permission system active."); - } - else if (wrapperPermissions) - log.info(Messaging.bracketize(name) + " Permissions will be delegated to wrapper plugin."); - else - { - Plugin test = getServer().getPluginManager().getPlugin("Permissions"); - - if (Permissions == null) - if (test != null) { - Permissions = (Permissions)test; - log.info(Messaging.bracketize(name) + " Standard Permission plugin enabled."); - } else { - log.info(Messaging.bracketize(name) + " Permission system not enabled. Disabling plugin."); - getServer().getPluginManager().disablePlugin(this); - } - } - } - - public void setupEconomy() - { - // Called with iConomy 2.1(Cookies wrapper). - // This catches plugins enabled BEFORE this plugin. - Plugin test = getServer().getPluginManager().getPlugin("iConomy"); - if (test != null) { - connectEconomy(test); - } - - test = getServer().getPluginManager().getPlugin("AnyConomy"); - if (test != null) { - connectEconomy(test); - } - - } - - public void connectEconomy(Plugin thisPlugin) - { - if(econType == EconType.ICONOMY3) - { - if(thisPlugin instanceof iConomy) - connectToiConomy((iConomy)thisPlugin); - } - - /* - else if(econType == EconType.ANYCONOMY) - { - if(thisPlugin instanceof AnyConomy) - connectToAnyConomy((AnyConomy)thisPlugin); - } - */ - - } - - /* - public void connectToAnyConomy(AnyConomy thisPlugin) - { - anyConomy = thisPlugin; - currency = ""; - econLoaded = true; - log.info(Messaging.bracketize(name) + " AnyConomy connected."); - } - */ - - - public void connectToiConomy(iConomy thisPlugin) - { - iC = thisPlugin; - currency = iConomy.currency; - econLoaded = true; - log.info(Messaging.bracketize(name) + " iConomy connected."); - } - - public static enum EconType - { - NONE, ICONOMY2, ICONOMY3, ANYCONOMY; - } -} \ No newline at end of file + +public class DynamicMarket extends JavaPlugin { + + public final Logger log = Logger.getLogger("Minecraft"); + public String name; // = "SimpleMarket"; + public String codename = "Caribou"; + public String version; // = "0.4a"; + public iListen playerListener = new iListen(this); + //public DMServerListener serverListener = new DMServerListener(this); + public static Permissions Permissions; + public static iProperty Settings; + public static String directory; // = "DynamicMarket" + File.separator; + public String shop_tag = "{BKT}[{}Shop{BKT}]{} "; + protected String currency;// = "Coin"; + protected int max_per_purchase = 64; + protected int max_per_sale = 64; + public String defaultShopAccount = ""; + public boolean defaultShopAccountFree = true; + public static iConomy iConomy = null; + protected String database_type = "sqlite"; + protected static String sqlite = "jdbc:sqlite:" + directory + "shop.db"; + protected static String mysql = "jdbc:mysql://localhost:3306/minecraft"; + protected static String mysql_user = "root"; + protected static String mysql_pass = "pass"; + protected static String mysql_dbEngine = "MyISAM"; + protected static Timer timer = null; + protected static String csvFileName; + protected static String csvFilePath; + protected boolean econLoaded = false; + protected EconType econType = EconType.NONE; + protected Items items; + protected String itemsPath = ""; + protected DatabaseMarket db = null; + protected boolean wrapperMode = false; + protected boolean wrapperPermissions = false; + protected boolean simplePermissions = false; + protected PermissionInterface permissionWrapper = null; + protected TransactionLogger transLog = null; + protected String transLogFile = "transactions.log"; + protected boolean transLogAutoFlush = true; + private MyServerListener myServerListener = new MyServerListener(this); + + private class MyServerListener extends ServerListener { + + private DynamicMarket plugin; + + public MyServerListener(DynamicMarket thisPlugin) { + this.plugin = thisPlugin; + } + + @Override + public void onPluginEnabled(PluginEvent event) { + if (plugin.iConomy == null) { + Plugin iConomy = plugin.getServer().getPluginManager().getPlugin("iConomy"); + + if (iConomy != null) { + if (iConomy.isEnabled()) { + plugin.iConomy = (iConomy) iConomy; + plugin.InitializeEconomy(); + } + } + } + + if (plugin.Permissions == null && !plugin.simplePermissions) { + Plugin Permissions = plugin.getServer().getPluginManager().getPlugin("Permissions"); + + if (Permissions != null) { + if (Permissions.isEnabled()) { + plugin.Permissions = (Permissions) Permissions; + System.out.println(Messaging.bracketize(plugin.name) + " hooked into Permissions."); + } + } + } + } + } + + public void onDisable() { + log.info(Messaging.bracketize(name) + " version " + Messaging.bracketize(version) + " (" + codename + ") disabled"); + } + + @Override + public void onEnable() { + PluginDescriptionFile desc = getDescription(); + getDataFolder().mkdir(); + + name = desc.getName(); + version = desc.getVersion(); + + directory = getDataFolder() + File.separator; + sqlite = "jdbc:sqlite:" + directory + "shop.db"; + + setup(); + setupPermissions(); + registerEvents(); + log.info(Messaging.bracketize(name) + " version " + Messaging.bracketize(version) + " (" + codename + ") enabled"); + } + + private void registerEvents() { + PluginManager thisPluginManager = getServer().getPluginManager(); + // thisPluginManager.registerEvent(Event.Type.PLAYER_COMMAND, this.playerListener, Event.Priority.Normal, this); + thisPluginManager.registerEvent(Event.Type.PLUGIN_ENABLE, this.myServerListener, Event.Priority.Monitor, this); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + if (!wrapperMode) { + boolean thisReturn; + thisReturn = this.playerListener.parseCommand(sender, cmd.getName(), args, "", defaultShopAccount, defaultShopAccountFree); + return thisReturn; + } else { + return true; + } + } + + public boolean wrapperCommand(CommandSender sender, String cmd, String[] args, String shopLabel, String accountName, boolean freeAccount) { + return this.playerListener.parseCommand(sender, cmd, args, (shopLabel == null ? "" : shopLabel), accountName, freeAccount); + } + + public boolean wrapperCommand(CommandSender sender, String cmd, String[] args, String shopLabel) { + return wrapperCommand(sender, cmd, args, (shopLabel == null ? "" : shopLabel), defaultShopAccount, defaultShopAccountFree); + } + + public boolean wrapperCommand(CommandSender sender, String cmd, String[] args) { + return wrapperCommand(sender, cmd, args, ""); + } + + public void setup() { + Settings = new iProperty(getDataFolder() + File.separator + name + ".settings"); + + //ItemsFile = new iProperty("items.db"); + itemsPath = Settings.getString("items-db-path", getDataFolder() + File.separator); + items = new Items(itemsPath + "items.db", this); + + shop_tag = Settings.getString("shop-tag", shop_tag); + max_per_purchase = Settings.getInt("max-items-per-purchase", 64); + max_per_sale = Settings.getInt("max-items-per-sale", 64); + + this.database_type = Settings.getString("database-type", "sqlite"); + + mysql = Settings.getString("mysql-db", mysql); + mysql_user = Settings.getString("mysql-user", mysql_user); + mysql_pass = Settings.getString("mysql-pass", mysql_pass); + mysql_dbEngine = Settings.getString("mysql-dbengine", mysql_dbEngine); + + if (this.database_type.equalsIgnoreCase("mysql")) { + db = new DatabaseMarket(DatabaseMarket.Type.MYSQL, "Market", items, mysql_dbEngine, this); + } else { + db = new DatabaseMarket(DatabaseMarket.Type.SQLITE, "Market", items, "", this); + } + + csvFileName = Settings.getString("csv-file", "shopDB.csv"); + csvFilePath = Settings.getString("csv-file-path", getDataFolder() + File.separator); + wrapperMode = Settings.getBoolean("wrapper-mode", false); + simplePermissions = Settings.getBoolean("simple-permissions", false); + wrapperPermissions = Settings.getBoolean("wrapper-permissions", false); + + Messaging.colNormal = "&" + Settings.getString("text-colour-normal", "e"); + Messaging.colCmd = "&" + Settings.getString("text-colour-command", "f"); + Messaging.colBracket = "&" + Settings.getString("text-colour-bracket", "d"); + Messaging.colParam = "&" + Settings.getString("text-colour-param", "b"); + Messaging.colError = "&" + Settings.getString("text-colour-error", "c"); + + defaultShopAccount = Settings.getString("default-shop-account", ""); + defaultShopAccountFree = Settings.getBoolean("default-shop-account-free", defaultShopAccountFree); + + transLogFile = Settings.getString("transaction-log-file", transLogFile); + transLogAutoFlush = Settings.getBoolean("transaction-log-autoflush", transLogAutoFlush); + if ((transLogFile != null) && (!transLogFile.isEmpty())) { + transLog = new TransactionLogger(this, getDataFolder() + File.separator + transLogFile, transLogAutoFlush); + } else { + transLog = new TransactionLogger(this, null, false); + } + + String econTypeString = Settings.getString("economy-plugin", "iconomy4"); + if (econTypeString.equalsIgnoreCase("iconomy4")) { + econType = EconType.ICONOMY4; + } else { + log.severe(Messaging.bracketize(name) + " Invalid economy setting for 'economy-plugin='."); + econType = EconType.NONE; + } + } + + public void setupPermissions() { + if (simplePermissions) { + Permissions = null; + log.info(Messaging.bracketize(name) + " Simple permission system active."); + } else if (wrapperPermissions) { + log.info(Messaging.bracketize(name) + " Permissions will be delegated to wrapper plugin."); + } + } + + public void InitializeEconomy() { + currency = iConomy.getBank().getCurrency(); + econLoaded = true; + log.info(Messaging.bracketize(name) + " successfully hooked into iConomy."); + } + + public static enum EconType { + + NONE, ICONOMY4; + } +} diff --git a/src/com/gmail/haloinverse/DynamicMarket/ItemClump.java b/src/com/gmail/haloinverse/DynamicMarket/ItemClump.java index 2d98c75..c47f884 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/ItemClump.java +++ b/src/com/gmail/haloinverse/DynamicMarket/ItemClump.java @@ -2,137 +2,120 @@ public class ItemClump { - // Implemented because bukkit's ItemStack methods don't handle item subtypes consistently. - - // Added in to be a convenient package for grabbing entire items worth of shop data at once, - // instead of one int at at time or in an easily-confused array. - // Also factorizes in some redundant string-parsing code, making it easier to change standard input formats - // if necessary (and shrinking the compiled .jar significantly) - public int itemId; // id of item - public int subType; // Subtype of item (i.e. dye colour); 0 if undamaged single-typed item. - public int count; // Number of items in this clump. - - public ItemClump() - { - // Default constructor with no parameters. - itemId = -1; - subType = 0; - count = 1; - } - - public ItemClump(int newId, int newType, int newCount) - { - itemId = newId; - subType = newType; - count = newCount; - } - - public ItemClump(int newId, int newType) - { - itemId = newId; - subType = newType; - count = 1; - } - - public ItemClump(String initString, DatabaseMarket namesDB, String shopLabel) - { - //Valid input string formats: - //"[ID(,Type)](:Count) (ignored)" - //"[ItemName](:Count) (ignored)" - //Pass null to namesDB to skip name lookup. - itemId = -1; - subType = 0; - count = 1; - String[] idData; - String[] initData = initString.split(" "); - boolean subtypeParsed = false; - - if (initData[0].contains(":")) - { - // Count detected. Pull it out, if it's valid. - idData = initData[0].split(":"); - try - { - count = Integer.valueOf(idData[1]).intValue(); - } - catch (NumberFormatException e) - { - count = 1; - } - initData[0] = idData[0]; - } - - if (initData[0].contains(",")) - { - // Subtype detected. Pull it out, if it's valid. - idData = initData[0].split(","); - try - { - subType = Integer.valueOf(idData[1]).intValue(); - subtypeParsed = true; - } - catch (NumberFormatException e) - { - subType = 0; - } - initData[0] = idData[0]; - } - - // Parse stripped item name, if possible. + // Implemented because bukkit's ItemStack methods don't handle item subtypes consistently. + // Added in to be a convenient package for grabbing entire items worth of shop data at once, + // instead of one int at at time or in an easily-confused array. + // Also factorizes in some redundant string-parsing code, making it easier to change standard input formats + // if necessary (and shrinking the compiled .jar significantly) + public int itemId; // id of item + public int subType; // Subtype of item (i.e. dye colour); 0 if undamaged single-typed item. + public int count; // Number of items in this clump. - try - { - itemId = Integer.valueOf(initData[0]).intValue(); - } catch (NumberFormatException ex) { - // It's trying to be a name. Find it. - if (initData[0].equalsIgnoreCase("default")) - { - itemId = -1; - subType = -1; - } - else - { - if (namesDB != null) - { - ItemClump foundItem = namesDB.nameLookup(initData[0], shopLabel); - if (foundItem != null) - { - itemId = foundItem.itemId; - if (!subtypeParsed) - subType = foundItem.subType; - } - } - } - } - - if (count < 1) count = 1; - } - - public String idString() { - return String.valueOf(itemId) + (subType == 0 ? "" : "," + String.valueOf(subType)); - } - - public String getName(DatabaseMarket namesDB, String shopLabel) - { - // Returns the name of this item. - // Really ought to use DatabaseMarket for name lookups... - return namesDB.getName(this, shopLabel); - } - - public boolean isValid() - { - if ((itemId != -1) && (subType != -1)) - return true; - if (isDefault()) - return true; - return false; - } - - public boolean isDefault() - { - if ((itemId == -1) && (subType == -1)) - return true; - return false; - } - - } + public ItemClump() { + // Default constructor with no parameters. + itemId = -1; + subType = 0; + count = 1; + } + + public ItemClump(int newId, int newType, int newCount) { + itemId = newId; + subType = newType; + count = newCount; + } + + public ItemClump(int newId, int newType) { + itemId = newId; + subType = newType; + count = 1; + } + + public ItemClump(String initString, DatabaseMarket namesDB, String shopLabel) { + //Valid input string formats: + //"[ID(,Type)](:Count) (ignored)" + //"[ItemName](:Count) (ignored)" + //Pass null to namesDB to skip name lookup. + itemId = -1; + subType = 0; + count = 1; + String[] idData; + String[] initData = initString.split(" "); + boolean subtypeParsed = false; + + if (initData[0].contains(":")) { + // Count detected. Pull it out, if it's valid. + idData = initData[0].split(":"); + try { + count = Integer.valueOf(idData[1]).intValue(); + } catch (NumberFormatException e) { + count = 1; + } + initData[0] = idData[0]; + } + + if (initData[0].contains(",")) { + // Subtype detected. Pull it out, if it's valid. + idData = initData[0].split(","); + try { + subType = Integer.valueOf(idData[1]).intValue(); + subtypeParsed = true; + } catch (NumberFormatException e) { + subType = 0; + } + initData[0] = idData[0]; + } + + // Parse stripped item name, if possible. + + try { + itemId = Integer.valueOf(initData[0]).intValue(); + } catch (NumberFormatException ex) { + // It's trying to be a name. Find it. + if (initData[0].equalsIgnoreCase("default")) { + itemId = -1; + subType = -1; + } else { + if (namesDB != null) { + ItemClump foundItem = namesDB.nameLookup(initData[0], shopLabel); + if (foundItem != null) { + itemId = foundItem.itemId; + if (!subtypeParsed) { + subType = foundItem.subType; + } + } + } + } + } + + if (count < 1) { + count = 1; + } + } + + public String idString() { + return String.valueOf(itemId) + (subType == 0 ? "" : "," + String.valueOf(subType)); + } + + public String getName(DatabaseMarket namesDB, String shopLabel) { + // Returns the name of this item. + // Really ought to use DatabaseMarket for name lookups... + return namesDB.getName(this, shopLabel); + } + + public boolean isValid() { + if ((itemId != -1) && (subType != -1)) { + return true; + } + if (isDefault()) { + return true; + } + return false; + } + + public boolean isDefault() { + if ((itemId == -1) && (subType == -1)) { + return true; + } + return false; + } +} diff --git a/src/com/gmail/haloinverse/DynamicMarket/Items.java b/src/com/gmail/haloinverse/DynamicMarket/Items.java index d70844e..d37e2a6 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/Items.java +++ b/src/com/gmail/haloinverse/DynamicMarket/Items.java @@ -1,234 +1,197 @@ package com.gmail.haloinverse.DynamicMarket; -//CHANGED: This was changed into an instanced class. -//CHANGED: Untyped items have a subtype (stored as damage) field = 0, NOT -1! -// This was completely breaking attempts to support typed items, i.e. logs/dyes/wool. -//TODO: Consider moving purely player-inventory-related methods into another class. -//TODO: Change "validate*" methods to something more descriptive. -//TODO: Add MySQL/SQLite support, with import from flat-file. - -/* */ //package com.nijikokun.bukkit.SimpleShop; -/* */ -/* */ import java.util.HashMap; - import java.util.Iterator; - import java.util.Map; - import org.bukkit.Material; -/* */ import org.bukkit.entity.Player; -/* */ import org.bukkit.inventory.ItemStack; - import org.bukkit.inventory.PlayerInventory; -/* */ -/* */ public class Items -/* */ { - - private HashMap itemsData; - private iProperty ItemsFile; - private DynamicMarket plugin; - - public Items(String itemFileName, DynamicMarket thisPlugin) - { - //TODO: Handle cases where the plugin loads, but items.db doesn't. - //TODO: Add user command for reloading items.db. - //TODO: Make item file format more generic. - this.plugin = thisPlugin; - ItemsFile = new iProperty(itemFileName); - // Following code originally in setupItems from SimpleShop -/* 169 */ Map mappedItems = null; -/* 170 */ itemsData = new HashMap(); -/* */ try -/* */ { -/* 173 */ mappedItems = ItemsFile.returnMap(); -/* */ } catch (Exception ex) { -/* 175 */ plugin.log.info(Messaging.bracketize(new StringBuilder().append(plugin.name).append(" Flatfile").toString()) + " could not grab item list!"); -/* */ } -/* */ Iterator i$; -/* 178 */ if (mappedItems != null) -/* 179 */ for (i$ = mappedItems.keySet().iterator(); i$.hasNext(); ) { Object item = i$.next(); -/* 180 */ String id = (String)item; -/* 181 */ String itemName = mappedItems.get(item); -/* 182 */ itemsData.put(id, itemName); -/* */ } -/* */ } - -/* */ public String name(String idString) - // Fetches the item name given an id string. - // Subtype, if present, is in the input format ("[id],[subtype]") -/* */ { -/* 22 */ if (itemsData.containsKey(idString)) { -/* 23 */ return ((String)itemsData.get(idString)); -/* */ } - if ((!(idString.contains(","))) && (itemsData.containsKey(idString+",0"))) - return((String)itemsData.get(idString+",0")); -/* */ // Fallback: Fetch the name from the bukkit Material class. -/* 26 */ //for (Material item : Material.values()) { -/* 27 */ // if (item.getId() == id) { -/* 28 */ // return item.toString(); -/* */ // } -/* */ //} -/* */ -/* 32 */ //return Misc.string(id); - return ("UNKNOWN"); -/* */ } - - public String name(ItemClump itemData) - { - // Fetches the item name given an ItemClump. - return name(Integer.toString(itemData.itemId) + (itemData.subType != 0 ? "," + Integer.toString(itemData.subType) : "")); - } - -/* */ -/* */ public void setName(String id, String name) -/* */ { -/* 42 */ itemsData.put(id, name); -/* 43 */ ItemsFile.setString(id, name); -/* */ } -/* */ - - public static boolean has(Player player, ItemClump scanItem, int numBundles) - { - return (hasAmount(player, scanItem) >= (scanItem.count * numBundles)); - } - - public static int hasAmount(Player player, ItemClump scanItem) - { - PlayerInventory inventory = player.getInventory(); - ItemStack[] items = inventory.getContents(); - int amount = 0; - - for (ItemStack item : items) { - if ((item != null) && (item.getTypeId() == scanItem.itemId) && (item.getDurability() == (byte)scanItem.subType)) { - amount += item.getAmount(); - } - } - return amount; - } - - public static boolean has(Player player, int itemId, int itemType, int amount) - { - return (hasAmount(player, new ItemClump(itemId, itemType)) >= amount); - } - - public void remove(Player player, ItemClump item, int amount) - { - // TODO: Clean this up once Bukkit's inventory.removeItem(ItemStack[]) code handles subtypes. - // Note that this removes (item.count * amount) items from the player's inventory. - // This is to streamline removing multiples of bundle counts. - PlayerInventory inventory = player.getInventory(); - ItemStack[] items = inventory.getContents(); - ItemStack thisItem; - int toRemove = item.count*amount; - - for (int invSlot = 35; (invSlot >= 0) && (toRemove > 0); --invSlot) - { - thisItem = items[invSlot]; - if ((items[invSlot] != null) && (thisItem.getTypeId() == item.itemId) && (thisItem.getDurability() == (byte)item.subType)) - { - toRemove -= thisItem.getAmount(); - inventory.clear(invSlot); - } - } - - if (toRemove < 0) // removed too many! put some back! - inventory.addItem(new ItemStack[] { new ItemStack(item.itemId, -toRemove, (byte)item.subType) }); - } - - public ItemClump nameLookup(String item) - { - // Given an item name (with optional ",", returns an ItemClump loaded with the id and subtype. - // If name is not found, returns null. - - int itemId = -1; - int itemSubtype = 0; - ItemClump returnedItem = null; - - for (String id : itemsData.keySet()) { - if (((String)itemsData.get(id)).equalsIgnoreCase(item)) { - if (id.contains(",")) { - itemId = Integer.valueOf(id.split(",")[0]).intValue(); - itemSubtype = Integer.valueOf(id.split(",")[1]).intValue(); - } - else { - itemId = Integer.valueOf(id).intValue(); - itemSubtype = 0; - } - returnedItem = new ItemClump(itemId, itemSubtype); - break; - } - } - - if (returnedItem != null) - return returnedItem; - - // No exact match found: Try partial-name matching. - String itemLower = item.toLowerCase(); - for (String id : itemsData.keySet()) { - if (((String)itemsData.get(id)).toLowerCase().contains(itemLower)) { - if (id.contains(",")) { - itemId = Integer.valueOf(id.split(",")[0]).intValue(); - itemSubtype = Integer.valueOf(id.split(",")[1]).intValue(); - } - else { - itemId = Integer.valueOf(id).intValue(); - itemSubtype = 0; - } - returnedItem = new ItemClump(itemId, itemSubtype); - break; - } - } - - return returnedItem; - } - - - public static boolean validateType(int id, int type) - // Given an id and a subtype, confirms that the selected subtype is valid. - //CHANGED: Rewritten as a switch block. Cleaner & faster. - { - if (type == 0) - return true; - if (type < 0) - return false; - - switch (id) - { - case 35: - case 63: - case 351: - return (type <= 15); - case 17: - return (type <= 2); - case 53: - case 64: - case 67: - case 71: - case 77: - case 86: - case 91: - return (type <= 3); - case 66: - return (type <= 9); - case 68: - return ((type >= 2) && (type <= 5)); - default: - return false; - } - } - - -/* */ public static boolean checkID(int id) - // ? Confirms that the given id is known by bukkit as an item id. -/* */ { -/* 289 */ for (Material item : Material.values()) { -/* 290 */ if (item.getId() == id) { -/* 291 */ return true; -/* */ } -/* */ } -/* */ -/* 295 */ return false; -/* */ } -/* */ } - -/* Location: C:\Program Files\eclipse\Bukkit\SimpleShop.jar - * Qualified Name: com.nijikokun.bukkit.SimpleShop.Items - * Java Class Version: 5 (49.0) - * JD-Core Version: 0.5.3 - */ \ No newline at end of file +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +public class Items { + + private HashMap itemsData; + private iProperty ItemsFile; + private DynamicMarket plugin; + + public Items(String itemFileName, DynamicMarket thisPlugin) { + //TODO: Handle cases where the plugin loads, but items.db doesn't. + //TODO: Add user command for reloading items.db. + //TODO: Make item file format more generic. + this.plugin = thisPlugin; + ItemsFile = new iProperty(itemFileName); + // Following code originally in setupItems from SimpleShop + Map mappedItems = null; + itemsData = new HashMap(); + + try { + mappedItems = ItemsFile.returnMap(); + } catch (Exception ex) { + plugin.log.info(Messaging.bracketize(new StringBuilder().append(plugin.name).append(" Flatfile").toString()) + " could not grab item list!"); + } + + Iterator i$; + + if (mappedItems != null) { + for (i$ = mappedItems.keySet().iterator(); i$.hasNext();) { + Object item = i$.next(); + String id = (String) item; + String itemName = mappedItems.get(item); + itemsData.put(id, itemName); + } + } + } + + public String name(String idString) { + if (itemsData.containsKey(idString)) { + return ((String) itemsData.get(idString)); + } + if ((!(idString.contains(","))) && (itemsData.containsKey(idString + ",0"))) { + return ((String) itemsData.get(idString + ",0")); + } + + return ("UNKNOWN"); + } + + public String name(ItemClump itemData) { + // Fetches the item name given an ItemClump. + return name(Integer.toString(itemData.itemId) + (itemData.subType != 0 ? "," + Integer.toString(itemData.subType) : "")); + } + + public void setName(String id, String name) { + itemsData.put(id, name); + ItemsFile.setString(id, name); + } + + public static boolean has(Player player, ItemClump scanItem, int numBundles) { + return (hasAmount(player, scanItem) >= (scanItem.count * numBundles)); + } + + public static int hasAmount(Player player, ItemClump scanItem) { + PlayerInventory inventory = player.getInventory(); + ItemStack[] items = inventory.getContents(); + int amount = 0; + + for (ItemStack item : items) { + if ((item != null) && (item.getTypeId() == scanItem.itemId) && (item.getDurability() == (byte) scanItem.subType)) { + amount += item.getAmount(); + } + } + return amount; + } + + public static boolean has(Player player, int itemId, int itemType, int amount) { + return (hasAmount(player, new ItemClump(itemId, itemType)) >= amount); + } + + public void remove(Player player, ItemClump item, int amount) { + // TODO: Clean this up once Bukkit's inventory.removeItem(ItemStack[]) code handles subtypes. + // Note that this removes (item.count * amount) items from the player's inventory. + // This is to streamline removing multiples of bundle counts. + PlayerInventory inventory = player.getInventory(); + ItemStack[] items = inventory.getContents(); + ItemStack thisItem; + int toRemove = item.count * amount; + + for (int invSlot = 35; (invSlot >= 0) && (toRemove > 0); --invSlot) { + thisItem = items[invSlot]; + if ((items[invSlot] != null) && (thisItem.getTypeId() == item.itemId) && (thisItem.getDurability() == (byte) item.subType)) { + toRemove -= thisItem.getAmount(); + inventory.clear(invSlot); + } + } + + if (toRemove < 0) // removed too many! put some back! + { + inventory.addItem(new ItemStack[]{new ItemStack(item.itemId, -toRemove, (byte) item.subType)}); + } + } + + public ItemClump nameLookup(String item) { + // Given an item name (with optional ",", returns an ItemClump loaded with the id and subtype. + // If name is not found, returns null. + + int itemId = -1; + int itemSubtype = 0; + ItemClump returnedItem = null; + + for (String id : itemsData.keySet()) { + if (((String) itemsData.get(id)).equalsIgnoreCase(item)) { + if (id.contains(",")) { + itemId = Integer.valueOf(id.split(",")[0]).intValue(); + itemSubtype = Integer.valueOf(id.split(",")[1]).intValue(); + } else { + itemId = Integer.valueOf(id).intValue(); + itemSubtype = 0; + } + returnedItem = new ItemClump(itemId, itemSubtype); + break; + } + } + + if (returnedItem != null) { + return returnedItem; + } + + // No exact match found: Try partial-name matching. + String itemLower = item.toLowerCase(); + for (String id : itemsData.keySet()) { + if (((String) itemsData.get(id)).toLowerCase().contains(itemLower)) { + if (id.contains(",")) { + itemId = Integer.valueOf(id.split(",")[0]).intValue(); + itemSubtype = Integer.valueOf(id.split(",")[1]).intValue(); + } else { + itemId = Integer.valueOf(id).intValue(); + itemSubtype = 0; + } + returnedItem = new ItemClump(itemId, itemSubtype); + break; + } + } + + return returnedItem; + } + + public static boolean validateType(int id, int type) { + if (type == 0) { + return true; + } + if (type < 0) { + return false; + } + + switch (id) { + case 35: + case 63: + case 351: + return (type <= 15); + case 17: + return (type <= 2); + case 53: + case 64: + case 67: + case 71: + case 77: + case 86: + case 91: + return (type <= 3); + case 66: + return (type <= 9); + case 68: + return ((type >= 2) && (type <= 5)); + default: + return false; + } + } + + public static boolean checkID(int id) // ? Confirms that the given id is known by bukkit as an item id. + { + for (Material item : Material.values()) { + if (item.getId() == id) { + return true; + } + } + + return false; + } +} diff --git a/src/com/gmail/haloinverse/DynamicMarket/MarketItem.java b/src/com/gmail/haloinverse/DynamicMarket/MarketItem.java index 3186748..f8da8f3 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/MarketItem.java +++ b/src/com/gmail/haloinverse/DynamicMarket/MarketItem.java @@ -1,944 +1,891 @@ package com.gmail.haloinverse.DynamicMarket; -import com.nijikokun.bukkit.iConomy.iConomy; import java.lang.Math; import java.util.ArrayList; //import java.sql.ResultSet; public class MarketItem extends ItemClump { - private String name; //n | name // name used for item - public int basePrice; //bp // base purchase price of item - public int stock; //s // current stock level of item - public boolean canBuy; //cb // true if can be purchased, false if not - public boolean canSell; //cs // true if can be sold, false if not - private int volatility; //v // % change in price per 1 stock bought/sold, * intScale - //iv // inverse volatility; units bought/sold per doubling/halving of price - public int salesTax; //st // basePrice * (1 - (salesTax/100)) = selling price - public int stockLowest; //sl // minimum stock at which purchases will fail (hard limit) - public int stockHighest; //sh // maximum stock at which sales will fail (hard limit) - public int stockFloor; //sf // minimum stock level possible (soft limit) - public int stockCeil; //sc // maximum stock level possible (soft limit) - public int priceFloor; //pf // minimum price <- applies to basePrice, without salesTax - public int priceCeil; //pc // maximum price - public int jitterPerc; - public int driftOut; - public int driftIn; - public int avgStock; - public int itemClass; - public String shopLabel = ""; // Shop DB table this is a member of. - // Other input tags: - //fixed // stock = 0 - // stockLowest = Integer.MIN_VALUE - // stockHighest = Integer.MAX_VALUE - // stockFloor = 0 - // stockCeil = 0 - // buyok // canBuy = 1 - // sellok // canSell = 1 - // !nobuy // canBuy = 1 - // !nosell // canSell = 1 - // !buyok // canBuy = 0 - // !sellok // canSell = 0 - // nobuy // canBuy = 0 - // nosell // canSell = 0 - public static int intScale = 10000; // Scale factor used in integerization of calculations. - public DatabaseMarket thisDatabase = null; // Database object this item is a member of. - - /* diamond: 10 items -> 10% price change, 1 item -> 1% price change, 0.01 * 10000 = 1000 - * - * cobble: 640 items -> 10% price change, 1 item -> 0.016% price change, 0.00016 * 10000 = 16 - * - * ?inelastic?: v=1 -> 0.001% price change, 1000 items -> 1% price change - * - * ?elastic?: v=10000, 1 item -> +100% | -50% price change - * - * volatility: % change in price per unit bought/sold, * intScale / 100 (2% per item = 2 * intScale / 100) - * inverse volatility: units bought/sold per doubling/halving of price - * - * ivol = ln(2) / ln(1+(vol/intScale)) - * vol = (2^(1/iVol)-1) * intScale - * - */ - - public MarketItem(String thisShopLabel) - { - // Default constructor with no parameters. - super(); - setBaseDefaults(); - shopLabel = thisShopLabel; - } - - public MarketItem() - { - // Default constructor with no parameters. - super(); - setBaseDefaults(); - } - - public MarketItem(String initString, MarketItem defaults, DatabaseMarket thisDB, String thisShopLabel) - { - //Valid input string formats: - //"[ID(,Type)](:Count) (buyprice (sellPrice)) (field:val (field:val (...)))" - //"[ItemName](:Count) (buyprice (sellPrice)) (field:val (field:val (...)))" - //TODO: Add alternate input format for setting low/high ranges with a single tag. - - super(initString.split(" ",2)[0], thisDB, thisShopLabel); // Parse id/name, type, and count from first split. - - thisDatabase = thisDB; - shopLabel = thisShopLabel; - - //SimpleMarket.log.info("[1] InitString: [" + initString + "]"); - - String[] initData = initString.split(" "); - - // If 0th tag (name) does not contain ":", use count from defaults. - if(!initData[0].contains(":")) - this.count = defaults.count; - - // Load defaults, if available. - if (defaults != null) - { - this.basePrice = Math.round((float)defaults.basePrice * this.count / defaults.count); - this.stock = Math.round(((float)defaults.stock * defaults.count / this.count) - 0.5f); - this.canBuy = defaults.canBuy; - this.canSell = defaults.canSell; - this.volatility = defaults.volatility; - this.salesTax = defaults.salesTax; - this.stockLowest = defaults.stockLowest; - this.stockHighest = defaults.stockHighest; - this.stockFloor = defaults.stockFloor; - this.stockCeil = defaults.stockCeil; - this.priceFloor = defaults.priceFloor; - this.priceCeil = defaults.priceCeil; - } - else - { - setBaseDefaults(); - } - - //Load data from remaining items in split. - //If first one or two items have no tag, assume they are the basePrice and the sellPrice. - - parseTags(initData); - - sanityCheck(); - } - - private void parseTags(String initData[]) - { - // Load data from a list of tags. - // Element [0] is ignored. - String curTag; - Integer curVal; - String stringVal; - String[] curParams; - boolean setUntaggedBase = false; - - if (initData.length > 1) - { - for (int i = 1; i <= initData.length - 1; i++) - { - stringVal = null; - // Get current tag and value - - if (initData[i].contains(":")) - { - curParams = initData[i].split(":"); - curTag = curParams[0]; - try - { - curVal = Integer.parseInt(curParams[1]); - } - catch (NumberFormatException ex) - { - if (curParams[1].equalsIgnoreCase("+INF")) - curVal = Integer.MAX_VALUE; - else if (curParams[1].equalsIgnoreCase("-INF")) - curVal = Integer.MIN_VALUE; - else - { - curVal = null; - stringVal = curParams[1]; - } - } - } - else - { - try - { // Try to parse it as a plain integer. - curTag = null; - curVal = Integer.parseInt(initData[i]); - } - catch (NumberFormatException ex) - { // Didn't work? Just use it as a string. - curVal = null; - curTag = initData[i]; - } - } - - // If first param is an untagged value, make it the basePrice. - if (i == 1) - { - if (curTag == null) - { - if (curVal != -1) - { - this.basePrice = curVal; - //maskData.basePrice = 1; - } - else - { - // Base price set to -1. Disable buying. - this.basePrice = 0; - //maskData.basePrice = 1; - this.canBuy = false; - } - setUntaggedBase = true; - continue; - } - } - - // If second param is an untagged value, make the sellPrice equal to it after sales tax is applied. - if (i == 2) - { - if ((setUntaggedBase) && (curTag == null)) - { - if (curVal != -1) - { - // if salePrice = basePrice * (1 - (salesTax / 100)) - // then (1 - (salePrice / basePrice)) * 100 = salesTax - if (this.basePrice != 0) - { - this.salesTax = Math.round((1 - ((float)curVal / basePrice)) * 100); - //maskData.salesTax = 1; - } - else - { - this.basePrice = curVal; - this.salesTax = 0; - //maskData.salesTax = 1; - } - } - else - { - // Sale price set to -1. Disable selling. - this.canSell = false; - } - continue; - } - } - - // Handle remaining items in split. - - if (curTag != null) - { - if (curVal != null) - { - if (curTag.equalsIgnoreCase("bp") || curTag.equalsIgnoreCase("baseprice")) - { - this.basePrice = curVal; - continue; - } - if (curTag.equalsIgnoreCase("s") || curTag.equalsIgnoreCase("stock")) - { - this.stock = curVal; - continue; - } - if (curTag.equalsIgnoreCase("v") || curTag.equalsIgnoreCase("volatility") || curTag.equalsIgnoreCase("vol")) - { - this.setVolatility(curVal); - continue; - } - if (curTag.equalsIgnoreCase("iv") || curTag.equalsIgnoreCase("invvolatility") || curTag.equalsIgnoreCase("ivol")) - { - this.setInverseVolatility(curVal); - continue; - } - if (curTag.equalsIgnoreCase("st") || curTag.equalsIgnoreCase("salestax")) - { - this.salesTax = rangeCrop(curVal, 0, 100); - continue; - } - if (curTag.equalsIgnoreCase("sl") || curTag.equalsIgnoreCase("stocklowest")) - { - this.stockLowest = curVal; - continue; - } - if (curTag.equalsIgnoreCase("sh") || curTag.equalsIgnoreCase("stockhighest")) - { - this.stockHighest = curVal; - continue; - } - if (curTag.equalsIgnoreCase("sf") || curTag.equalsIgnoreCase("stockfloor")) - { - this.stockFloor = curVal; - continue; - } - if (curTag.equalsIgnoreCase("sc") || curTag.equalsIgnoreCase("stockceiling")) - { - this.stockCeil = curVal; - continue; - } - if (curTag.equalsIgnoreCase("pf") || curTag.equalsIgnoreCase("pricefloor")) - { - this.priceFloor = curVal; - continue; - } - if (curTag.equalsIgnoreCase("pc") || curTag.equalsIgnoreCase("priceceiling")) - { - this.priceCeil = curVal; - continue; - } - } - } - if (curTag.equalsIgnoreCase("flat")) - { - this.stock = 0; - this.stockLowest = Integer.MIN_VALUE; - this.stockHighest = Integer.MAX_VALUE; - this.stockFloor = Integer.MIN_VALUE; - this.stockCeil = Integer.MAX_VALUE; - this.priceFloor = 0; - this.priceCeil = Integer.MAX_VALUE; - this.volatility = 0; - continue; - } - if (curTag.equalsIgnoreCase("fixed")) - { - this.stock = 0; - this.stockLowest = Integer.MIN_VALUE; - this.stockHighest = Integer.MAX_VALUE; - this.stockFloor = 0; - this.stockCeil = 0; - this.priceFloor = 0; - this.priceCeil = Integer.MAX_VALUE; - this.volatility = 0; - continue; - } - if (curTag.equalsIgnoreCase("float")) - { - this.stockFloor = Integer.MIN_VALUE; - this.stockCeil = Integer.MAX_VALUE; - this.stockLowest = Integer.MIN_VALUE; - this.stockHighest = Integer.MAX_VALUE; - this.priceFloor = 0; - this.priceCeil = Integer.MAX_VALUE; - if (this.volatility == 0) - this.volatility = 100; - } - if (curTag.equalsIgnoreCase("finite")) - { - this.stockFloor = Integer.MIN_VALUE; - this.stockCeil = Integer.MAX_VALUE; - this.stockLowest = 0; - this.stockHighest = Integer.MAX_VALUE; - } - if ((curTag.equalsIgnoreCase("buyok")) || (curTag.equalsIgnoreCase("!nobuy"))) - { - this.canBuy = true; - continue; - } - if ((curTag.equalsIgnoreCase("sellok")) || (curTag.equalsIgnoreCase("!nosell"))) - { - this.canSell = true; - continue; - } - if ((curTag.equalsIgnoreCase("!buyok")) || (curTag.equalsIgnoreCase("nobuy")) || (curTag.equalsIgnoreCase("!cb"))) - { - this.canBuy = false; - continue; - } - if ((curTag.equalsIgnoreCase("!sellok")) || (curTag.equalsIgnoreCase("nosell")) || (curTag.equalsIgnoreCase("!cs"))) - { - this.canSell = false; - continue; - } - if (curTag.equalsIgnoreCase("cb") || curTag.equalsIgnoreCase("canbuy")) - { - if ((stringVal != null) && (!(stringVal.isEmpty()))) - { - this.canBuy = ((stringVal.toLowerCase().startsWith("y")) || (stringVal.toLowerCase().startsWith("t"))); - } - else - this.canBuy = true; - continue; - } - if (curTag.equalsIgnoreCase("cs") || curTag.equalsIgnoreCase("cansell")) - { - if ((stringVal != null) && (!(stringVal.isEmpty()))) - { - this.canSell = ((stringVal.toLowerCase().startsWith("y")) || (stringVal.toLowerCase().startsWith("t"))); - } - else - this.canSell = true; - continue; - } - if ((curTag.equalsIgnoreCase("name")) || (curTag.equalsIgnoreCase("n"))) - { - setName(stringVal); - continue; - } - if (curTag.equalsIgnoreCase("renorm")) - { - //double oldBuyPrice = getStockPrice(this.stock); - int newStock; - if (curVal == null) - newStock = 0; - else - newStock = curVal; - this.basePrice = getRenormedPrice(newStock); - this.stock = newStock; - // basePrice = inverse of stockPrice = rangeCrop(this.basePrice * Math.pow(getVolFactor(), -rangeCrop(stockLevel, stockFloor, stockCeil)), priceFloor, priceCeil) + private String name; //n | name // name used for item + public int basePrice; //bp // base purchase price of item + public int stock; //s // current stock level of item + public boolean canBuy; //cb // true if can be purchased, false if not + public boolean canSell; //cs // true if can be sold, false if not + private int volatility; //v // % change in price per 1 stock bought/sold, * intScale + //iv // inverse volatility; units bought/sold per doubling/halving of price + public int salesTax; //st // basePrice * (1 - (salesTax/100)) = selling price + public int stockLowest; //sl // minimum stock at which purchases will fail (hard limit) + public int stockHighest; //sh // maximum stock at which sales will fail (hard limit) + public int stockFloor; //sf // minimum stock level possible (soft limit) + public int stockCeil; //sc // maximum stock level possible (soft limit) + public int priceFloor; //pf // minimum price <- applies to basePrice, without salesTax + public int priceCeil; //pc // maximum price + public int jitterPerc; + public int driftOut; + public int driftIn; + public int avgStock; + public int itemClass; + public String shopLabel = ""; // Shop DB table this is a member of. + // Other input tags: + //fixed // stock = 0 + // stockLowest = Integer.MIN_VALUE + // stockHighest = Integer.MAX_VALUE + // stockFloor = 0 + // stockCeil = 0 + // buyok // canBuy = 1 + // sellok // canSell = 1 + // !nobuy // canBuy = 1 + // !nosell // canSell = 1 + // !buyok // canBuy = 0 + // !sellok // canSell = 0 + // nobuy // canBuy = 0 + // nosell // canSell = 0 + public static int intScale = 10000; // Scale factor used in integerization of calculations. + public DatabaseMarket thisDatabase = null; // Database object this item is a member of. + + /* diamond: 10 items -> 10% price change, 1 item -> 1% price change, 0.01 * 10000 = 1000 + * + * cobble: 640 items -> 10% price change, 1 item -> 0.016% price change, 0.00016 * 10000 = 16 + * + * ?inelastic?: v=1 -> 0.001% price change, 1000 items -> 1% price change + * + * ?elastic?: v=10000, 1 item -> +100% | -50% price change + * + * volatility: % change in price per unit bought/sold, * intScale / 100 (2% per item = 2 * intScale / 100) + * inverse volatility: units bought/sold per doubling/halving of price + * + * ivol = ln(2) / ln(1+(vol/intScale)) + * vol = (2^(1/iVol)-1) * intScale + * + */ + public MarketItem(String thisShopLabel) { + // Default constructor with no parameters. + super(); + setBaseDefaults(); + shopLabel = thisShopLabel; + } + + public MarketItem() { + // Default constructor with no parameters. + super(); + setBaseDefaults(); + } + + public MarketItem(String initString, MarketItem defaults, DatabaseMarket thisDB, String thisShopLabel) { + //Valid input string formats: + //"[ID(,Type)](:Count) (buyprice (sellPrice)) (field:val (field:val (...)))" + //"[ItemName](:Count) (buyprice (sellPrice)) (field:val (field:val (...)))" + //TODO: Add alternate input format for setting low/high ranges with a single tag. + + super(initString.split(" ", 2)[0], thisDB, thisShopLabel); // Parse id/name, type, and count from first split. + + thisDatabase = thisDB; + shopLabel = thisShopLabel; + + //SimpleMarket.log.info("[1] InitString: [" + initString + "]"); + + String[] initData = initString.split(" "); + + // If 0th tag (name) does not contain ":", use count from defaults. + if (!initData[0].contains(":")) { + this.count = defaults.count; + } + + // Load defaults, if available. + if (defaults != null) { + this.basePrice = Math.round((float) defaults.basePrice * this.count / defaults.count); + this.stock = Math.round(((float) defaults.stock * defaults.count / this.count) - 0.5f); + this.canBuy = defaults.canBuy; + this.canSell = defaults.canSell; + this.volatility = defaults.volatility; + this.salesTax = defaults.salesTax; + this.stockLowest = defaults.stockLowest; + this.stockHighest = defaults.stockHighest; + this.stockFloor = defaults.stockFloor; + this.stockCeil = defaults.stockCeil; + this.priceFloor = defaults.priceFloor; + this.priceCeil = defaults.priceCeil; + } else { + setBaseDefaults(); + } + + //Load data from remaining items in split. + //If first one or two items have no tag, assume they are the basePrice and the sellPrice. + + parseTags(initData); + + sanityCheck(); + } + + private void parseTags(String initData[]) { + // Load data from a list of tags. + // Element [0] is ignored. + String curTag; + Integer curVal; + String stringVal; + String[] curParams; + boolean setUntaggedBase = false; + + if (initData.length > 1) { + for (int i = 1; i <= initData.length - 1; i++) { + stringVal = null; + // Get current tag and value + + if (initData[i].contains(":")) { + curParams = initData[i].split(":"); + curTag = curParams[0]; + try { + curVal = Integer.parseInt(curParams[1]); + } catch (NumberFormatException ex) { + if (curParams[1].equalsIgnoreCase("+INF")) { + curVal = Integer.MAX_VALUE; + } else if (curParams[1].equalsIgnoreCase("-INF")) { + curVal = Integer.MIN_VALUE; + } else { + curVal = null; + stringVal = curParams[1]; + } + } + } else { + try { // Try to parse it as a plain integer. + curTag = null; + curVal = Integer.parseInt(initData[i]); + } catch (NumberFormatException ex) { // Didn't work? Just use it as a string. + curVal = null; + curTag = initData[i]; + } + } + + // If first param is an untagged value, make it the basePrice. + if (i == 1) { + if (curTag == null) { + if (curVal != -1) { + this.basePrice = curVal; + //maskData.basePrice = 1; + } else { + // Base price set to -1. Disable buying. + this.basePrice = 0; + //maskData.basePrice = 1; + this.canBuy = false; + } + setUntaggedBase = true; + continue; + } + } + + // If second param is an untagged value, make the sellPrice equal to it after sales tax is applied. + if (i == 2) { + if ((setUntaggedBase) && (curTag == null)) { + if (curVal != -1) { + // if salePrice = basePrice * (1 - (salesTax / 100)) + // then (1 - (salePrice / basePrice)) * 100 = salesTax + if (this.basePrice != 0) { + this.salesTax = Math.round((1 - ((float) curVal / basePrice)) * 100); + //maskData.salesTax = 1; + } else { + this.basePrice = curVal; + this.salesTax = 0; + //maskData.salesTax = 1; + } + } else { + // Sale price set to -1. Disable selling. + this.canSell = false; + } + continue; + } + } + + // Handle remaining items in split. + + if (curTag != null) { + if (curVal != null) { + if (curTag.equalsIgnoreCase("bp") || curTag.equalsIgnoreCase("baseprice")) { + this.basePrice = curVal; + continue; + } + if (curTag.equalsIgnoreCase("s") || curTag.equalsIgnoreCase("stock")) { + this.stock = curVal; + continue; + } + if (curTag.equalsIgnoreCase("v") || curTag.equalsIgnoreCase("volatility") || curTag.equalsIgnoreCase("vol")) { + this.setVolatility(curVal); + continue; + } + if (curTag.equalsIgnoreCase("iv") || curTag.equalsIgnoreCase("invvolatility") || curTag.equalsIgnoreCase("ivol")) { + this.setInverseVolatility(curVal); + continue; + } + if (curTag.equalsIgnoreCase("st") || curTag.equalsIgnoreCase("salestax")) { + this.salesTax = rangeCrop(curVal, 0, 100); + continue; + } + if (curTag.equalsIgnoreCase("sl") || curTag.equalsIgnoreCase("stocklowest")) { + this.stockLowest = curVal; + continue; + } + if (curTag.equalsIgnoreCase("sh") || curTag.equalsIgnoreCase("stockhighest")) { + this.stockHighest = curVal; + continue; + } + if (curTag.equalsIgnoreCase("sf") || curTag.equalsIgnoreCase("stockfloor")) { + this.stockFloor = curVal; + continue; + } + if (curTag.equalsIgnoreCase("sc") || curTag.equalsIgnoreCase("stockceiling")) { + this.stockCeil = curVal; + continue; + } + if (curTag.equalsIgnoreCase("pf") || curTag.equalsIgnoreCase("pricefloor")) { + this.priceFloor = curVal; + continue; + } + if (curTag.equalsIgnoreCase("pc") || curTag.equalsIgnoreCase("priceceiling")) { + this.priceCeil = curVal; + continue; + } + } + } + if (curTag.equalsIgnoreCase("flat")) { + this.stock = 0; + this.stockLowest = Integer.MIN_VALUE; + this.stockHighest = Integer.MAX_VALUE; + this.stockFloor = Integer.MIN_VALUE; + this.stockCeil = Integer.MAX_VALUE; + this.priceFloor = 0; + this.priceCeil = Integer.MAX_VALUE; + this.volatility = 0; + continue; + } + if (curTag.equalsIgnoreCase("fixed")) { + this.stock = 0; + this.stockLowest = Integer.MIN_VALUE; + this.stockHighest = Integer.MAX_VALUE; + this.stockFloor = 0; + this.stockCeil = 0; + this.priceFloor = 0; + this.priceCeil = Integer.MAX_VALUE; + this.volatility = 0; + continue; + } + if (curTag.equalsIgnoreCase("float")) { + this.stockFloor = Integer.MIN_VALUE; + this.stockCeil = Integer.MAX_VALUE; + this.stockLowest = Integer.MIN_VALUE; + this.stockHighest = Integer.MAX_VALUE; + this.priceFloor = 0; + this.priceCeil = Integer.MAX_VALUE; + if (this.volatility == 0) { + this.volatility = 100; + } + } + if (curTag.equalsIgnoreCase("finite")) { + this.stockFloor = Integer.MIN_VALUE; + this.stockCeil = Integer.MAX_VALUE; + this.stockLowest = 0; + this.stockHighest = Integer.MAX_VALUE; + } + if ((curTag.equalsIgnoreCase("buyok")) || (curTag.equalsIgnoreCase("!nobuy"))) { + this.canBuy = true; + continue; + } + if ((curTag.equalsIgnoreCase("sellok")) || (curTag.equalsIgnoreCase("!nosell"))) { + this.canSell = true; + continue; + } + if ((curTag.equalsIgnoreCase("!buyok")) || (curTag.equalsIgnoreCase("nobuy")) || (curTag.equalsIgnoreCase("!cb"))) { + this.canBuy = false; + continue; + } + if ((curTag.equalsIgnoreCase("!sellok")) || (curTag.equalsIgnoreCase("nosell")) || (curTag.equalsIgnoreCase("!cs"))) { + this.canSell = false; + continue; + } + if (curTag.equalsIgnoreCase("cb") || curTag.equalsIgnoreCase("canbuy")) { + if ((stringVal != null) && (!(stringVal.isEmpty()))) { + this.canBuy = ((stringVal.toLowerCase().startsWith("y")) || (stringVal.toLowerCase().startsWith("t"))); + } else { + this.canBuy = true; + } + continue; + } + if (curTag.equalsIgnoreCase("cs") || curTag.equalsIgnoreCase("cansell")) { + if ((stringVal != null) && (!(stringVal.isEmpty()))) { + this.canSell = ((stringVal.toLowerCase().startsWith("y")) || (stringVal.toLowerCase().startsWith("t"))); + } else { + this.canSell = true; + } + continue; + } + if ((curTag.equalsIgnoreCase("name")) || (curTag.equalsIgnoreCase("n"))) { + setName(stringVal); + continue; + } + if (curTag.equalsIgnoreCase("renorm")) { + //double oldBuyPrice = getStockPrice(this.stock); + int newStock; + if (curVal == null) { + newStock = 0; + } else { + newStock = curVal; + } + this.basePrice = getRenormedPrice(newStock); + this.stock = newStock; + // basePrice = inverse of stockPrice = rangeCrop(this.basePrice * Math.pow(getVolFactor(), -rangeCrop(stockLevel, stockFloor, stockCeil)), priceFloor, priceCeil) /* - * oldstockPrice = this.basePrice * (getVolFactor() ^ -stockLevel) - * oldstockPrice / (getVolFactor() ^ -stockLevel) = basePrice - */ - //this.basePrice = (int)Math.round(oldBuyPrice / Math.pow(getVolFactor(), -rangeCrop(this.stock, stockFloor, stockCeil))); - } - } - //TODO: Log and report invalid tags somehow. - } - } - - public int getRenormedPrice(int newStock) - { - // Calculate what the renormalized base price would be when shifting from the current stock level to newStock. - double oldBuyPrice = getStockPrice(this.stock); - return (int)Math.round(oldBuyPrice / Math.pow(getVolFactor(), -rangeCrop(newStock, stockFloor, stockCeil))); - } - - public MarketItem(SQLHandler myQuery) - { - // Initialize a new MarketItem from an SQLHandler ResultSet. - super(); - //thisDatabase.plugin.log.info("Creating from SQL..."); - this.itemId = myQuery.getInt("item"); - this.subType = myQuery.getInt("subtype"); - this.name = myQuery.getString("name"); - this.count = myQuery.getInt("count"); - this.basePrice = myQuery.getInt("baseprice"); - this.canBuy = (myQuery.getInt("canbuy") == 1); - this.canSell = (myQuery.getInt("cansell") == 1); - this.stock = myQuery.getInt("stock"); - this.volatility = myQuery.getInt("volatility"); - this.salesTax = myQuery.getInt("salestax"); - this.stockHighest = myQuery.getInt("stockhighest"); - this.stockLowest = myQuery.getInt("stocklowest"); - this.stockFloor = myQuery.getInt("stockfloor"); - this.stockCeil = myQuery.getInt("stockceil"); - this.priceFloor = myQuery.getInt("pricefloor"); - this.priceCeil = myQuery.getInt("priceceil"); - this.shopLabel = myQuery.getString("shoplabel"); - sanityCheck(); - } - - private void sanityCheck() - { - // Check and fix possible chaos-inducing data. - // Mirrors DatabaseMarket.sanityCheckAll. - - this.salesTax = rangeCrop(this.salesTax, 0, 100); - - if (this.stockHighest < this.stock) - this.stockHighest = this.stock; - - if (this.stockLowest > this.stock) - this.stockLowest = this.stock; - - if (this.stockCeil < this.stock) - this.stockCeil = this.stock; - - if (this.stockFloor > this.stock) - this.stockFloor = this.stock; - - if (this.priceCeil < this.priceFloor) - this.priceCeil = this.priceFloor; - - this.basePrice = Math.max(0, this.basePrice); - } - - private void setBaseDefaults() - { - name = null; - basePrice = 0; - stock = 0; - canBuy = true; - canSell = true; - volatility = 1; - salesTax = 0; - stockLowest = Integer.MIN_VALUE; - stockHighest = Integer.MAX_VALUE; - stockFloor = 0; - stockCeil = 0; - priceFloor = 0; - priceCeil = Integer.MAX_VALUE; - } - - //public int sellPrice() - //{ - // return (rangeCrop(Math.round(basePrice * (1 - (salesTax / 100))), priceFloor, priceCeil)); - //} - - public static int rangeCrop(int value, int minVal, int maxVal) - { - return (Math.min(Math.max(value, minVal), maxVal)); - } - - public static double rangeCrop(double value, double minVal, double maxVal) - { - return (Math.min(Math.max(value, minVal), maxVal)); - } - - public String getName() - { - if ((this.name == null) || (this.name.isEmpty())) - this.name = super.getName(thisDatabase, shopLabel); - return this.name; - } - - public void setName(String newName) - { - if ((newName != null) && (!(newName.isEmpty()))) - { - this.name = newName; - } - else - { - this.name = super.getName(thisDatabase, shopLabel); - } - } - - public double getBatchPrice(int startStock, int endStock) - { - // Gets the current base price for the items at stock levels from startStock to endStock. - // NOTE: Does not check stockLowest/stockHighest transaction limits. - - int lowStock = Math.min(startStock, endStock); - int highStock = Math.max(startStock, endStock); - int numTerms = highStock - lowStock + 1; - double lowStockPrice; - double highStockPrice; - int fixedStockLimit; - - // End calculation if volatility == 0. Price does not change, so all items are the same value. - if (volatility == 0) - return (numTerms * getStockPrice(stock)); - - // End calculation if highStock <= stockFloor (All below floor) - if (highStock <= stockFloor) - return (numTerms * getStockPrice(stockFloor)); - - // End calculation if lowStock >= stockCeil (All above ceiling) - if (lowStock >= stockCeil) - return (numTerms * getStockPrice(stockCeil)); - - // Split calculation if stockFloor reached by lowStock (Some below floor) - if (lowStock < stockFloor) - return (((stockFloor-lowStock)*getStockPrice(stockFloor)) + getBatchPrice(stockFloor, highStock)); - - // Split calculation if stockCeil reached by highStock (Some above ceiling) - if (highStock > stockCeil) - return (((highStock-stockCeil)*getStockPrice(stockCeil)) + getBatchPrice(lowStock, stockCeil)); - - lowStockPrice = getStockPrice(lowStock); // highest price in range - highStockPrice = getStockPrice(highStock); // lowest price in range - - // WARNING in this section: Highest stock level corresponds to lowest price, - // and lowest stock level corresponds to highest price. - - // End calculation if lowStockPrice <= priceFloor (All below floor) - if (lowStockPrice <= priceFloor) - return (numTerms * priceFloor); - - // End calculation if highStockPrice >= priceCeil (All above ceiling) - if (highStockPrice >= priceCeil) - return (numTerms * priceCeil); - - // Split calculation if highStockPrice < priceFloor (Some below floor) - if (highStockPrice < priceFloor) - { - fixedStockLimit = (int)Math.round(Math.floor(stockAtPrice(priceFloor))); - return (((highStock - fixedStockLimit) * priceFloor) + getBatchPrice(lowStock, fixedStockLimit)); - } - - // Split calculation if lowStockPrice > priceCeil (Some above ceiling) - if (lowStockPrice > priceCeil) - { - fixedStockLimit = (int)Math.round(Math.ceil(stockAtPrice(priceCeil))); - return (((fixedStockLimit - lowStock) * priceCeil) + getBatchPrice(fixedStockLimit, highStock)); - } - - - // All range limits handled? Find the sum of terms of a finite geometric series. - //return Math.round(this.basePrice * Math.pow(getVolFactor(),-lowStock) * (Math.pow(getVolFactor(),numTerms) - 1) / (getVolFactor()-1)); - //return math.round(firstTerm * (1 - (ratio ^ terms)) / (1 - ratio)); - return Math.round(lowStockPrice * (1 - (Math.pow(1/getVolFactor(), numTerms))) / (1 - (1/getVolFactor()))); - } - - public int getBuyPrice(int numBundles) - { - // Return the purchase price of the given number of bundles. - getBatchPrice(stock, stock + numBundles - 1); - return (int)Math.round(Math.ceil(getBatchPrice(stock, stock - numBundles + 1))); - } - - public int getSellPrice(int numBundles) - { - // Return the selling price of the given number of bundles. - return (int)Math.round(Math.floor(deductTax(getBatchPrice(stock + numBundles, stock + 1)))); - } - - private double deductTax(double basePrice) - { - // Returns the given price minus the sales tax. - return (basePrice * (1 - ((double)salesTax/100))); - } - - private double getStockPrice(int stockLevel) - { - // Crops result to stockFloor/stockCeil/priceFloor/priceCeil. - return rangeCrop(this.basePrice * Math.pow(getVolFactor(), -rangeCrop(stockLevel, stockFloor, stockCeil)), priceFloor, priceCeil); - } - - public int getVolatility() - { - return this.volatility; - } - - public double getVolFactor() - { - return (1 + (double)volatility/intScale); - } - - public void setVolatility(int newVol) - { - this.volatility = rangeCrop(newVol, 0, intScale); - } - - public void setVolatility(double newVol) - { - setVolatility((int)Math.round(newVol)); - } - - public int getInverseVolatility() - { - if(volatility == 0) - return Integer.MAX_VALUE; - else - return (int)Math.round(Math.log(2) / Math.log(getVolFactor())); - } - - public void setInverseVolatility(int newIVol) - { - //if (newIVol == Integer.MAX_VALUE) - // setVolatility(0); - //else - // setVolatility((Math.pow(2,(1/(double)newIVol))-1) * intScale); - setVolatility(iVolToVol(newIVol)); - } - - public static int iVolToVol(int invVol) - { - // Converts inverse volatility to volatility. - if (invVol == Integer.MAX_VALUE) - return 0; - else - return (int)Math.round((Math.pow(2,(1/(double)invVol))-1) * intScale); - } - - private double stockAtPrice(int targPrice) - { - // Returns the stock level at which price == targPrice. - if (volatility == 0) - { - // If price doesn't change, the stock level is effectively +/-INF. - if (targPrice > basePrice) - return Integer.MIN_VALUE; - if (targPrice < basePrice) - return Integer.MAX_VALUE; - // targPrice == basePrice - return stock; - } - return -(Math.log((double)targPrice/basePrice) / Math.log(getVolFactor())); - } - - public String formatBundleCount(int numBundles) - { - if (numBundles == 1) - return (Integer.toString(count)); - if (count == 1) - return (Integer.toString(numBundles)); - return (Integer.toString(count) + "x" + Integer.toString(numBundles)); - } - - public String infoStringBuy(int numBundles) - { - if (!isValid()) - return ("{ERR}Invalid or uninitialized item."); - if (!canBuy) - return ("{PRM}"+getName() + "{ERR} is unavailable for purchase."); - if (!getCanBuy(1)) - return ("{PRM}"+getName() + "{ERR} is out of stock: no more can be bought right now."); - if (!getCanBuy(numBundles)) - return ("{PRM}"+getName() + "{ERR} has only {PRM}" + formatBundleCount(leftToBuy()) + " {ERR}left for sale."); - // Display count as [(x)] - return ("{}Buy: {BKT}[{PRM}" + formatBundleCount(numBundles) + "{BKT}]{} for {PRM}" + getBuyPrice(numBundles) + " " + iConomy.currency); - //TODO: Abstract currency name from iConomy reference. - } - - public String infoStringSell(int numBundles) - { - if (!isValid()) - return ("{ERR}Invalid or uninitialized item."); - if (!canSell) - return ("{PRM}"+getName() + "{ERR} is unavailable for purchase."); - if (!getCanSell(1)) - return ("{PRM}"+getName() + "{ERR} is overstocked: no more can be sold right now."); - if (!getCanSell(numBundles)) - return ("{PRM}"+getName() + "{ERR} is overstocked, only {PRM}" + formatBundleCount(leftToSell()) + " {ERR}can be sold."); - // Display count as [(x)] - return ("{}Sell: {BKT}[{PRM}" + formatBundleCount(numBundles) + "{BKT}]{} for {PRM}" + getSellPrice(numBundles) + " " + iConomy.currency); - //TODO: Abstract currency name from iConomy reference. - } - - public int leftToBuy() - { - return (stock - stockLowest); - } - - public int leftToSell() - { - return (stockHighest - stock); - } - - public String infoStringBuy() - { - return infoStringBuy(1); - } - - public String infoStringSell() - { - return infoStringSell(1); - } - - public boolean getCanBuy(int numBundles) - { - // Report if the requested number of bundles can be bought. - if (canBuy == false) - return false; - if ((stock - numBundles) < stockLowest) - return false; - return true; - } - - public boolean getCanSell(int numBundles) - { - // Report if the requested number of bundles can be sold. - if (canSell == false) - return false; - if ((stock + numBundles) > stockHighest) - return false; - return true; - } - - public String infoStringShort() - { - return("{BKT}[{}" + itemId + (subType != 0? ","+subType : "") + "{BKT}]{} " + getName() + "{BKT}[{}" + count + "{BKT}]{} Buy:{BKT}[{}" + (getCanBuy(1)? getBuyPrice(1) : "-") + "{BKT}]{} Sell:{BKT}[{}" + (getCanSell(1)? getSellPrice(1) : "-") + "{BKT}]"); - } - - public ArrayList infoStringFull() - { - // More detailed info, more useful to shop admins. - // Switch to select line number? - ArrayList returnList = new ArrayList(); - returnList.add("{}ID:{BKT}[{PRM}" + itemId + (subType != 0? ","+subType : "") + "{BKT}]{} Name:{PRM}" + getName() + "{} BundleSize:{BKT}[{PRM}" + count + "{BKT}]"); - returnList.add("{}BasePrice:{BKT}[{PRM}" + basePrice + "{BKT}]{} SalesTax:{BKT}[{PRM}" + salesTax + "{BKT}]{} Vol:{BKT}[{PRM}" + volatility + "{BKT}]{} IVol:{BKT}[{PRM}" + getInverseVolatility() + "{BKT}]"); - returnList.add("{}Stock:{BKT}[{PRM}" + stock + "{BKT}]{} CanBuy:{BKT}[{PRM}" + (getCanBuy(1)? getBuyPrice(1) : "-") + "{BKT}]{} CanSell:{BKT}[{PRM}" + (getCanSell(1)? getSellPrice(1) : "-") + "{BKT}]"); - returnList.add("{}StockLowest:{BKT}[{PRM}" + intFormat(stockLowest) + "{BKT}]{} StockHighest:{BKT}[{PRM}" + intFormat(stockHighest) + "{BKT}]"); - returnList.add("{}StockFloor:{BKT}[{PRM}" + intFormat(stockFloor) + "{BKT}]{} StockCeiling:{BKT}[{PRM}" + intFormat(stockCeil) + "{BKT}]"); - returnList.add("{}PriceFloor:{BKT}[{PRM}" + intFormat(priceFloor) + "{BKT}]{} PriceCeiling:{BKT}[{PRM}" + intFormat(priceCeil) + "{BKT}]"); - return returnList; - - /* - return("&d[&f" + itemId + (subType != 0? ","+subType : "") + "&d]&f " + getName() + "&d[&f" + count + "&d]&f " + - "bp:&d[&f" + basePrice + "&d]&f st:&d[&f" + salesTax + "&d]&f v:&d[&f" + volatility + "&d]&f " + - "iv:&d[&f" + getInverseVolatility() + "&d]&f s:&d[&f" + stock + "&d]&f " + - "cb:&d[&f" + (getCanBuy(1)? getBuyPrice(1) : "-") + "&d]&f cs:&d[&f" + (getCanSell(1)? getSellPrice(1) : "-") + "&d]&f " + - "sl:&d[&f" + intFormat(stockLowest) + "&d]&f sh:&d[&f" + intFormat(stockHighest) + "&d]&f " + - "sf:&d[&f" + intFormat(stockFloor) + "&d]&f sc:&d[&f" + intFormat(stockCeil) + "&d]&f " + - "pf:&d[&f" + intFormat(priceFloor) + "&d]&f pc:&d[&f" + intFormat(priceCeil) + "&d]"); - */ - } - - public String intFormat(int thisInt) - { - // Returns the string value of an int, with Integer.MAX_VALUE and Integer.MIN_VALUE converted to shorthand. - if (thisInt == Integer.MAX_VALUE) - return "+INF"; - if (thisInt == Integer.MIN_VALUE) - return "-INF"; - return Integer.toString(thisInt); - } - - public String csvLine() - { - // Spits out a line corresponding to a line in a .csv file. - return (itemId + "," + subType + "," + count + "," + name + "," + basePrice + "," + stock + "," + (canBuy? "Y" : "N") + "," + (canSell? "Y" : "N") + "," + volatility + "," + salesTax + "," + intFormat(stockLowest) + "," + intFormat(stockHighest) + "," + intFormat(stockFloor) + "," + intFormat(stockCeil) + "," + intFormat(priceFloor) + "," + intFormat(priceCeil) + "," + jitterPerc + "," + driftOut + "," + driftIn + "," + avgStock + "," + itemClass); - } - - public static String csvHeaderLine() - { - // Spits out an appropriate header line for the output spreadsheet. - return ("itemId,subType,count,name,basePrice,stock,canBuy,canSell,volatility,salesTax,stockLowest,stockHighest,stockFloor,stockCeil,priceFloor,priceCeil,jitterPerc,driftOut,driftIn,avgStock,itemClass"); - } - - private int quickParse(String intString) - { - // Parses strings into ints, throwing away errors and replacing them with 0s. - if (intString.equalsIgnoreCase("-inf")) - return Integer.MIN_VALUE; - if (intString.equalsIgnoreCase("+inf")) - return Integer.MAX_VALUE; - try - { - return Integer.parseInt(intString); - } - catch (NumberFormatException ex) - { - return 0; - } - } - - public MarketItem(String csvString, MarketItem defaults, String shopLabel, boolean isCSV) - { - super(); - - if (defaults != null) - { - this.itemId = defaults.itemId; - this.subType = defaults.subType; - this.count = defaults.count; - this.basePrice = defaults.basePrice; - this.stock = defaults.stock; - this.canBuy = defaults.canBuy; - this.canSell = defaults.canSell; - this.volatility = defaults.volatility; - this.salesTax = defaults.salesTax; - this.stockLowest = defaults.stockLowest; - this.stockHighest = defaults.stockHighest; - this.stockFloor = defaults.stockFloor; - this.stockCeil = defaults.stockCeil; - this.priceFloor = defaults.priceFloor; - this.priceCeil = defaults.priceCeil; - this.jitterPerc = defaults.jitterPerc; - this.driftOut = defaults.driftOut; - this.driftIn = defaults.driftIn; - this.avgStock = defaults.avgStock; - this.itemClass = defaults.itemClass; - } - else - setBaseDefaults(); - - String[] inputParams = csvString.split(","); - - if (inputParams.length < 21) - { - return; - } - - if (!inputParams[0].isEmpty()) - itemId = quickParse(inputParams[0]); - if (!inputParams[1].isEmpty()) - subType = quickParse(inputParams[1]); - if (!inputParams[2].isEmpty()) - count = quickParse(inputParams[2]); - if (!inputParams[3].isEmpty()) - name = inputParams[3]; - if (!inputParams[4].isEmpty()) - basePrice = quickParse(inputParams[4]); - if (!inputParams[5].isEmpty()) - stock = quickParse(inputParams[5]); - if (!inputParams[6].isEmpty()) - canBuy = inputParams[6].equalsIgnoreCase("Y"); - if (!inputParams[7].isEmpty()) - canSell = inputParams[7].equalsIgnoreCase("Y"); - if (!inputParams[8].isEmpty()) - volatility = quickParse(inputParams[8]); - if (!inputParams[9].isEmpty()) - salesTax = quickParse(inputParams[9]); - if (!inputParams[10].isEmpty()) - stockLowest = quickParse(inputParams[10]); - if (!inputParams[11].isEmpty()) - stockHighest = quickParse(inputParams[11]); - if (!inputParams[12].isEmpty()) - stockFloor = quickParse(inputParams[12]); - if (!inputParams[13].isEmpty()) - stockCeil = quickParse(inputParams[13]); - if (!inputParams[14].isEmpty()) - priceFloor = quickParse(inputParams[14]); - if (!inputParams[15].isEmpty()) - priceCeil = quickParse(inputParams[15]); - if (!inputParams[16].isEmpty()) - jitterPerc = quickParse(inputParams[16]); - if (!inputParams[17].isEmpty()) - driftOut = quickParse(inputParams[17]); - if (!inputParams[18].isEmpty()) - driftIn = quickParse(inputParams[18]); - if (!inputParams[19].isEmpty()) - avgStock = quickParse(inputParams[19]); - if (!inputParams[20].isEmpty()) - itemClass = quickParse(inputParams[20]); - this.shopLabel = shopLabel; - sanityCheck(); - } - - public void setEmptyMask() - { - // Wipes all fields to prepare this MarketItem to be used as a data mask. - this.name = null; - this.basePrice = 0; - this.stock = 0; - this.canBuy = false; - this.canSell = false; - this.volatility = 0; - this.salesTax = 0; - this.stockLowest = 0; - this.stockHighest = 0; - this.stockFloor = 0; - this.stockCeil = 0; - this.priceFloor = 0; - this.priceCeil = 0; - this.jitterPerc = 0; - this.driftOut = 0; - this.driftIn = 0; - this.avgStock = 0; - this.itemClass = 0; - this.shopLabel = null; - } - - /* - public void copyMasked(MarketItem data, MarketItem mask) - { - // Copies in the fields from data, for only the fields set non-zero/non-null/true in mask. - if (mask.name != null) this.name = data.name; - if (mask.basePrice != 0) this.basePrice = data.basePrice; - if (mask.stock != 0) this.stock = data.stock; - if (mask.canBuy) this.canBuy = data.canBuy; - if (mask.canSell) this.canSell = data.canSell; - if (mask.volatility != 0) this.volatility = data.volatility; - if (mask.salesTax != 0) this.salesTax = data.salesTax; - if (mask.stockLowest != 0) this.stockLowest = data.stockLowest; - if (mask.stockHighest != 0) this.stockHighest = data.stockHighest; - if (mask.stockFloor != 0) this.stockFloor = data.stockFloor; - if (mask.stockCeil != 0) this.stockCeil = data.stockCeil; - if (mask.priceFloor != 0) this.priceFloor = data.priceFloor; - if (mask.priceCeil != 0) this.priceCeil = data.priceCeil; - if (mask.jitterPerc != 0) this.jitterPerc = data.jitterPerc; - if (mask.driftOut != 0) this.driftOut = data.driftOut; - if (mask.driftIn != 0) this.driftIn = data.driftIn; - if (mask.avgStock != 0) this.avgStock = data.avgStock; - if (mask.itemClass != 0) this.itemClass = data.itemClass; - if (mask.shopLabel != null) this.shopLabel = data.shopLabel; - } - */ + * oldstockPrice = this.basePrice * (getVolFactor() ^ -stockLevel) + * oldstockPrice / (getVolFactor() ^ -stockLevel) = basePrice + */ + //this.basePrice = (int)Math.round(oldBuyPrice / Math.pow(getVolFactor(), -rangeCrop(this.stock, stockFloor, stockCeil))); + } + } + //TODO: Log and report invalid tags somehow. + } + } + + public int getRenormedPrice(int newStock) { + // Calculate what the renormalized base price would be when shifting from the current stock level to newStock. + double oldBuyPrice = getStockPrice(this.stock); + return (int) Math.round(oldBuyPrice / Math.pow(getVolFactor(), -rangeCrop(newStock, stockFloor, stockCeil))); + } + + public MarketItem(SQLHandler myQuery) { + // Initialize a new MarketItem from an SQLHandler ResultSet. + super(); + //thisDatabase.plugin.log.info("Creating from SQL..."); + this.itemId = myQuery.getInt("item"); + this.subType = myQuery.getInt("subtype"); + this.name = myQuery.getString("name"); + this.count = myQuery.getInt("count"); + this.basePrice = myQuery.getInt("baseprice"); + this.canBuy = (myQuery.getInt("canbuy") == 1); + this.canSell = (myQuery.getInt("cansell") == 1); + this.stock = myQuery.getInt("stock"); + this.volatility = myQuery.getInt("volatility"); + this.salesTax = myQuery.getInt("salestax"); + this.stockHighest = myQuery.getInt("stockhighest"); + this.stockLowest = myQuery.getInt("stocklowest"); + this.stockFloor = myQuery.getInt("stockfloor"); + this.stockCeil = myQuery.getInt("stockceil"); + this.priceFloor = myQuery.getInt("pricefloor"); + this.priceCeil = myQuery.getInt("priceceil"); + this.shopLabel = myQuery.getString("shoplabel"); + sanityCheck(); + } + + private void sanityCheck() { + // Check and fix possible chaos-inducing data. + // Mirrors DatabaseMarket.sanityCheckAll. + + this.salesTax = rangeCrop(this.salesTax, 0, 100); + + if (this.stockHighest < this.stock) { + this.stockHighest = this.stock; + } + + if (this.stockLowest > this.stock) { + this.stockLowest = this.stock; + } + + if (this.stockCeil < this.stock) { + this.stockCeil = this.stock; + } + + if (this.stockFloor > this.stock) { + this.stockFloor = this.stock; + } + + if (this.priceCeil < this.priceFloor) { + this.priceCeil = this.priceFloor; + } + + this.basePrice = Math.max(0, this.basePrice); + } + + private void setBaseDefaults() { + name = null; + basePrice = 0; + stock = 0; + canBuy = true; + canSell = true; + volatility = 1; + salesTax = 0; + stockLowest = Integer.MIN_VALUE; + stockHighest = Integer.MAX_VALUE; + stockFloor = 0; + stockCeil = 0; + priceFloor = 0; + priceCeil = Integer.MAX_VALUE; + } + + //public int sellPrice() + //{ + // return (rangeCrop(Math.round(basePrice * (1 - (salesTax / 100))), priceFloor, priceCeil)); + //} + public static int rangeCrop(int value, int minVal, int maxVal) { + return (Math.min(Math.max(value, minVal), maxVal)); + } + + public static double rangeCrop(double value, double minVal, double maxVal) { + return (Math.min(Math.max(value, minVal), maxVal)); + } + + public String getName() { + if ((this.name == null) || (this.name.isEmpty())) { + this.name = super.getName(thisDatabase, shopLabel); + } + return this.name; + } + + public void setName(String newName) { + if ((newName != null) && (!(newName.isEmpty()))) { + this.name = newName; + } else { + this.name = super.getName(thisDatabase, shopLabel); + } + } + + public double getBatchPrice(int startStock, int endStock) { + // Gets the current base price for the items at stock levels from startStock to endStock. + // NOTE: Does not check stockLowest/stockHighest transaction limits. + + int lowStock = Math.min(startStock, endStock); + int highStock = Math.max(startStock, endStock); + int numTerms = highStock - lowStock + 1; + double lowStockPrice; + double highStockPrice; + int fixedStockLimit; + + // End calculation if volatility == 0. Price does not change, so all items are the same value. + if (volatility == 0) { + return (numTerms * getStockPrice(stock)); + } + + // End calculation if highStock <= stockFloor (All below floor) + if (highStock <= stockFloor) { + return (numTerms * getStockPrice(stockFloor)); + } + + // End calculation if lowStock >= stockCeil (All above ceiling) + if (lowStock >= stockCeil) { + return (numTerms * getStockPrice(stockCeil)); + } + + // Split calculation if stockFloor reached by lowStock (Some below floor) + if (lowStock < stockFloor) { + return (((stockFloor - lowStock) * getStockPrice(stockFloor)) + getBatchPrice(stockFloor, highStock)); + } + + // Split calculation if stockCeil reached by highStock (Some above ceiling) + if (highStock > stockCeil) { + return (((highStock - stockCeil) * getStockPrice(stockCeil)) + getBatchPrice(lowStock, stockCeil)); + } + + lowStockPrice = getStockPrice(lowStock); // highest price in range + highStockPrice = getStockPrice(highStock); // lowest price in range + + // WARNING in this section: Highest stock level corresponds to lowest price, + // and lowest stock level corresponds to highest price. + + // End calculation if lowStockPrice <= priceFloor (All below floor) + if (lowStockPrice <= priceFloor) { + return (numTerms * priceFloor); + } + + // End calculation if highStockPrice >= priceCeil (All above ceiling) + if (highStockPrice >= priceCeil) { + return (numTerms * priceCeil); + } + + // Split calculation if highStockPrice < priceFloor (Some below floor) + if (highStockPrice < priceFloor) { + fixedStockLimit = (int) Math.round(Math.floor(stockAtPrice(priceFloor))); + return (((highStock - fixedStockLimit) * priceFloor) + getBatchPrice(lowStock, fixedStockLimit)); + } + + // Split calculation if lowStockPrice > priceCeil (Some above ceiling) + if (lowStockPrice > priceCeil) { + fixedStockLimit = (int) Math.round(Math.ceil(stockAtPrice(priceCeil))); + return (((fixedStockLimit - lowStock) * priceCeil) + getBatchPrice(fixedStockLimit, highStock)); + } + + + // All range limits handled? Find the sum of terms of a finite geometric series. + //return Math.round(this.basePrice * Math.pow(getVolFactor(),-lowStock) * (Math.pow(getVolFactor(),numTerms) - 1) / (getVolFactor()-1)); + //return math.round(firstTerm * (1 - (ratio ^ terms)) / (1 - ratio)); + return Math.round(lowStockPrice * (1 - (Math.pow(1 / getVolFactor(), numTerms))) / (1 - (1 / getVolFactor()))); + } + + public int getBuyPrice(int numBundles) { + // Return the purchase price of the given number of bundles. + getBatchPrice(stock, stock + numBundles - 1); + return (int) Math.round(Math.ceil(getBatchPrice(stock, stock - numBundles + 1))); + } + + public int getSellPrice(int numBundles) { + // Return the selling price of the given number of bundles. + return (int) Math.round(Math.floor(deductTax(getBatchPrice(stock + numBundles, stock + 1)))); + } + + private double deductTax(double basePrice) { + // Returns the given price minus the sales tax. + return (basePrice * (1 - ((double) salesTax / 100))); + } + + private double getStockPrice(int stockLevel) { + // Crops result to stockFloor/stockCeil/priceFloor/priceCeil. + return rangeCrop(this.basePrice * Math.pow(getVolFactor(), -rangeCrop(stockLevel, stockFloor, stockCeil)), priceFloor, priceCeil); + } + + public int getVolatility() { + return this.volatility; + } + + public double getVolFactor() { + return (1 + (double) volatility / intScale); + } + + public void setVolatility(int newVol) { + this.volatility = rangeCrop(newVol, 0, intScale); + } + + public void setVolatility(double newVol) { + setVolatility((int) Math.round(newVol)); + } + + public int getInverseVolatility() { + if (volatility == 0) { + return Integer.MAX_VALUE; + } else { + return (int) Math.round(Math.log(2) / Math.log(getVolFactor())); + } + } + + public void setInverseVolatility(int newIVol) { + //if (newIVol == Integer.MAX_VALUE) + // setVolatility(0); + //else + // setVolatility((Math.pow(2,(1/(double)newIVol))-1) * intScale); + setVolatility(iVolToVol(newIVol)); + } + + public static int iVolToVol(int invVol) { + // Converts inverse volatility to volatility. + if (invVol == Integer.MAX_VALUE) { + return 0; + } else { + return (int) Math.round((Math.pow(2, (1 / (double) invVol)) - 1) * intScale); + } + } + + private double stockAtPrice(int targPrice) { + // Returns the stock level at which price == targPrice. + if (volatility == 0) { + // If price doesn't change, the stock level is effectively +/-INF. + if (targPrice > basePrice) { + return Integer.MIN_VALUE; + } + if (targPrice < basePrice) { + return Integer.MAX_VALUE; + } + // targPrice == basePrice + return stock; + } + return -(Math.log((double) targPrice / basePrice) / Math.log(getVolFactor())); + } + + public String formatBundleCount(int numBundles) { + if (numBundles == 1) { + return (Integer.toString(count)); + } + if (count == 1) { + return (Integer.toString(numBundles)); + } + return (Integer.toString(count) + "x" + Integer.toString(numBundles)); + } + + public String infoStringBuy(int numBundles) { + if (!isValid()) { + return ("{ERR}Invalid or uninitialized item."); + } + if (!canBuy) { + return ("{PRM}" + getName() + "{ERR} is unavailable for purchase."); + } + if (!getCanBuy(1)) { + return ("{PRM}" + getName() + "{ERR} is out of stock: no more can be bought right now."); + } + if (!getCanBuy(numBundles)) { + return ("{PRM}" + getName() + "{ERR} has only {PRM}" + formatBundleCount(leftToBuy()) + " {ERR}left for sale."); + } + // Display count as [(x)] + return ("{}Buy: {BKT}[{PRM}" + formatBundleCount(numBundles) + "{BKT}]{} for {PRM}" + DynamicMarket.iConomy.getBank().format(getBuyPrice(numBundles))); + //TODO: Abstract currency name from iConomy reference. + } + + public String infoStringSell(int numBundles) { + if (!isValid()) { + return ("{ERR}Invalid or uninitialized item."); + } + if (!canSell) { + return ("{PRM}" + getName() + "{ERR} is unavailable for purchase."); + } + if (!getCanSell(1)) { + return ("{PRM}" + getName() + "{ERR} is overstocked: no more can be sold right now."); + } + if (!getCanSell(numBundles)) { + return ("{PRM}" + getName() + "{ERR} is overstocked, only {PRM}" + formatBundleCount(leftToSell()) + " {ERR}can be sold."); + } + // Display count as [(x)] + return ("{}Sell: {BKT}[{PRM}" + formatBundleCount(numBundles) + "{BKT}]{} for {PRM}" + DynamicMarket.iConomy.getBank().format(getSellPrice(numBundles))); + //TODO: Abstract currency name from iConomy reference. + } + + public int leftToBuy() { + return (stock - stockLowest); + } + + public int leftToSell() { + return (stockHighest - stock); + } + + public String infoStringBuy() { + return infoStringBuy(1); + } + + public String infoStringSell() { + return infoStringSell(1); + } + + public boolean getCanBuy(int numBundles) { + // Report if the requested number of bundles can be bought. + if (canBuy == false) { + return false; + } + if ((stock - numBundles) < stockLowest) { + return false; + } + return true; + } + + public boolean getCanSell(int numBundles) { + // Report if the requested number of bundles can be sold. + if (canSell == false) { + return false; + } + if ((stock + numBundles) > stockHighest) { + return false; + } + return true; + } + + public String infoStringShort() { + return ("{BKT}[{}" + itemId + (subType != 0 ? "," + subType : "") + "{BKT}]{} " + getName() + "{BKT}[{}" + count + "{BKT}]{} Buy:{BKT}[{}" + (getCanBuy(1) ? getBuyPrice(1) : "-") + "{BKT}]{} Sell:{BKT}[{}" + (getCanSell(1) ? getSellPrice(1) : "-") + "{BKT}]"); + } + + public ArrayList infoStringFull() { + // More detailed info, more useful to shop admins. + // Switch to select line number? + ArrayList returnList = new ArrayList(); + returnList.add("{}ID:{BKT}[{PRM}" + itemId + (subType != 0 ? "," + subType : "") + "{BKT}]{} Name:{PRM}" + getName() + "{} BundleSize:{BKT}[{PRM}" + count + "{BKT}]"); + returnList.add("{}BasePrice:{BKT}[{PRM}" + basePrice + "{BKT}]{} SalesTax:{BKT}[{PRM}" + salesTax + "{BKT}]{} Vol:{BKT}[{PRM}" + volatility + "{BKT}]{} IVol:{BKT}[{PRM}" + getInverseVolatility() + "{BKT}]"); + returnList.add("{}Stock:{BKT}[{PRM}" + stock + "{BKT}]{} CanBuy:{BKT}[{PRM}" + (getCanBuy(1) ? getBuyPrice(1) : "-") + "{BKT}]{} CanSell:{BKT}[{PRM}" + (getCanSell(1) ? getSellPrice(1) : "-") + "{BKT}]"); + returnList.add("{}StockLowest:{BKT}[{PRM}" + intFormat(stockLowest) + "{BKT}]{} StockHighest:{BKT}[{PRM}" + intFormat(stockHighest) + "{BKT}]"); + returnList.add("{}StockFloor:{BKT}[{PRM}" + intFormat(stockFloor) + "{BKT}]{} StockCeiling:{BKT}[{PRM}" + intFormat(stockCeil) + "{BKT}]"); + returnList.add("{}PriceFloor:{BKT}[{PRM}" + intFormat(priceFloor) + "{BKT}]{} PriceCeiling:{BKT}[{PRM}" + intFormat(priceCeil) + "{BKT}]"); + return returnList; + + /* + return("&d[&f" + itemId + (subType != 0? ","+subType : "") + "&d]&f " + getName() + "&d[&f" + count + "&d]&f " + + "bp:&d[&f" + basePrice + "&d]&f st:&d[&f" + salesTax + "&d]&f v:&d[&f" + volatility + "&d]&f " + + "iv:&d[&f" + getInverseVolatility() + "&d]&f s:&d[&f" + stock + "&d]&f " + + "cb:&d[&f" + (getCanBuy(1)? getBuyPrice(1) : "-") + "&d]&f cs:&d[&f" + (getCanSell(1)? getSellPrice(1) : "-") + "&d]&f " + + "sl:&d[&f" + intFormat(stockLowest) + "&d]&f sh:&d[&f" + intFormat(stockHighest) + "&d]&f " + + "sf:&d[&f" + intFormat(stockFloor) + "&d]&f sc:&d[&f" + intFormat(stockCeil) + "&d]&f " + + "pf:&d[&f" + intFormat(priceFloor) + "&d]&f pc:&d[&f" + intFormat(priceCeil) + "&d]"); + */ + } + + public String intFormat(int thisInt) { + // Returns the string value of an int, with Integer.MAX_VALUE and Integer.MIN_VALUE converted to shorthand. + if (thisInt == Integer.MAX_VALUE) { + return "+INF"; + } + if (thisInt == Integer.MIN_VALUE) { + return "-INF"; + } + return Integer.toString(thisInt); + } + + public String csvLine() { + // Spits out a line corresponding to a line in a .csv file. + return (itemId + "," + subType + "," + count + "," + name + "," + basePrice + "," + stock + "," + (canBuy ? "Y" : "N") + "," + (canSell ? "Y" : "N") + "," + volatility + "," + salesTax + "," + intFormat(stockLowest) + "," + intFormat(stockHighest) + "," + intFormat(stockFloor) + "," + intFormat(stockCeil) + "," + intFormat(priceFloor) + "," + intFormat(priceCeil) + "," + jitterPerc + "," + driftOut + "," + driftIn + "," + avgStock + "," + itemClass); + } + + public static String csvHeaderLine() { + // Spits out an appropriate header line for the output spreadsheet. + return ("itemId,subType,count,name,basePrice,stock,canBuy,canSell,volatility,salesTax,stockLowest,stockHighest,stockFloor,stockCeil,priceFloor,priceCeil,jitterPerc,driftOut,driftIn,avgStock,itemClass"); + } + + private int quickParse(String intString) { + // Parses strings into ints, throwing away errors and replacing them with 0s. + if (intString.equalsIgnoreCase("-inf")) { + return Integer.MIN_VALUE; + } + if (intString.equalsIgnoreCase("+inf")) { + return Integer.MAX_VALUE; + } + try { + return Integer.parseInt(intString); + } catch (NumberFormatException ex) { + return 0; + } + } + + public MarketItem(String csvString, MarketItem defaults, String shopLabel, boolean isCSV) { + super(); + + if (defaults != null) { + this.itemId = defaults.itemId; + this.subType = defaults.subType; + this.count = defaults.count; + this.basePrice = defaults.basePrice; + this.stock = defaults.stock; + this.canBuy = defaults.canBuy; + this.canSell = defaults.canSell; + this.volatility = defaults.volatility; + this.salesTax = defaults.salesTax; + this.stockLowest = defaults.stockLowest; + this.stockHighest = defaults.stockHighest; + this.stockFloor = defaults.stockFloor; + this.stockCeil = defaults.stockCeil; + this.priceFloor = defaults.priceFloor; + this.priceCeil = defaults.priceCeil; + this.jitterPerc = defaults.jitterPerc; + this.driftOut = defaults.driftOut; + this.driftIn = defaults.driftIn; + this.avgStock = defaults.avgStock; + this.itemClass = defaults.itemClass; + } else { + setBaseDefaults(); + } + + String[] inputParams = csvString.split(","); + + if (inputParams.length < 21) { + return; + } + + if (!inputParams[0].isEmpty()) { + itemId = quickParse(inputParams[0]); + } + if (!inputParams[1].isEmpty()) { + subType = quickParse(inputParams[1]); + } + if (!inputParams[2].isEmpty()) { + count = quickParse(inputParams[2]); + } + if (!inputParams[3].isEmpty()) { + name = inputParams[3]; + } + if (!inputParams[4].isEmpty()) { + basePrice = quickParse(inputParams[4]); + } + if (!inputParams[5].isEmpty()) { + stock = quickParse(inputParams[5]); + } + if (!inputParams[6].isEmpty()) { + canBuy = inputParams[6].equalsIgnoreCase("Y"); + } + if (!inputParams[7].isEmpty()) { + canSell = inputParams[7].equalsIgnoreCase("Y"); + } + if (!inputParams[8].isEmpty()) { + volatility = quickParse(inputParams[8]); + } + if (!inputParams[9].isEmpty()) { + salesTax = quickParse(inputParams[9]); + } + if (!inputParams[10].isEmpty()) { + stockLowest = quickParse(inputParams[10]); + } + if (!inputParams[11].isEmpty()) { + stockHighest = quickParse(inputParams[11]); + } + if (!inputParams[12].isEmpty()) { + stockFloor = quickParse(inputParams[12]); + } + if (!inputParams[13].isEmpty()) { + stockCeil = quickParse(inputParams[13]); + } + if (!inputParams[14].isEmpty()) { + priceFloor = quickParse(inputParams[14]); + } + if (!inputParams[15].isEmpty()) { + priceCeil = quickParse(inputParams[15]); + } + if (!inputParams[16].isEmpty()) { + jitterPerc = quickParse(inputParams[16]); + } + if (!inputParams[17].isEmpty()) { + driftOut = quickParse(inputParams[17]); + } + if (!inputParams[18].isEmpty()) { + driftIn = quickParse(inputParams[18]); + } + if (!inputParams[19].isEmpty()) { + avgStock = quickParse(inputParams[19]); + } + if (!inputParams[20].isEmpty()) { + itemClass = quickParse(inputParams[20]); + } + this.shopLabel = shopLabel; + sanityCheck(); + } + + public void setEmptyMask() { + // Wipes all fields to prepare this MarketItem to be used as a data mask. + this.name = null; + this.basePrice = 0; + this.stock = 0; + this.canBuy = false; + this.canSell = false; + this.volatility = 0; + this.salesTax = 0; + this.stockLowest = 0; + this.stockHighest = 0; + this.stockFloor = 0; + this.stockCeil = 0; + this.priceFloor = 0; + this.priceCeil = 0; + this.jitterPerc = 0; + this.driftOut = 0; + this.driftIn = 0; + this.avgStock = 0; + this.itemClass = 0; + this.shopLabel = null; + } + /* + public void copyMasked(MarketItem data, MarketItem mask) + { + // Copies in the fields from data, for only the fields set non-zero/non-null/true in mask. + if (mask.name != null) this.name = data.name; + if (mask.basePrice != 0) this.basePrice = data.basePrice; + if (mask.stock != 0) this.stock = data.stock; + if (mask.canBuy) this.canBuy = data.canBuy; + if (mask.canSell) this.canSell = data.canSell; + if (mask.volatility != 0) this.volatility = data.volatility; + if (mask.salesTax != 0) this.salesTax = data.salesTax; + if (mask.stockLowest != 0) this.stockLowest = data.stockLowest; + if (mask.stockHighest != 0) this.stockHighest = data.stockHighest; + if (mask.stockFloor != 0) this.stockFloor = data.stockFloor; + if (mask.stockCeil != 0) this.stockCeil = data.stockCeil; + if (mask.priceFloor != 0) this.priceFloor = data.priceFloor; + if (mask.priceCeil != 0) this.priceCeil = data.priceCeil; + if (mask.jitterPerc != 0) this.jitterPerc = data.jitterPerc; + if (mask.driftOut != 0) this.driftOut = data.driftOut; + if (mask.driftIn != 0) this.driftIn = data.driftIn; + if (mask.avgStock != 0) this.avgStock = data.avgStock; + if (mask.itemClass != 0) this.itemClass = data.itemClass; + if (mask.shopLabel != null) this.shopLabel = data.shopLabel; + } + */ } diff --git a/src/com/gmail/haloinverse/DynamicMarket/Messaging.java b/src/com/gmail/haloinverse/DynamicMarket/Messaging.java index 4240243..c09fdf6 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/Messaging.java +++ b/src/com/gmail/haloinverse/DynamicMarket/Messaging.java @@ -1,97 +1,77 @@ package com.gmail.haloinverse.DynamicMarket; -/* */ //package com.nijikokun.bukkit.SimpleShop; -/* */ -// CHANGED: Commented out imports that weren't being used. -/* */ //import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -/* */ -/* */ public class Messaging -/* */ { -/* 32 */ public Player player = null; - private CommandSender sender = null; - public static String colNormal = "&e"; // Normal text colour {} - public static String colCmd = "&f"; // Command highlight colour {CMD} - public static String colBracket = "&d"; // Highlighting of brackets around params/data {PBK} - public static String colParam = "&b"; // Highlighting of parameters. - public static String colError = "&c"; // Highlighting for errors. {ERR} -/* */ - public Messaging(CommandSender thisSender) - { - sender = thisSender; - if (thisSender instanceof Player) - player = (Player)thisSender; - } - - public boolean isPlayer() - { - if (player == null) - return false; - return true; - } +public class Messaging { - @Deprecated -/* */ public static String argument(String original, String[] arguments, String[] points) -/* */ { -/* 44 */ for (int i = 0; i < arguments.length; ++i) { -/* 45 */ if (arguments[i].contains(",")) { -/* 46 */ for (String arg : arguments[i].split(",")) -/* 47 */ original = original.replace(arg, points[i]); -/* */ } -/* */ else { -/* 50 */ original = original.replace(arguments[i], points[i]); -/* */ } -/* */ } -/* */ -/* 54 */ return original; -/* */ } -/* */ - //TODO: Use Bukkit's colour enums. - //TODO: Make highlight colours configurable. - - public static String parseHighlights(String original) - { - return original.replace("{}",colNormal).replace("{CMD}",colCmd).replace("{BKT}",colBracket).replace("{ERR}",colError).replace("{PRM}",colParam); - } - - public static String stripHighlights(String original) - { - return original.replace("{}","").replace("{CMD}","").replace("{BKT}","").replace("{ERR}","").replace("{PRM}",""); - } + public Player player = null; + private CommandSender sender = null; + public static String colNormal = "&e"; // Normal text colour {} + public static String colCmd = "&f"; // Command highlight colour {CMD} + public static String colBracket = "&d"; // Highlighting of brackets around params/data {PBK} + public static String colParam = "&b"; // Highlighting of parameters. + public static String colError = "&c"; // Highlighting for errors. {ERR} +/* */ -/* */ public static String parse(String original) -/* */ { -/* 70 */ return parseHighlights(original).replaceAll("(&([a-z0-9]))", "§$2").replace("&&", "&"); -/* */ } -/* */ -/* */ public static String colorize(String original) -/* */ { -/* 87 */ return original.replace("", "§0").replace("", "§1").replace("", "§2").replace("", "§3").replace("", "§4").replace("", "§5").replace("", "§6").replace("", "§7").replace("", "§8").replace("", "§9").replace("", "§a").replace("", "§b").replace("", "§c").replace("", "§d").replace("", "§e").replace("", "§f"); -/* */ } -/* */ -/* */ public static String bracketize(String message) -/* */ { -/* 98 */ return "[" + message + "]"; -/* */ } -/* */ -/* */ -/* */ public void send(String message) -/* */ { -/* 138 */ if (sender != null) -/* 139 */ sender.sendMessage(parse(message)); -/* */ } -/* */ -/* */ public static void broadcast(String message) -/* */ { -/* 148 */ for (Player p : iListen.plugin.getServer().getOnlinePlayers()) -/* 149 */ p.sendMessage(parse(message)); -/* */ } -/* */ } + public Messaging(CommandSender thisSender) { + sender = thisSender; + if (thisSender instanceof Player) { + player = (Player) thisSender; + } + } -/* Location: C:\Program Files\eclipse\Bukkit\SimpleShop.jar - * Qualified Name: com.nijikokun.bukkit.SimpleShop.Messaging - * Java Class Version: 5 (49.0) - * JD-Core Version: 0.5.3 - */ \ No newline at end of file + public boolean isPlayer() { + if (player == null) { + return false; + } + return true; + } + + @Deprecated + public static String argument(String original, String[] arguments, String[] points) { + for (int i = 0; i < arguments.length; ++i) { + if (arguments[i].contains(",")) { + for (String arg : arguments[i].split(",")) { + original = original.replace(arg, points[i]); + } + } else { + original = original.replace(arguments[i], points[i]); + } + } + + return original; + } + + public static String parseHighlights(String original) { + return original.replace("{}", colNormal).replace("{CMD}", colCmd).replace("{BKT}", colBracket).replace("{ERR}", colError).replace("{PRM}", colParam); + } + + public static String stripHighlights(String original) { + return original.replace("{}", "").replace("{CMD}", "").replace("{BKT}", "").replace("{ERR}", "").replace("{PRM}", ""); + } + + public static String parse(String original) { + return parseHighlights(original).replaceAll("(&([a-z0-9]))", "§$2").replace("&&", "&"); + } + + public static String colorize(String original) { + return original.replace("", "§0").replace("", "§1").replace("", "§2").replace("", "§3").replace("", "§4").replace("", "§5").replace("", "§6").replace("", "§7").replace("", "§8").replace("", "§9").replace("", "§a").replace("", "§b").replace("", "§c").replace("", "§d").replace("", "§e").replace("", "§f"); + } + + public static String bracketize(String message) { + return "[" + message + "]"; + } + + public void send(String message) { + if (sender != null) { + sender.sendMessage(parse(message)); + } + } + + public static void broadcast(String message) { + for (Player p : iListen.plugin.getServer().getOnlinePlayers()) { + p.sendMessage(parse(message)); + } + } +} diff --git a/src/com/gmail/haloinverse/DynamicMarket/SQLHandler.java b/src/com/gmail/haloinverse/DynamicMarket/SQLHandler.java index 85757f9..6370b08 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/SQLHandler.java +++ b/src/com/gmail/haloinverse/DynamicMarket/SQLHandler.java @@ -9,286 +9,268 @@ import java.sql.Statement; public class SQLHandler { - - // A wrapper class to handle the repeated grunt-work of SQL queries and the errors they throw. - public Connection conn; - public PreparedStatement ps; - private ArrayList psList; - public ResultSet rs; - public DatabaseCore connDB; - public ArrayList inputList; - public boolean isOK; // Default true, set to false when errors occur. - - public SQLHandler(DatabaseCore thisDB) - { - isOK = true; - inputList = new ArrayList(); - psList = new ArrayList(); - connDB = thisDB; - try { - conn = connDB.connection(); - conn.setAutoCommit(false); - } catch (ClassNotFoundException ex) { - connDB.logSevereException("Database connector not found for " + connDB.dbTypeString(), ex); - conn = null; - isOK = false; - } catch (SQLException ex) { - connDB.logSevereException("SQL Error connecting to " + connDB.dbTypeString() + "database", ex); - conn = null; - isOK = false; - } - ps = null; - rs = null; - }; - - public void prepareStatement(String sqlString) - { - try { - // Store previous prepareStatement, if one was already prepared. - if (ps != null) - { - psList.add(ps); - ps = null; - } - if (conn != null) - { - // Switch GREATEST/LEAST for MAX/MIN with SQLite. - if (connDB.databaseType.equals(DatabaseCore.Type.SQLITE)) - { - if(sqlString.contains("GREATEST")) - sqlString = sqlString.replaceAll("GREATEST", "MAX"); - if(sqlString.contains("LEAST")) - sqlString = sqlString.replaceAll("LEAST", "MIN"); - } - ps = conn.prepareStatement(sqlString); - for(int i = 1; i <= inputList.size(); ++i) - { - ps.setObject(i, inputList.get(i-1)); - } - inputList.clear(); - } - } catch (SQLException ex) { - // TODO Auto-generated catch block - connDB.logSevereException("Error preparing query statement [" + sqlString + "] for " + connDB.dbTypeString(), ex); - ps = null; - isOK = false; - } - } - - public void prepareBatchStatement(String sqlString) - { - // Takes the sqlString, and creates a preparedStatement. - // Unlike prepareStatement, this does NOT read the parameters already entered into inputList. - // The inputList is instead read by addToBatch. - try { - // Store previous prepareStatement, if one was already prepared. - if (ps != null) - { - psList.add(ps); - ps = null; - } - if (conn != null) - { - ps = conn.prepareStatement(sqlString); - //for(int i = 1; i <= inputList.size(); ++i) - //{ - // ps.setObject(i, inputList.get(i-1)); - //} - //inputList.clear(); - } - } catch (SQLException ex) { - connDB.logSevereException("Error preparing query statement [" + sqlString + "] for " + connDB.dbTypeString(), ex); - ps = null; - isOK = false; - } - } - - public void addToBatch() - { - // Add the current inputList to the current (batch)preparedStatement as a batch item. - for(int i = 1; i <= inputList.size(); ++i) - { - try - { - ps.setObject(i, inputList.get(i-1)); - } catch (SQLException ex) { - connDB.logSevereException("Error adding [" + inputList.get(i-1) + "] to batch in position " + i + " for " + connDB.dbTypeString(), ex); - ps = null; - isOK = false; - break; - } - } - try { - ps.addBatch(); - } catch (SQLException ex) { - connDB.logSevereException("Error adding completed batch to PreparedStatement for " + connDB.dbTypeString(), ex); - ps = null; - isOK = false; - } - inputList.clear(); - } - - public void executeQuery() - { - // Executes only the most recent preparedStatement, AND returns the result. - // Clears the preparedStatement after use. - try { - rs = null; - if (ps != null) - { - rs = ps.executeQuery(); - conn.commit(); - ps = null; - } - } catch (SQLException ex) { - connDB.logSevereException("Error executing query statement [" + ps.toString() + "] with " + connDB.dbTypeString(), ex); - rs = null; - isOK = false; - } - } - - public void executeUpdates() - { - // Executes all currently loaded preparedStatements. - try { - // Store previous prepareStatement, if one was already prepared. - if (ps != null) - { - psList.add(ps); - ps = null; - } - if (!psList.isEmpty()) - { - for(PreparedStatement thisPs : psList) - thisPs.executeUpdate(); - // Clear list once finished execution. - psList.clear(); - conn.commit(); - } - } catch (SQLException ex) { - connDB.logSevereException("Error executing update statement [" + ps.toString() + "] with " + connDB.dbTypeString(), ex); - isOK = false; - } - } - - public void executeStatement(String sqlStatement) - { - Statement st = null; - if (conn != null) - { - try { - st = conn.createStatement(); - st.executeUpdate(sqlStatement); - conn.commit(); - } catch (SQLException ex) { - connDB.logSevereException("Error executing statement [" + sqlStatement + "] with " + connDB.dbTypeString(), ex); - isOK = false; - } finally { - if (st != null) - try { - st.close(); - } catch (SQLException ex) { - connDB.logSevereException("Error closing statement [" + sqlStatement + "] with " + connDB.dbTypeString(), ex); - isOK = false; - } - } - } - } - - public boolean checkTable(String tableName) - { - boolean bool = false; - if (conn != null) - try { - DatabaseMetaData dbm = conn.getMetaData(); - rs = dbm.getTables(null, null, tableName, null); - bool = rs.next(); - return bool; - } - catch (SQLException ex) - { - connDB.logSevereException("Table check for " + connDB.dbTypeString() + " Failed", ex); - isOK = false; - bool = false; - return bool; - } - return bool; - } - - public boolean checkColumnExists(String tableName, String columnName) - { - boolean bool = false; - if (conn != null) - try { - DatabaseMetaData dbm = conn.getMetaData(); - rs = dbm.getColumns(null, null, tableName, columnName); - bool = rs.next(); - return bool; - } - catch (SQLException ex) - { - connDB.logSevereException("Column check for " + connDB.dbTypeString() + " Failed", ex); - isOK = false; - bool = false; - return bool; - } - return bool; - } - - public int getInt(String fieldName) - { - try { - return rs.getInt(fieldName); - } catch (SQLException ex) { - connDB.logSevereException("getInt '" + fieldName + "' with " + connDB.dbTypeString() + " Failed", ex); - isOK = false; - return 0; - } - } - - public String getString(String fieldName) - { - try { - return rs.getString(fieldName); - } catch (SQLException ex) { - connDB.logSevereException("getString '" + fieldName + "' with " + connDB.dbTypeString() + " Failed", ex); - isOK = false; - return null; - } - } - - public void close() - { - if (rs != null) - try { - rs.close(); - } catch (SQLException ex) { - connDB.logSevereException("SQL error closing resultset for " + connDB.dbTypeString() + "database", ex); - isOK = false; - } - if (ps != null) - try { - ps.close(); - } catch (SQLException ex) { - connDB.logSevereException("SQL error closing prepared statement for " + connDB.dbTypeString() + "database", ex); - isOK = false; - } - if (conn != null) - try { - conn.close(); - } catch (SQLException ex) { - connDB.logSevereException("SQL error closing connection for " + connDB.dbTypeString() + "database", ex); - isOK = false; - } - } - - protected void finalize() throws Throwable { - // Just in case close() doesn't get called... - try { - close(); - } finally { - super.finalize(); - } - } + // A wrapper class to handle the repeated grunt-work of SQL queries and the errors they throw. + public Connection conn; + public PreparedStatement ps; + private ArrayList psList; + public ResultSet rs; + public DatabaseCore connDB; + public ArrayList inputList; + public boolean isOK; // Default true, set to false when errors occur. + + public SQLHandler(DatabaseCore thisDB) { + isOK = true; + inputList = new ArrayList(); + psList = new ArrayList(); + connDB = thisDB; + try { + conn = connDB.connection(); + conn.setAutoCommit(false); + } catch (ClassNotFoundException ex) { + connDB.logSevereException("Database connector not found for " + connDB.dbTypeString(), ex); + conn = null; + isOK = false; + } catch (SQLException ex) { + connDB.logSevereException("SQL Error connecting to " + connDB.dbTypeString() + "database", ex); + conn = null; + isOK = false; + } + ps = null; + rs = null; + } + + ; + + public void prepareStatement(String sqlString) { + try { + // Store previous prepareStatement, if one was already prepared. + if (ps != null) { + psList.add(ps); + ps = null; + } + if (conn != null) { + // Switch GREATEST/LEAST for MAX/MIN with SQLite. + if (connDB.databaseType.equals(DatabaseCore.Type.SQLITE)) { + if (sqlString.contains("GREATEST")) { + sqlString = sqlString.replaceAll("GREATEST", "MAX"); + } + if (sqlString.contains("LEAST")) { + sqlString = sqlString.replaceAll("LEAST", "MIN"); + } + } + ps = conn.prepareStatement(sqlString); + for (int i = 1; i <= inputList.size(); ++i) { + ps.setObject(i, inputList.get(i - 1)); + } + inputList.clear(); + } + } catch (SQLException ex) { + // TODO Auto-generated catch block + connDB.logSevereException("Error preparing query statement [" + sqlString + "] for " + connDB.dbTypeString(), ex); + ps = null; + isOK = false; + } + } + + public void prepareBatchStatement(String sqlString) { + // Takes the sqlString, and creates a preparedStatement. + // Unlike prepareStatement, this does NOT read the parameters already entered into inputList. + // The inputList is instead read by addToBatch. + try { + // Store previous prepareStatement, if one was already prepared. + if (ps != null) { + psList.add(ps); + ps = null; + } + if (conn != null) { + ps = conn.prepareStatement(sqlString); + //for(int i = 1; i <= inputList.size(); ++i) + //{ + // ps.setObject(i, inputList.get(i-1)); + //} + //inputList.clear(); + } + } catch (SQLException ex) { + connDB.logSevereException("Error preparing query statement [" + sqlString + "] for " + connDB.dbTypeString(), ex); + ps = null; + isOK = false; + } + } + + public void addToBatch() { + // Add the current inputList to the current (batch)preparedStatement as a batch item. + for (int i = 1; i <= inputList.size(); ++i) { + try { + ps.setObject(i, inputList.get(i - 1)); + } catch (SQLException ex) { + connDB.logSevereException("Error adding [" + inputList.get(i - 1) + "] to batch in position " + i + " for " + connDB.dbTypeString(), ex); + ps = null; + isOK = false; + break; + } + } + try { + ps.addBatch(); + } catch (SQLException ex) { + connDB.logSevereException("Error adding completed batch to PreparedStatement for " + connDB.dbTypeString(), ex); + ps = null; + isOK = false; + } + inputList.clear(); + } + + public void executeQuery() { + // Executes only the most recent preparedStatement, AND returns the result. + // Clears the preparedStatement after use. + try { + rs = null; + if (ps != null) { + rs = ps.executeQuery(); + conn.commit(); + ps = null; + } + } catch (SQLException ex) { + connDB.logSevereException("Error executing query statement [" + ps.toString() + "] with " + connDB.dbTypeString(), ex); + rs = null; + isOK = false; + } + } + + public void executeUpdates() { + // Executes all currently loaded preparedStatements. + try { + // Store previous prepareStatement, if one was already prepared. + if (ps != null) { + psList.add(ps); + ps = null; + } + if (!psList.isEmpty()) { + for (PreparedStatement thisPs : psList) { + thisPs.executeUpdate(); + } + // Clear list once finished execution. + psList.clear(); + conn.commit(); + } + } catch (SQLException ex) { + connDB.logSevereException("Error executing update statement [" + ps.toString() + "] with " + connDB.dbTypeString(), ex); + isOK = false; + } + } + + public void executeStatement(String sqlStatement) { + Statement st = null; + if (conn != null) { + try { + st = conn.createStatement(); + st.executeUpdate(sqlStatement); + conn.commit(); + } catch (SQLException ex) { + connDB.logSevereException("Error executing statement [" + sqlStatement + "] with " + connDB.dbTypeString(), ex); + isOK = false; + } finally { + if (st != null) { + try { + st.close(); + } catch (SQLException ex) { + connDB.logSevereException("Error closing statement [" + sqlStatement + "] with " + connDB.dbTypeString(), ex); + isOK = false; + } + } + } + } + } + + public boolean checkTable(String tableName) { + boolean bool = false; + if (conn != null) { + try { + DatabaseMetaData dbm = conn.getMetaData(); + rs = dbm.getTables(null, null, tableName, null); + bool = rs.next(); + return bool; + } catch (SQLException ex) { + connDB.logSevereException("Table check for " + connDB.dbTypeString() + " Failed", ex); + isOK = false; + bool = false; + return bool; + } + } + return bool; + } + + public boolean checkColumnExists(String tableName, String columnName) { + boolean bool = false; + if (conn != null) { + try { + DatabaseMetaData dbm = conn.getMetaData(); + rs = dbm.getColumns(null, null, tableName, columnName); + bool = rs.next(); + return bool; + } catch (SQLException ex) { + connDB.logSevereException("Column check for " + connDB.dbTypeString() + " Failed", ex); + isOK = false; + bool = false; + return bool; + } + } + return bool; + } + + public int getInt(String fieldName) { + try { + return rs.getInt(fieldName); + } catch (SQLException ex) { + connDB.logSevereException("getInt '" + fieldName + "' with " + connDB.dbTypeString() + " Failed", ex); + isOK = false; + return 0; + } + } + + public String getString(String fieldName) { + try { + return rs.getString(fieldName); + } catch (SQLException ex) { + connDB.logSevereException("getString '" + fieldName + "' with " + connDB.dbTypeString() + " Failed", ex); + isOK = false; + return null; + } + } + + public void close() { + if (rs != null) { + try { + rs.close(); + } catch (SQLException ex) { + connDB.logSevereException("SQL error closing resultset for " + connDB.dbTypeString() + "database", ex); + isOK = false; + } + } + if (ps != null) { + try { + ps.close(); + } catch (SQLException ex) { + connDB.logSevereException("SQL error closing prepared statement for " + connDB.dbTypeString() + "database", ex); + isOK = false; + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException ex) { + connDB.logSevereException("SQL error closing connection for " + connDB.dbTypeString() + "database", ex); + isOK = false; + } + } + } + + protected void finalize() throws Throwable { + // Just in case close() doesn't get called... + try { + close(); + } finally { + super.finalize(); + } + } } diff --git a/src/com/gmail/haloinverse/DynamicMarket/TransactionLogger.java b/src/com/gmail/haloinverse/DynamicMarket/TransactionLogger.java index bcc9901..60fb858 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/TransactionLogger.java +++ b/src/com/gmail/haloinverse/DynamicMarket/TransactionLogger.java @@ -6,67 +6,63 @@ public class TransactionLogger { - private BufferedWriter logWriter = null; - private DynamicMarket plugin; - private String logFileName; - public boolean autoFlush; - public boolean isOK; - - public TransactionLogger (DynamicMarket thisPlugin, String fileName, boolean setAutoFlush) - { - this.isOK = true; - this.plugin = thisPlugin; - this.logFileName = fileName; - this.autoFlush = setAutoFlush; - if ((fileName == null) || (fileName.isEmpty())) - { - isOK = false; - return; - } - try { - logWriter = new BufferedWriter(new FileWriter(logFileName, true)); - } catch (IOException ex) { - logSevereException("Error opening log file for writing: " + logFileName, ex); - isOK = false; - return; - } - } - - public void logTransaction(String thisLine) - { - if (logWriter == null) - return; - try { - logWriter.newLine(); - logWriter.write(thisLine); - if(this.autoFlush) - logWriter.flush(); - } catch (IOException ex) { - logSevereException("Error writing output line to log file: " + logFileName, ex); - isOK = false; - } - } - - protected void finalize() - { - if (logWriter == null) - return; - try - { - logWriter.flush(); - } catch (IOException ex) { - logSevereException("Error flushing output while closing logfile:" + logFileName, ex); - } - try - { - logWriter.close(); - } catch (IOException ex) { - logSevereException("Error closing logfile:" + logFileName, ex); - } - } - - private void logSevereException(String exDesc, Exception exDetail) - { - plugin.log.severe("[" + plugin.name + "]: " + exDesc + ": " + exDetail); - } + private BufferedWriter logWriter = null; + private DynamicMarket plugin; + private String logFileName; + public boolean autoFlush; + public boolean isOK; + + public TransactionLogger(DynamicMarket thisPlugin, String fileName, boolean setAutoFlush) { + this.isOK = true; + this.plugin = thisPlugin; + this.logFileName = fileName; + this.autoFlush = setAutoFlush; + if ((fileName == null) || (fileName.isEmpty())) { + isOK = false; + return; + } + try { + logWriter = new BufferedWriter(new FileWriter(logFileName, true)); + } catch (IOException ex) { + logSevereException("Error opening log file for writing: " + logFileName, ex); + isOK = false; + return; + } + } + + public void logTransaction(String thisLine) { + if (logWriter == null) { + return; + } + try { + logWriter.newLine(); + logWriter.write(thisLine); + if (this.autoFlush) { + logWriter.flush(); + } + } catch (IOException ex) { + logSevereException("Error writing output line to log file: " + logFileName, ex); + isOK = false; + } + } + + protected void finalize() { + if (logWriter == null) { + return; + } + try { + logWriter.flush(); + } catch (IOException ex) { + logSevereException("Error flushing output while closing logfile:" + logFileName, ex); + } + try { + logWriter.close(); + } catch (IOException ex) { + logSevereException("Error closing logfile:" + logFileName, ex); + } + } + + private void logSevereException(String exDesc, Exception exDetail) { + plugin.log.severe("[" + plugin.name + "]: " + exDesc + ": " + exDetail); + } } diff --git a/src/com/gmail/haloinverse/DynamicMarket/iListen.java b/src/com/gmail/haloinverse/DynamicMarket/iListen.java index 8f3961c..acd4b1e 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/iListen.java +++ b/src/com/gmail/haloinverse/DynamicMarket/iListen.java @@ -3,10 +3,9 @@ import com.gmail.haloinverse.DynamicMarket.DynamicMarket.EconType; //import com.haloinverse.AnyConomy.Exceptions.*; +import com.nijiko.coelho.iConomy.system.Account; import com.nijikokun.bukkit.Permissions.Permissions; -import com.nijikokun.bukkit.iConomy.iConomy; -import com.nijikokun.bukkit.iConomy.Account; import java.util.ArrayList; //import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -15,1254 +14,982 @@ import org.bukkit.event.player.PlayerListener; import org.bukkit.inventory.ItemStack; - -public class iListen extends PlayerListener -{ - - public static DynamicMarket plugin; - - public iListen(DynamicMarket instance) - { - plugin = instance; - } - - private boolean hasPermission(CommandSender sender, String permString) - { - if (plugin.simplePermissions) - { - if (sender instanceof Player) - { - if (Misc.isAny(permString, new String[] {"access", "buy", "sell"})) - return true; - else - return false; - } - else - return true; - } - if (plugin.wrapperPermissions) - { - if (plugin.permissionWrapper != null) - return plugin.permissionWrapper.permission(sender, permString); - plugin.log.severe(Messaging.bracketize(plugin.name) + "WARNING: wrapper-permissions set, but no permission handler registered!"); - return false; - } - // Permissions not overridden. - if (sender instanceof Player) - return Permissions.Security.permission((Player)sender, plugin.name.toLowerCase()+"."+permString); - return true; - } - - private boolean showHelp(CommandSender sender, String topic) - { - //TODO: Migrate help system to an MCDocs-like plugin eventually. - Messaging message = new Messaging(sender); - - if (topic.isEmpty()) - { - String commands = ""; - String topics = ""; - String shortcuts = ""; - message.send("{}" + Misc.headerify("{CMD} " + plugin.name + " {BKT}({CMD}" + plugin.codename + "{BKT}){} ")); - message.send("{} {BKT}(){} Optional, {PRM}<>{} Parameter"); - message.send("{CMD} /shop help {BKT}({PRM}{BKT}){} - Show help."); - message.send("{CMD} /shop {PRM}{BKT}({CMD}:{PRM}{BKT}){} - Show buy/sell info on an item."); - message.send("{CMD} /shop {PRM} {} - Use a shop command."); - commands += " list"; - shortcuts += " -? -l"; - if (hasPermission(sender,"buy")) - { - commands += " buy"; - shortcuts += " -b"; - } - if (hasPermission(sender,"sell")) - { - commands += " sell"; - shortcuts += " -s"; - } - - commands += " info"; - shortcuts += " -i"; - - if (hasPermission(sender,"items.add")) - { - commands += " add"; - shortcuts += " -a"; - } - if (hasPermission(sender,"items.update")) - { - commands += " update"; - shortcuts += " -u"; - } - if (hasPermission(sender,"items.remove")) - { - commands += " remove"; - shortcuts += " -r"; - } - if (hasPermission(sender,"admin")) - { - commands += " reload"; - commands += " reset"; - commands += " exportdb importdb"; - } - - topics += "ids details about"; - if (hasPermission(sender, "items.add") || hasPermission(sender, "items.update")) - topics += " tags"; - - message.send("{} Commands: {CMD}" + commands); - message.send("{} Shortcuts: {CMD}" + shortcuts); - message.send("{} Other help topics: {PRM}" + topics); - return true; - } - message.send("{}" + Misc.headerify("{} " + plugin.name + " {BKT}({}" + plugin.codename + "{BKT}){} : " + topic + "{} ")); - if (topic.equalsIgnoreCase("buy")) - { - if (hasPermission(sender,"buy")) - { - message.send("{CMD} /shop buy {PRM}{BKT}({CMD}:{PRM}{CMD})"); - message.send("{} Buy {PRM}{} bundles of an item."); - message.send("{} If {PRM}{} is missing, buys 1 bundle."); - return true; - } - } - if (topic.equalsIgnoreCase("sell")) - { - if (hasPermission(sender,"sell")) - { - message.send("{CMD} /shop sell {PRM}{BKT}({CMD}:{PRM}{CMD})"); - message.send("{} Sell {PRM}{} bundles of an item."); - message.send("{} If {PRM}{} is missing, sells 1 bundle."); - return true; - } - } - if (topic.equalsIgnoreCase("info")) - { - //if (hasPermission(player,"sell")) - //{ - message.send("{CMD} /shop info {PRM}"); - message.send("{} Show detailed information about a shop item."); - message.send("{} Unlike {CMD}/shop {PRM}{}, this shows ALL fields."); - return true; - //} - } - if (topic.equalsIgnoreCase("add")) - { - if (hasPermission(sender,"items.add")) - { - message.send("{CMD} /shop add {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT} ({PRM}{BKT})) {PRM}"); - message.send("{} Adds item {PRM}{} to the shop."); - message.send("{} Transactions will be in {PRM}{} units (default 1)."); - message.send("{PRM} {} and {PRM}{} will be converted, if used."); - message.send("{} Prices are per-bundle."); - message.send("{} See also: {CMD}/shop help tags"); - return true; - } - } - if (topic.equalsIgnoreCase("update")) - { - if (hasPermission(sender,"items.update")) - { - message.send("{CMD} /shop update {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT} ({PRM}{BKT})) {PRM}"); - message.send("{} Changes item {PRM}{}'s shop details."); - message.send("{PRM} {}, {PRM}{}, {PRM}{}, and {PRM}{} will be changed."); - message.send("{} Transactions will be in {PRM}{} units (default 1)."); - message.send("{} Prices are per-bundle."); - message.send("{} See also: {CMD}/shop help tags"); - return true; - } - } - if (topic.equalsIgnoreCase("remove")) - { - if (hasPermission(sender,"items.remove")) - { - message.send("{CMD} /shop remove {PRM}"); - message.send("{} Removes item {PRM}{} from the shop."); - return true; - } - } - if (hasPermission(sender,"admin")) - { - if (topic.equalsIgnoreCase("reload")) - { - message.send("{CMD} /shop reload"); - message.send("{} Restarts the shop plugin."); - message.send("{} Attempts to reload all relevant config files."); - return true; - } - if (topic.equalsIgnoreCase("reset")) - { - message.send("{CMD} /shop reset"); - message.send("{} Completely resets the shop database."); - message.send("{} This will remove all items from the shop, and"); - message.send("{} create a new empty shop database."); - return true; - } - if (topic.equalsIgnoreCase("exportdb")) - { - message.send("{CMD} /shop exportdb"); - message.send("{} Dumps the shop database to a .csv file."); - message.send("{} Name and location are set in the main config file."); - message.send("{} The file can be edited by most spreadsheet programs."); - return true; - } - if (topic.equalsIgnoreCase("importdb")) - { - message.send("{CMD} /shop importdb"); - message.send("{} Reads a .csv file in to the shop database."); - message.send("{} Name and location are set in the main config file."); - message.send("{} The format MUST be the same as the export format."); - message.send("{} Records matching id/subtype will be updated."); - return true; - } - } - if (topic.equalsIgnoreCase("ids")) - { - message.send("{} Item ID format: {PRM}{BKT}({CMD},{PRM}{BKT})({CMD}:{PRM}{BKT})"); - message.send("{PRM} {}: Full name or ID number of the item."); - message.send("{PRM} {}: Subtype of the item (default: 0)"); - message.send("{} Subtypes are used for wool/dye colours, log types, etc."); - message.send("{PRM} {}: For shop items, this specifies bundle size."); - message.send("{} For transactions, this sets the number of bundles bought or sold."); - return true; - } - if (topic.equalsIgnoreCase("list")) - { - message.send("{CMD} /shop list {BKT}({PRM}{BKT}) ({PRM}{BKT})"); - message.send("{} Displays the items in the shop."); - message.send("{} List format: {BKT}[{PRM}{BKT}]{PRM} {BKT}[{PRM}{BKT}]{} Buy {BKT}[{PRM}{BKT}]{} Sell {BKT}[{PRM}{BKT}]"); - message.send("{} Page 1 is displayed by default, if no page number is given."); - message.send("{} If {PRM}{} is used, displays items containing {PRM}{}."); - return true; - } - if (topic.equalsIgnoreCase("details")) - { - message.send("{CMD} /shop {PRM}{BKT}({CMD}:{PRM}{BKT})"); - message.send("{} Displays the current buy/sell price of the selected item."); - message.send("{} Since prices can fluctuate, use {PRM}{} to get batch pricing."); - message.send("{} See {CMD}/shop help ids{} for information on IDs."); - return true; - } - if ((Misc.isEither(topic.split(" ")[0],"tags","tag")) && ((hasPermission(sender, "items.add") || hasPermission(sender, "items.update")))) - { - if(topic.indexOf(" ") > -1) - { - // Possible tag listed! - String thisTag = topic.split(" ")[1].replace(":",""); - if (Misc.isEither(thisTag, "n","name")) - { - message.send("{CMD} n:{BKT}|{CMD}name:{} - Name/rename item"); - message.send("{} Sets the item's name in the shop DB."); - message.send("{} New name will persist until the item is removed."); - message.send("{} If name is blank, will try to reload the name from items.db."); - return true; - } - if (Misc.isEither(thisTag, "bp","baseprice")) - { - message.send("{CMD} bp:{BKT}|{CMD}BasePrice:{} - Base purchase price"); - message.send("{} Buy price of the item at stock level 0."); - message.send("{} All other prices are derived from this starting value."); - message.send("{} Referenced by {PRM}SalesTax{}, {PRM}Stock{}, and {PRM}Volatility{}."); - message.send("{} Soft-limited by {PRM}PriceFloor{}/{PRM}PriceCeiling{}."); - return true; - } - if (Misc.isEither(thisTag, "s","stock")) - { - message.send("{CMD} s:{BKT}|{CMD}Stock:{} - Current stock level"); - message.send("{} Stock level of this item (in bundles)."); - message.send("{} Increases/decreases when items are sold/bought."); - message.send("{} Affects buy/sell prices, if {PRM}Volatility{} > 0."); - message.send("{} Soft-limited by {PRM}StockFloor{}/{PRM}StockCeiling{}."); - message.send("{} Hard-limited (transactions fail) by {PRM}StockLowest{}/{PRM}StockHighest{}."); - return true; - } - if (Misc.isEither(thisTag, "cb","canbuy")) - { - message.send("{CMD} cb:{BKT}|{CMD}CanBuy:{} - Buyability of item"); - message.send("{} Set to 'Y', 'T', or blank to allow buying from shop."); - message.send("{} Set to 'N' or 'F' to disallow buying from shop."); - return true; - } - if (Misc.isEither(thisTag, "cs","cansell")) - { - message.send("{CMD} cs:{BKT}|{CMD}CanSell:{} - Sellability of item"); - message.send("{} Set to 'Y', 'T', or blank to allow selling to shop."); - message.send("{} Set to 'N' or 'F' to disallow selling to shop."); - return true; - } - if (Misc.isAny(thisTag, new String[] {"v","vol", "volatility"})) - { - message.send("{CMD} v:{BKT}|{CMD}Vol:{}{BKT}|{CMD}Volatility:{} - Price volatility"); - message.send("{} Percent increase in price per 1 bundle bought from shop, * 10000."); - message.send("{} v=0 prevents the price from changing with stock level."); - message.send("{} v=1 increases the price 1% per 100 bundles bought."); - message.send("{} v=10000 increases the price 100% per 1 bundle bought."); - message.send("{} Calculations are compound vs. current stock level."); - return true; - } - if (Misc.isAny(thisTag, new String[] {"iv","ivol", "invvolatility"})) - { - message.send("{CMD} iv:{BKT}|{CMD}IVol:{}{BKT}|{CMD}InvVolatility:{} - Inverse Volatility"); - message.send("{} Number of bundles bought in order to double the price."); - message.send("{} Converted to volatility when entered."); - message.send("{} iv=+INF prevents the price from changing with stock level."); - message.send("{} iv=6400 doubles the price for each 6400 items bought."); - message.send("{} iv=1 doubles the price for each item bought."); - message.send("{} Calculations are compound vs. current stock level."); - return true; - } - if (Misc.isEither(thisTag, "st","salestax")) - { - message.send("{CMD} st:{BKT}|{CMD}SalesTax:{} - Sales Tax"); - message.send("{} Percent difference between BuyPrice and SellPrice, * 100."); - message.send("{} {PRM}SellPrice{}={PRM}BuyPrice{}*(1-({PRM}SalesTax{}/100))"); - message.send("{} If {PRM}SellPrice{} is entered as an untagged value, it is used to calculate {PRM}SalesTax{}."); - message.send("{} {PRM}SalesTax{} is applied after {PRM}PriceFloor{}/{PRM}PriceCeiling{}."); - return true; - } - if (Misc.isEither(thisTag, "sl","stocklowest")) - { - message.send("{CMD} sl:{BKT}|{CMD}StockLowest:{} - Lowest stock level (hard limit)"); - message.send("{} Buying from shop will fail if it would put stock below {PRM}StockLowest{}."); - message.send("{} Set to 0 to to make stock 'finite'."); - message.send("{} Set to -INF or a negative value to use stock level as a 'relative offset'."); - return true; - } - if (Misc.isEither(thisTag, "sh","stockhighest")) - { - message.send("{CMD} sh:{BKT}|{CMD}StockHighest:{} - Highest stock level (hard limit)"); - message.send("{} Selling to shop will fail if it would put stock above {PRM}StockHighest{}."); - message.send("{} Set to +INF to let maximum stock be unlimited."); - return true; - } - if (Misc.isEither(thisTag, "sf","stockfloor")) - { - message.send("{CMD} sf:{BKT}|{CMD}StockFloor:{} - Lowest stock level (soft limit)"); - message.send("{} If {PRM}Stock{} falls below {PRM}StockFloor{}, it will be reset to {PRM}StockFloor{}."); - message.send("{} Further purchases will be at a flat rate, until {PRM}Stock{} rises."); - return true; - } - if (Misc.isEither(thisTag, "sc","stockceiling")) - { - message.send("{CMD} sc:{BKT}|{CMD}StockCeiling:{} - Highest stock level (soft limit)"); - message.send("{} If {PRM}Stock{} rises above {PRM}StockCeiling{}, it will be reset to {PRM}StockCeiling{}."); - message.send("{} Further sales will be at a flat rate, until {PRM}Stock{} falls."); - return true; - } - if (Misc.isEither(thisTag, "pf","pricefloor")) - { - message.send("{CMD} pf:{BKT}|{CMD}PriceFloor:{} - Lowest buy price (soft limit)"); - message.send("{} If {PRM}BuyPrice{} falls below {PRM}PriceFloor{}, it will be cropped at {PRM}PriceFloor{}."); - message.send("{} Buy/sell prices will be at a flat rate, until {PRM}BuyPrice{} rises above {PRM}PriceFloor{}."); - message.send("{} {PRM}PriceFloor{} is applied to {PRM}SellPrice{} before {PRM}SalesTax{}."); - return true; - } - if (Misc.isEither(thisTag, "pc","priceceiling")) - { - message.send("{CMD} pc:{BKT}|{CMD}PriceCeiling:{} - Highest buy price (soft limit)"); - message.send("{} If {PRM}BuyPrice{} rises above {PRM}PriceCeiling{}, it will be cropped at {PRM}PriceCeiling{}."); - message.send("{} Buy/sell prices will be at a flat rate, until {PRM}BuyPrice{} falls below {PRM}PriceCeiling{}."); - message.send("{} {PRM}PriceCeiling{} is applied to {PRM}SellPrice{} before {PRM}SalesTax{}."); - return true; - } - if (thisTag.equalsIgnoreCase("flat")) - { - message.send("{CMD} flat{} - Set item with flat pricing."); - message.send("{} Buy/sell prices for this item will not change with stock level."); - message.send("{} Stock level WILL be tracked, and can float freely."); - message.send("{} Equivalent to: {CMD}s:0 sl:-INF sh:+INF sf:-INF sc:+INF v:0 pf:0 pc:+INF"); - return true; - } - if (thisTag.equalsIgnoreCase("fixed")) - { - message.send("{CMD} fixed{} - Set item with fixed pricing."); - message.send("{} Buy/sell prices for this item will not change with transactions."); - message.send("{} Stock level WILL NOT be tracked, and {PRM}Stock{} will remain at 0."); - message.send("{} Equivalent to: {CMD}s:0 sl:-INF sh:+INF sf:0 sc:0 v:0 pf:0 pc:+INF"); - return true; - } - if (thisTag.equalsIgnoreCase("float")) - { - message.send("{CMD} float{} - Set item with floating pricing."); - message.send("{} Buy/sell prices for this item will vary by stock level."); - message.send("{} If {PRM}Vol{}=0, {PRM}Vol{} will be set to a default of 100."); - message.send("{} (For finer control, set {PRM}Volatility{} to an appropriate value.)"); - message.send("{} Stock level can float freely above and below 0 with transactions."); - message.send("{} Equivalent to: {CMD}sl:-INF sh:+INF sf:-INF sc:+INF {BKT}({CMD}v:100{BKT}){CMD} pf:0 pc:+INF"); - return true; - } - if (thisTag.equalsIgnoreCase("finite")) - { - message.send("{CMD} finite{} - Set item with finite stock."); - message.send("{} Buying from shop will fail if it would make {PRM}Stock{} < 0."); - message.send("{} Any number of items can be sold to the shop."); - message.send("{} Equivalent to: {CMD}sl:0 sh:+INF sf:-INF sc:+INF"); - return true; - } - if (thisTag.equalsIgnoreCase("renorm")) - { - message.send("{CMD} renorm{BKT}({CMD}:{PRM}{BKT}){} - Renormalize an item's price."); - message.send("{} Resets an item's {PRM}Stock{}, while preserving its current price."); - message.send("{} Sets an item's {PRM}BasePrice{} to its current {PRM}BuyPrice{},"); - message.send("{} then sets {PRM}Stock{} to {PRM}{} (0 if blank or missing)."); - return true; - } - message.send("{ERR} Unknown tag {PRM}"+thisTag+"{ERR}."); - message.send("{ERR} Use {CMD}/shop help tags{ERR} to list tags."); - return false; - } - else - { - message.send("{} Tag format: {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT}({CMD}:{PRM}{BKT}))..."); - message.send("{} Available tags: {CMD} Name: BasePrice: SalesTax: Stock: CanBuy: CanSell: Vol: IVol:"); - message.send("{CMD} StockLowest: StockHighest: StockFloor: StockCeiling: PriceFloor: PriceCeiling:"); - message.send("{} Available preset tags: {CMD}Fixed Flat Float Finite Renorm:"); - message.send("{} Use {CMD}/shop help tag {PRM}{} for tag descriptions."); - return true; - } - } - if (topic.equalsIgnoreCase("about")) - { - message.send("{} " + plugin.name + " " + plugin.version + " written by HaloInverse."); - message.send("{} Original structure and portions of code are from SimpleShop 1.1 by Nijikokun."); - return true; - } - message.send("{}Unknown help topic:{CMD} " + topic); - message.send("{}Use {CMD}/shop help{} to list topics."); - return false; - } - - - private int get_balance(String name) - { - if (!plugin.econLoaded) - return 0; - if ((name != null) && (!name.isEmpty())) - { - //if (plugin.econType == EconType.ICONOMY2) - // return iConomy.db.get_balance(name); - if (plugin.econType == EconType.ICONOMY3) - return (int)iConomy.Bank.getAccount(name).getBalance(); - - /* - if (plugin.econType == EconType.ANYCONOMY) - try { - return (int)plugin.anyConomy.getBalance(name); - } catch (InternalEconException e) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Internal Economy Error Getting Balance for '" + name + "': " + e); - return 0; - } catch (NoAccountException e) { - try { - plugin.anyConomy.createAccount(name); - } catch (NoEconRegisteredException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Transaction before economy registered: " + e1); - return 0; - } catch (InternalEconException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Internal Economy Error Creating Account '" + name + "': " + e1); - return 0; - } catch (AccountExistsException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Inconsistent NoAccount/AccountExists Errors for '" + name + "': " + e1); - return 0; - } - } catch (NoEconRegisteredException e) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Transaction before economy registered: " + e); - return 0; - } - */ - - //plugin.log.info(Messaging.bracketize(name) + "GetBalance: " + name + ":" + (int)iConomy.Bank.getAccount(name).getBalance()); - //return (int)iConomy.Bank.getAccount(name).getBalance(); - //plugin.log.info(Messaging.bracketize(name) + "GetBalance: " + name + ":" + iConomy.database.getBalance(name)); - //return (int)iConomy.database.getBalance(name); - } - //plugin.log.info(Messaging.bracketize(name) + "GetBalance: (none):0"); - return 0; - } - - //private void set_balance(String name, int amount) - //{ - // if ((name != null) && (!name.isEmpty())) - // iConomy.db.set_balance(name, amount); - //} - - private void show_balance(Player player, Messaging message) - { - //plugin.iC.l.showBalance(player.getName(), player, true); - int thisBalance = get_balance(player.getName()); - message.send("{} Balance: {PRM}" + thisBalance + " " + getCurrencyName(thisBalance) + (Math.abs(thisBalance)==1? "" : "s")); - } - - private void delta_balance(String name, int amount) //throws InvalidTransactionException - { - if (!plugin.econLoaded) - return; - if ((name != null) && (!name.isEmpty())) - { - //plugin.log.info(Messaging.bracketize(name) + "GetBalance: " + name + ":" + iConomy.database.getBalance(name)); - //plugin.log.info(Messaging.bracketize(name) + "SetBalance: " + name + ":" + (iConomy.database.getBalance(name) + amount)); - //iConomy.Bank.updateAccount(name, iConomy.Bank.getAccount(name).getBalance() + amount); - //if (plugin.econType == EconType.ICONOMY2) - // iConomy.db.set_balance(name, get_balance(name) + amount); - if (plugin.econType == EconType.ICONOMY3) - { - Account thisAccount = iConomy.Bank.getAccount(name); - thisAccount.add(amount); - thisAccount.save(); - } - - /* - else if (plugin.econType == EconType.ANYCONOMY) - { - try { - plugin.anyConomy.addBalance(name, amount); - } catch (InternalEconException e) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Internal Economy Error Performing Transaction for '" + name + "': " + e); - return; - } catch (NoAccountException e) { - try { - plugin.anyConomy.createAccount(name); - } catch (NoEconRegisteredException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Transaction before economy registered: " + e1); - return; - } catch (InternalEconException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Internal Economy Error Creating Account '" + name + "': " + e1); - return; - } catch (AccountExistsException e1) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Inconsistent NoAccount/AccountExists Errors for '" + name + "': " + e1); - return; - } - } catch (NoEconRegisteredException e) { - plugin.log.severe(Messaging.bracketize(plugin.name) + " Transaction before economy registered: " + e); - return; - } - } - */ - - } - } - - private boolean shopShowItemInfo(String itemString, Messaging message, boolean fullInfo, String shopLabel) - { - ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); - - if (!requested.isValid()) { - message.send(plugin.shop_tag + "{ERR}Unrecognized or invalid item or command."); - return false; - } - - MarketItem data = plugin.db.data(requested, shopLabel); - - if (data == null) { - message.send(plugin.shop_tag + "{ERR}Item currently not traded in shop."); - return false; - } - - message.send(plugin.shop_tag + "{}Item {PRM}" + data.getName() + "{BKT}[{PRM}" + data.idString() + "{BKT}]{} info:"); - if (fullInfo) - { - ArrayList thisList = data.infoStringFull(); - for (String thisLine : thisList) - message.send(thisLine); - } - else - { - //message.send("Placeholder..."); - message.send(data.infoStringBuy(requested.count)); - message.send(data.infoStringSell(requested.count)); - } - return true; - } - - private boolean shopBuyItem(Player player, String itemString, String shopLabel, String accountName) - { - //TODO: Check for sufficient inventory space for received items. - ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); - Messaging message = new Messaging(player); - - int balance = get_balance(player.getName()); - - int transValue; - - if (!requested.isValid()) { - message.send(plugin.shop_tag + "{ERR}Invalid item."); - message.send("Use: {CMD}/shop buy {PRM}{BKT}({CMD}:{PRM}{BKT})"); - return false; - } - - MarketItem data = plugin.db.data(requested, shopLabel); - - if ((data == null) || !data.isValid()) { - message.send(plugin.shop_tag + "{ERR}Unrecognized item name, or not in shop."); - return false; - } - - if (data.isDefault()) { - message.send(plugin.shop_tag + "{ERR}The default item template is not buyable."); - return false; - } - - if (!data.canBuy) { - message.send(plugin.shop_tag + "{ERR}" + data.getName() + " currently not purchaseable from shop."); - return false; - } - - if (!data.getCanBuy(requested.count)) { - message.send(plugin.shop_tag + "{ERR}" + data.getName() + " understocked: only " + data.formatBundleCount(data.leftToBuy()) + " left."); - return false; - } - - if ((requested.count < 1) || (requested.count * data.count > plugin.max_per_purchase)) - { - message.send(plugin.shop_tag + "{ERR}Amount over max items per purchase."); - return false; - } - - transValue = data.getBuyPrice(requested.count); - - //if (balance < data.buy * requested.count) { - if (balance < transValue) - { - message.send(plugin.shop_tag + "{ERR}You do not have enough " + getCurrencyNamePlural() + " to do this."); - message.send(data.infoStringBuy(requested.count)); - return false; - } - - //delta_balance(player.getName(), -transValue); - //delta_balance(accountName, transValue); - - - //try { - delta_balance(player.getName(), -transValue); - //} catch (InvalidTransactionException e) { - // message.send(plugin.shop_tag + "{ERR}Transaction rejected by economy system."); - // return false; - //} - //try { - delta_balance(accountName, transValue); - //} catch (InvalidTransactionException e) { - // message.send(plugin.shop_tag + "{ERR}Transaction rejected by economy system."); - // try { - // // Roll back previous transaction. - // delta_balance(player.getName(), transValue); - // } catch (InvalidTransactionException e1) { - // plugin.log.severe(Messaging.bracketize(plugin.name) + " Could not roll back '" + player.getName() + "' after invalid transaction with '" + accountName + "': " + e1); - // return false; - // } - //} - - - player.getInventory().addItem(new ItemStack[] { new ItemStack(data.itemId, requested.count * data.count, (short) 0, (byte)requested.subType) }); - - plugin.db.removeStock(requested, shopLabel); - - message.send(plugin.shop_tag + "Purchased {BKT}[{PRM}" + data.formatBundleCount(requested.count) + "{BKT}]{PRM} " + data.getName() + "{} for {PRM}" + transValue + " " + getCurrencyName(transValue)); - show_balance(player, message); - if (plugin.transLog.isOK) - plugin.transLog.logTransaction(player.getName() + ", Buy, " + (-requested.count) + ", " + data.count + ", " + data.getName() + ", " + - data.itemId + ", " + data.subType + ", " + transValue + ", " + (shopLabel==null?"":shopLabel) + ", " + (accountName==null?"":accountName)); - return true; - } - - private boolean shopSellItem(Player player, String itemString, String shopLabel, String accountName, boolean freeAccount) - { - ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); - Messaging message = new Messaging(player); - - //int balance = get_balance(player.getName()); - int transValue; - - if (!requested.isValid()) { - message.send(plugin.shop_tag + "{ERR}Invalid item."); - message.send("Use: {CMD}/shop sell {PRM}{BKT}({CMD}:{PRM}{BKT})"); - return false; - } - - MarketItem data = plugin.db.data(requested, shopLabel); - - if ((data == null) || !data.isValid()) { - message.send(plugin.shop_tag + "{ERR}Unrecognized item name, or not in shop."); - return false; - } - - if (data.isDefault()) { - message.send(plugin.shop_tag + "{ERR}The default template is not sellable."); - return false; - } - - if (data.canSell == false) { - message.send(plugin.shop_tag + "{ERR}" + data.getName() + " currently not sellable to shop."); - return false; - } - - if ((requested.count < 1) || (requested.count * data.count > plugin.max_per_sale)) { - message.send(plugin.shop_tag + "{ERR}Amount over max items per sale."); - return false; - } - - if (!data.getCanSell(requested.count)) { - message.send(plugin.shop_tag + "{ERR}" + data.getName() + " overstocked: only " + data.formatBundleCount(data.leftToSell()) + " can be sold."); - return false; - } - - if (!(Items.has(player, data, requested.count))) { - message.send(plugin.shop_tag + "{ERR}You do not have enough " + data.getName() + " to do this."); - return false; - } - - transValue = data.getSellPrice(requested.count); - - if (!freeAccount) - { - if (get_balance(accountName) < transValue) - { - message.send(plugin.shop_tag + "{ERR}Shop account does not have enough " + getCurrencyNamePlural() + " to pay for " + data.formatBundleCount(requested.count) +" "+data.getName()+"."); - return false; - } - } - - plugin.items.remove(player, data, requested.count); - - - //delta_balance(player.getName(), transValue); - //delta_balance(accountName, -transValue); - - - //try { - delta_balance(player.getName(), transValue); - //} catch (InvalidTransactionException e) { - // message.send(plugin.shop_tag + "{ERR}Transaction rejected by economy system."); - // return false; - //} - //try { - delta_balance(accountName, -transValue); - //} catch (InvalidTransactionException e) { - // message.send(plugin.shop_tag + "{ERR}Transaction rejected by economy system."); - // try { - // Roll back previous transaction. - // delta_balance(player.getName(), -transValue); - // } catch (InvalidTransactionException e1) { - // plugin.log.severe(Messaging.bracketize(plugin.name) + " Could not roll back '" + player.getName() + "' after invalid transaction with '" + accountName + "': " + e1); - // return false; - // } - //} - - - plugin.db.addStock(requested, shopLabel); - - message.send(plugin.shop_tag + "Sold {BKT}[{PRM}" + data.formatBundleCount(requested.count) + "{BKT}]{PRM} " + data.getName() + "{} for {PRM}" + transValue + " " + getCurrencyName(transValue)); - show_balance(player, message); - if (plugin.transLog.isOK) - plugin.transLog.logTransaction(player.getName() + ", Sell, " + requested.count + ", " + data.count + ", " + data.getName() + ", " + - data.itemId + ", " + data.subType + ", " + (-transValue) + ", " + (shopLabel==null?"":shopLabel) + ", " + (accountName==null?"":accountName)); - return true; - } - - private boolean shopAddItem(String itemString, Messaging message, String shopLabel) - { - MarketItem newItem = new MarketItem(itemString, plugin.db.getDefault(shopLabel), plugin.db, shopLabel); - - if (!newItem.isValid()) - { - message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); - return false; - } - - if (plugin.db.hasRecord(newItem)) - { - message.send(plugin.shop_tag + "{ERR}"+newItem.getName()+" is already in the market list."); - message.send(plugin.shop_tag + "{ERR}Use {CMD}/shop update{ERR} instead."); - return false; - } - - if ((newItem.count < 1) || (newItem.count > plugin.max_per_sale)) { - message.send(plugin.shop_tag + "{ERR}Invalid amount. (Range: 1.." + plugin.max_per_sale + ")"); - return false; - } - - if (plugin.db.add(newItem)) - { - message.send(plugin.shop_tag + "Item {PRM}" + newItem.getName() + "{} added:"); - //message.send(newItem.infoStringBuy()); - //message.send(newItem.infoStringSell()); - ArrayList thisList = newItem.infoStringFull(); - for (String thisLine : thisList) - message.send(thisLine); - return true; - } - else - { - message.send(plugin.shop_tag + "{ERR}Item {PRM}" + newItem.getName() + "{ERR} could not be added."); - return false; - } - } - - private boolean shopUpdateItem(String itemStringIn, Messaging message, String shopLabel) - { - // Make a copy of itemStringIn, in case modification is needed. - String itemString = new String(itemStringIn); - - // Check if the item name is "all". - String firstItem = itemString.split(" ",2)[0]; - String thisName = firstItem.split(":",2)[0]; - if (thisName.equalsIgnoreCase("all")) - { - // Update-all requested. - // Check bundle size first. - try - { - if (firstItem.contains(":")) - if (Integer.valueOf(firstItem.split(":",2)[1]) > plugin.max_per_sale) - { - message.send(plugin.shop_tag + "{ERR}Invalid bundle size [" +firstItem.split(":",2)[1]+ "]. (Range: 1.." + plugin.max_per_sale + ")"); - return false; - } - } - catch (NumberFormatException ex) - { - message.send(plugin.shop_tag + "{ERR}Invalid bundle size [" +firstItem.split(":",2)[1]+ "]. (Range: 1.." + plugin.max_per_sale + ")"); - return false; - } - - if (plugin.db.updateAllFromTags(itemStringIn, shopLabel)) - { - message.send(plugin.shop_tag + " All shop items updated."); - return true; - } - else - { - message.send(plugin.shop_tag + " {ERR}All shop items update failed."); - return false; - } - } - // End of update-all subsection - - // Fetch the previous record and use it as the default for parsing these string tags. - - ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); - - if (requested == null) { - message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); - return false; - } - - MarketItem prevData = plugin.db.data(requested, shopLabel); - - if (prevData == null) { - message.send(plugin.shop_tag + "{ERR}" + itemString.split(" ",2)[0] + " not found in market."); - message.send(plugin.shop_tag + "{ERR}Use {CMD}/shop add{ERR} instead."); - return false; - } - - // If no :count is input, insert it into itemString. - if (!(itemString.split(" ")[0].contains(":"))) - { - String[] itemSubStrings = itemString.split(" ", 2); - itemSubStrings[0] += ":" + prevData.count; - if (itemSubStrings.length > 1) - itemString = itemSubStrings[0] + " " + itemSubStrings[1]; - else - itemString = itemSubStrings[0]; - } - - MarketItem updated = new MarketItem(itemString, prevData, plugin.db, shopLabel); - - if ((updated.count < 1) || (updated.count > plugin.max_per_sale)) { - message.send(plugin.shop_tag + "{ERR}Invalid bundle size. (Range: 1.." + plugin.max_per_sale + ")"); - return false; - } - - if (plugin.db.update(updated)) - { - message.send(plugin.shop_tag + "Item {PRM}" + updated.getName() + "{} updated:"); - //message.send(updated.infoStringBuy()); - //message.send(updated.infoStringSell()); - ArrayList thisList = updated.infoStringFull(); - for (String thisLine : thisList) - message.send(thisLine); - return true; - } - else - { - message.send(plugin.shop_tag + "Item {PRM}" + updated.getName() + "{} update {ERR}failed."); - return false; - } - } - - private boolean shopRemoveItem(String itemString, Messaging message, String shopLabel) - { - ItemClump removed = new ItemClump(itemString, plugin.db, shopLabel); - String removedItemName = null; - - if (removed.itemId == -1) { - message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); - return false; - } - - MarketItem itemToRemove = plugin.db.data(removed, shopLabel); - - if (itemToRemove == null) - { - message.send(plugin.shop_tag + "{ERR}Item {PRM}" + removed.getName(plugin.db, shopLabel) + "{ERR} not found in market."); - return false; - } - - removedItemName = itemToRemove.getName(); - if (removedItemName == null) - removedItemName = ""; - - if (plugin.db.remove(removed, shopLabel)) - { - message.send(plugin.shop_tag + "Item " + removedItemName + " was removed."); - return true; - } - else - { - message.send(plugin.shop_tag + "Item " + removedItemName + " {ERR}could not be removed."); - return false; - } - } - - public boolean shopReset(CommandSender sender, String confirmString, String shopLabel) - { - Messaging message = new Messaging(sender); - if (confirmString.isEmpty()) - { - message.send("{ERR} Warning!{} This will DELETE AND REBUILD the shop DB."); - message.send("{} If you're sure, type: {CMD}/shop reset confirm"); - return true; - } - if (confirmString.equalsIgnoreCase("confirm")) - { - if (plugin.db.resetDatabase(shopLabel)) - { - message.send("{} Database successfully reset."); - return true; - } - else - { - message.send("{} Database {ERR}not{} successfully reset."); - return false; - } - } - message.send("{ERR} Incorrect confirmation keyword."); - return false; - } - - - public void onPlayerCommand(PlayerChatEvent event) - { - // Is this truly deprecated or not? - // Receives commands from OTHER plugins... - // but /shop seems to be handled through DynamicMarket.onCommand. - //TODO: Test further. - //plugin.log.info("OnPlayerCommand called with: " + event.getMessage()); - String base; - String[] args; - String[] msg = event.getMessage().split(" ",2); - if (msg.length > 0) - { - base = msg[0]; - if (base.startsWith("/")) - base = base.substring(1); - } - else - return; - if (msg.length > 1) - args = msg[1].split(" "); - else - args = new String[] {}; - Player player = event.getPlayer(); - if (!onCommand(player, base, "", args, "")) - { - // event.setCancelled(true)? - } - } - - - public boolean onCommand(CommandSender sender, String cmd, String commandLabel, String[] args, String shopLabel) - { - return parseCommand(sender, cmd, args, shopLabel, "", true); - } - - public boolean parseCommand(CommandSender sender, String cmd, String[] args, String shopLabel, String accountName, boolean freeAccount) - { - //String commandName = cmd.getName().toLowerCase(); - - //TODO: Show helpful errors for inappropriate numbers of arguments. - //accountName: iConomy account which receives/provides the money from/to transactions. - //freeAccount: If true, account is not checked for debt. - - //Player player = (Player) sender; - Messaging message = new Messaging(sender); - - //if (commandName.equals("shop")) { - //if (cmd.getName().toLowerCase().equals("shop")) { - if (cmd.toLowerCase().equals("shop")) { - - if (!hasPermission(sender, "access")) - { - message.send("{ERR}You do not have permission to access the shop."); - return false; - } - - if (args.length == 0) { - showHelp(sender, ""); - return true; - } - - String subCommand = args[0]; - - if ((args.length == 1) && (!(Misc.isAny(subCommand, new String[] {"list", "-l", "help", "-?", "idata", "reset", "reload", "exportdb", "importdb"})))) { - return shopShowItemInfo(args[0], message, false, shopLabel); - } - - if ((Misc.isEither(subCommand, "info", "-i")) && (args.length <= 2)) - if (args.length == 2) - return (shopShowItemInfo(args[1], message, true, shopLabel)); - - if ((Misc.isEither(subCommand, "help", "-?")) && (args.length <= 3)) { - if (args.length == 3) - return showHelp(sender, args[1] + " " + args[2]); - //else - if (args.length == 2) - return showHelp(sender, args[1]); - //else - return showHelp(sender, ""); - } - - if ((Misc.isEither(subCommand, "buy", "-b")) && (args.length >= 2)) { - if (!message.isPlayer()) - { - message.send("{ERR}Cannot purchase items without being logged in."); - return false; - } - if (!(hasPermission(sender, "buy"))) { - message.send("{ERR}You do not have permission to buy from the shop."); - return false; - } - return shopBuyItem((Player)sender, args[1], shopLabel, accountName); - } - - if ((Misc.isEither(subCommand, "sell", "-s")) && (args.length >= 2)) { - if (!message.isPlayer()) - { - message.send("{ERR}Cannot sell items without being logged in."); - return false; - } - if (!(hasPermission(sender,"sell"))) { - message.send("{ERR}You do not have permission to sell to the shop."); - return false; - } - return shopSellItem((Player)sender, args[1], shopLabel, accountName, freeAccount); - } - - if (subCommand.equalsIgnoreCase("reload")) { - if (!(hasPermission(sender,"admin"))) { - message.send("{ERR}You do not have permission to reload the shop plugin."); - return false; - } - // CHANGED: Call onDisable before calling onEnable, in case important stuff gets added to onDisable later. - plugin.onDisable(); - plugin.onEnable(); - return true; - //TODO: Make this return a more sensible success value than blind-true. - } - - if (subCommand.equalsIgnoreCase("reset")) { - if (!(hasPermission(sender,"admin"))) { - message.send("{ERR}You do not have permission to reset the shop DB."); - return false; - } - if (args.length >= 2) - return shopReset(sender, args[1], shopLabel); - else - return shopReset(sender, "", shopLabel); - } - - if (subCommand.equalsIgnoreCase("exportDB")) { - if (!(hasPermission(sender,"admin"))) { - message.send("{ERR}You do not have permission to export the shop DB."); - return false; - } - if (plugin.db.dumpToCSV(DynamicMarket.csvFilePath + shopLabel + DynamicMarket.csvFileName, shopLabel)) - { - message.send("{} Database export to {PRM}"+shopLabel+DynamicMarket.csvFileName+"{} successful."); - return true; - } - else - { - message.send("{ERR} Database export to {PRM}"+shopLabel+DynamicMarket.csvFileName+"{ERR} NOT successful."); - message.send("{ERR} See Bukkit console for details."); - return false; - } - } - - if (subCommand.equalsIgnoreCase("importDB")) - { - if (!(hasPermission(sender,"admin"))) - { - message.send("{ERR}You do not have permission to import the shop DB."); - return false; - } - if (plugin.db.inhaleFromCSV(DynamicMarket.csvFilePath + shopLabel + DynamicMarket.csvFileName, shopLabel)) - { - message.send("{} Database import from {PRM}"+shopLabel+DynamicMarket.csvFileName+"{} successful."); - return true; - } - else - { - message.send("{ERR} Database import from {PRM}"+shopLabel+DynamicMarket.csvFileName+"{ERR} NOT successful."); - message.send("{ERR} See Bukkit console for details."); - return false; - } - } - - if ((Misc.isEither(subCommand, "add", "-a")) && (args.length > 2)) - { - // /shop add [id](:count) [buy] [sell] - if (!(hasPermission(sender, "items.add"))) { - message.send("{ERR}You do not have permission to add items to the shop."); - return false; - } - return shopAddItem(Misc.combineSplit(1, args, " "), message, shopLabel); - } - - if ((Misc.isEither(subCommand, "update", "-u")) && (args.length >= 2)) - { - if (!(hasPermission(sender, "items.update"))) { - message.send("{ERR}You do not have permission to update shop items."); - return false; - } - return shopUpdateItem(Misc.combineSplit(1, args, " "), message, shopLabel); - } - - if ((Misc.isEither(subCommand, "remove", "-r")) && (args.length == 2)) - { - if (!(hasPermission(sender, "items.remove"))) { - message.send("{ERR}You do not have permission to remove shop items."); - return false; - } - return shopRemoveItem(args[1], message, shopLabel); - } - - if (Misc.isEither(subCommand, "list", "-l")) - { - // Possible inputs: - // none (default first page, unfiltered) - // pageNum - // nameFilter - // nameFilter pageNum - // TODO: Break into another method. - int pageSelect = 1; - String nameFilter = null; - if (args.length == 2) - { - try - { - pageSelect = Integer.valueOf(args[1]).intValue(); - } - catch (NumberFormatException ex) - { - nameFilter = args[1]; - } - } - if (args.length == 3) - { - nameFilter = args[1]; - try - { - pageSelect = Integer.valueOf(args[2]).intValue(); - } - catch (NumberFormatException ex) - { - pageSelect = 1; - } - } - ArrayList list = plugin.db.list(pageSelect, nameFilter, shopLabel); - ArrayList listToCount = plugin.db.list(0, nameFilter, shopLabel); - int numPages = (listToCount.size()/8 + (listToCount.size() % 8 > 0 ? 1 : 0)); - if (listToCount.isEmpty()) - { - message.send(plugin.shop_tag + "{ERR}No items are set up in the shop yet..."); - return false; - } - if (pageSelect > numPages) - { - message.send(plugin.shop_tag + "{ERR}The shop only has " + numPages + " pages of items."); - return false; - } - if (list.isEmpty()) - { - message.send(plugin.shop_tag + "{ERR}Horrors! The page calculation made a mistake!"); - return false; - } - - else { - message.send("{}Shop Items: Page {BKT}[{PRM}" + pageSelect + "{BKT}]{} of {BKT}[{PRM}" + numPages + "{BKT}]"); - for (MarketItem data : list) { - message.send(data.infoStringShort()); - } - } - return true; - } - - // If this point is reached, no subcommand was matched... - message.send("{ERR}Unknown or mangled shop command. Try {CMD}/shop help{ERR}."); - return false; - } - - // "/shop" not matched. - return false; - } - - public String getCurrencyName() - { - if (plugin.econType == EconType.ICONOMY3) - { - return plugin.currency; - } - - /* - else if (plugin.econType == EconType.ANYCONOMY) - { - try { - return plugin.anyConomy.getEconomyCurrencyName(); - } catch (NoEconRegisteredException e) { - plugin.log.warning(Messaging.bracketize(plugin.name) + " Currency name fetched before economy registered."); - return ""; - } - } - */ - else - return ""; - } - - public String getCurrencyNamePlural() - { - if (plugin.econType == EconType.ICONOMY3) - { - return plugin.currency + "s"; - } - - /* - else if (plugin.econType == EconType.ANYCONOMY) - { - try { - return plugin.anyConomy.getEconomyCurrencyNamePlural(); - } catch (NoEconRegisteredException e) { - plugin.log.warning(Messaging.bracketize(plugin.name) + " Currency name fetched before economy registered."); - return ""; - } - } - */ - else - return ""; - } - - public String getCurrencyName(int amountOfCurrency) - { - // Switches pluralization depending on quantity. - return (Math.abs(amountOfCurrency)==1?getCurrencyName():getCurrencyNamePlural()); - } - +public class iListen extends PlayerListener { + + public static DynamicMarket plugin; + + public iListen(DynamicMarket instance) { + plugin = instance; + } + + private boolean hasPermission(CommandSender sender, String permString) { + if (plugin.simplePermissions || plugin.Permissions == null) { + if (sender instanceof Player) { + if (Misc.isAny(permString, new String[]{"access", "buy", "sell"})) { + return true; + } else { + return false; + } + } else { + return true; + } + } + if (plugin.wrapperPermissions) { + if (plugin.permissionWrapper != null) { + return plugin.permissionWrapper.permission(sender, permString); + } + plugin.log.severe(Messaging.bracketize(plugin.name) + "WARNING: wrapper-permissions set, but no permission handler registered!"); + return false; + } + // Permissions not overridden. + if (sender instanceof Player) { + return Permissions.Security.permission((Player) sender, plugin.name.toLowerCase() + "." + permString); + } + return true; + } + + private boolean showHelp(CommandSender sender, String topic) { + //TODO: Migrate help system to an MCDocs-like plugin eventually. + Messaging message = new Messaging(sender); + + if (topic.isEmpty()) { + String commands = ""; + String topics = ""; + String shortcuts = ""; + message.send("{}" + Misc.headerify("{CMD} " + plugin.name + " {BKT}({CMD}" + plugin.codename + "{BKT}){} ")); + message.send("{} {BKT}(){} Optional, {PRM}<>{} Parameter"); + message.send("{CMD} /shop help {BKT}({PRM}{BKT}){} - Show help."); + message.send("{CMD} /shop {PRM}{BKT}({CMD}:{PRM}{BKT}){} - Show buy/sell info on an item."); + message.send("{CMD} /shop {PRM} {} - Use a shop command."); + commands += " list"; + shortcuts += " -? -l"; + if (hasPermission(sender, "buy")) { + commands += " buy"; + shortcuts += " -b"; + } + if (hasPermission(sender, "sell")) { + commands += " sell"; + shortcuts += " -s"; + } + + commands += " info"; + shortcuts += " -i"; + + if (hasPermission(sender, "items.add")) { + commands += " add"; + shortcuts += " -a"; + } + if (hasPermission(sender, "items.update")) { + commands += " update"; + shortcuts += " -u"; + } + if (hasPermission(sender, "items.remove")) { + commands += " remove"; + shortcuts += " -r"; + } + if (hasPermission(sender, "admin")) { + commands += " reload"; + commands += " reset"; + commands += " exportdb importdb"; + } + + topics += "ids details about"; + if (hasPermission(sender, "items.add") || hasPermission(sender, "items.update")) { + topics += " tags"; + } + + message.send("{} Commands: {CMD}" + commands); + message.send("{} Shortcuts: {CMD}" + shortcuts); + message.send("{} Other help topics: {PRM}" + topics); + return true; + } + message.send("{}" + Misc.headerify("{} " + plugin.name + " {BKT}({}" + plugin.codename + "{BKT}){} : " + topic + "{} ")); + if (topic.equalsIgnoreCase("buy")) { + if (hasPermission(sender, "buy")) { + message.send("{CMD} /shop buy {PRM}{BKT}({CMD}:{PRM}{CMD})"); + message.send("{} Buy {PRM}{} bundles of an item."); + message.send("{} If {PRM}{} is missing, buys 1 bundle."); + return true; + } + } + if (topic.equalsIgnoreCase("sell")) { + if (hasPermission(sender, "sell")) { + message.send("{CMD} /shop sell {PRM}{BKT}({CMD}:{PRM}{CMD})"); + message.send("{} Sell {PRM}{} bundles of an item."); + message.send("{} If {PRM}{} is missing, sells 1 bundle."); + return true; + } + } + if (topic.equalsIgnoreCase("info")) { + //if (hasPermission(player,"sell")) + //{ + message.send("{CMD} /shop info {PRM}"); + message.send("{} Show detailed information about a shop item."); + message.send("{} Unlike {CMD}/shop {PRM}{}, this shows ALL fields."); + return true; + //} + } + if (topic.equalsIgnoreCase("add")) { + if (hasPermission(sender, "items.add")) { + message.send("{CMD} /shop add {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT} ({PRM}{BKT})) {PRM}"); + message.send("{} Adds item {PRM}{} to the shop."); + message.send("{} Transactions will be in {PRM}{} units (default 1)."); + message.send("{PRM} {} and {PRM}{} will be converted, if used."); + message.send("{} Prices are per-bundle."); + message.send("{} See also: {CMD}/shop help tags"); + return true; + } + } + if (topic.equalsIgnoreCase("update")) { + if (hasPermission(sender, "items.update")) { + message.send("{CMD} /shop update {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT} ({PRM}{BKT})) {PRM}"); + message.send("{} Changes item {PRM}{}'s shop details."); + message.send("{PRM} {}, {PRM}{}, {PRM}{}, and {PRM}{} will be changed."); + message.send("{} Transactions will be in {PRM}{} units (default 1)."); + message.send("{} Prices are per-bundle."); + message.send("{} See also: {CMD}/shop help tags"); + return true; + } + } + if (topic.equalsIgnoreCase("remove")) { + if (hasPermission(sender, "items.remove")) { + message.send("{CMD} /shop remove {PRM}"); + message.send("{} Removes item {PRM}{} from the shop."); + return true; + } + } + if (hasPermission(sender, "admin")) { + if (topic.equalsIgnoreCase("reload")) { + message.send("{CMD} /shop reload"); + message.send("{} Restarts the shop plugin."); + message.send("{} Attempts to reload all relevant config files."); + return true; + } + if (topic.equalsIgnoreCase("reset")) { + message.send("{CMD} /shop reset"); + message.send("{} Completely resets the shop database."); + message.send("{} This will remove all items from the shop, and"); + message.send("{} create a new empty shop database."); + return true; + } + if (topic.equalsIgnoreCase("exportdb")) { + message.send("{CMD} /shop exportdb"); + message.send("{} Dumps the shop database to a .csv file."); + message.send("{} Name and location are set in the main config file."); + message.send("{} The file can be edited by most spreadsheet programs."); + return true; + } + if (topic.equalsIgnoreCase("importdb")) { + message.send("{CMD} /shop importdb"); + message.send("{} Reads a .csv file in to the shop database."); + message.send("{} Name and location are set in the main config file."); + message.send("{} The format MUST be the same as the export format."); + message.send("{} Records matching id/subtype will be updated."); + return true; + } + } + if (topic.equalsIgnoreCase("ids")) { + message.send("{} Item ID format: {PRM}{BKT}({CMD},{PRM}{BKT})({CMD}:{PRM}{BKT})"); + message.send("{PRM} {}: Full name or ID number of the item."); + message.send("{PRM} {}: Subtype of the item (default: 0)"); + message.send("{} Subtypes are used for wool/dye colours, log types, etc."); + message.send("{PRM} {}: For shop items, this specifies bundle size."); + message.send("{} For transactions, this sets the number of bundles bought or sold."); + return true; + } + if (topic.equalsIgnoreCase("list")) { + message.send("{CMD} /shop list {BKT}({PRM}{BKT}) ({PRM}{BKT})"); + message.send("{} Displays the items in the shop."); + message.send("{} List format: {BKT}[{PRM}{BKT}]{PRM} {BKT}[{PRM}{BKT}]{} Buy {BKT}[{PRM}{BKT}]{} Sell {BKT}[{PRM}{BKT}]"); + message.send("{} Page 1 is displayed by default, if no page number is given."); + message.send("{} If {PRM}{} is used, displays items containing {PRM}{}."); + return true; + } + if (topic.equalsIgnoreCase("details")) { + message.send("{CMD} /shop {PRM}{BKT}({CMD}:{PRM}{BKT})"); + message.send("{} Displays the current buy/sell price of the selected item."); + message.send("{} Since prices can fluctuate, use {PRM}{} to get batch pricing."); + message.send("{} See {CMD}/shop help ids{} for information on IDs."); + return true; + } + if ((Misc.isEither(topic.split(" ")[0], "tags", "tag")) && ((hasPermission(sender, "items.add") || hasPermission(sender, "items.update")))) { + if (topic.indexOf(" ") > -1) { + // Possible tag listed! + String thisTag = topic.split(" ")[1].replace(":", ""); + if (Misc.isEither(thisTag, "n", "name")) { + message.send("{CMD} n:{BKT}|{CMD}name:{} - Name/rename item"); + message.send("{} Sets the item's name in the shop DB."); + message.send("{} New name will persist until the item is removed."); + message.send("{} If name is blank, will try to reload the name from items.db."); + return true; + } + if (Misc.isEither(thisTag, "bp", "baseprice")) { + message.send("{CMD} bp:{BKT}|{CMD}BasePrice:{} - Base purchase price"); + message.send("{} Buy price of the item at stock level 0."); + message.send("{} All other prices are derived from this starting value."); + message.send("{} Referenced by {PRM}SalesTax{}, {PRM}Stock{}, and {PRM}Volatility{}."); + message.send("{} Soft-limited by {PRM}PriceFloor{}/{PRM}PriceCeiling{}."); + return true; + } + if (Misc.isEither(thisTag, "s", "stock")) { + message.send("{CMD} s:{BKT}|{CMD}Stock:{} - Current stock level"); + message.send("{} Stock level of this item (in bundles)."); + message.send("{} Increases/decreases when items are sold/bought."); + message.send("{} Affects buy/sell prices, if {PRM}Volatility{} > 0."); + message.send("{} Soft-limited by {PRM}StockFloor{}/{PRM}StockCeiling{}."); + message.send("{} Hard-limited (transactions fail) by {PRM}StockLowest{}/{PRM}StockHighest{}."); + return true; + } + if (Misc.isEither(thisTag, "cb", "canbuy")) { + message.send("{CMD} cb:{BKT}|{CMD}CanBuy:{} - Buyability of item"); + message.send("{} Set to 'Y', 'T', or blank to allow buying from shop."); + message.send("{} Set to 'N' or 'F' to disallow buying from shop."); + return true; + } + if (Misc.isEither(thisTag, "cs", "cansell")) { + message.send("{CMD} cs:{BKT}|{CMD}CanSell:{} - Sellability of item"); + message.send("{} Set to 'Y', 'T', or blank to allow selling to shop."); + message.send("{} Set to 'N' or 'F' to disallow selling to shop."); + return true; + } + if (Misc.isAny(thisTag, new String[]{"v", "vol", "volatility"})) { + message.send("{CMD} v:{BKT}|{CMD}Vol:{}{BKT}|{CMD}Volatility:{} - Price volatility"); + message.send("{} Percent increase in price per 1 bundle bought from shop, * 10000."); + message.send("{} v=0 prevents the price from changing with stock level."); + message.send("{} v=1 increases the price 1% per 100 bundles bought."); + message.send("{} v=10000 increases the price 100% per 1 bundle bought."); + message.send("{} Calculations are compound vs. current stock level."); + return true; + } + if (Misc.isAny(thisTag, new String[]{"iv", "ivol", "invvolatility"})) { + message.send("{CMD} iv:{BKT}|{CMD}IVol:{}{BKT}|{CMD}InvVolatility:{} - Inverse Volatility"); + message.send("{} Number of bundles bought in order to double the price."); + message.send("{} Converted to volatility when entered."); + message.send("{} iv=+INF prevents the price from changing with stock level."); + message.send("{} iv=6400 doubles the price for each 6400 items bought."); + message.send("{} iv=1 doubles the price for each item bought."); + message.send("{} Calculations are compound vs. current stock level."); + return true; + } + if (Misc.isEither(thisTag, "st", "salestax")) { + message.send("{CMD} st:{BKT}|{CMD}SalesTax:{} - Sales Tax"); + message.send("{} Percent difference between BuyPrice and SellPrice, * 100."); + message.send("{} {PRM}SellPrice{}={PRM}BuyPrice{}*(1-({PRM}SalesTax{}/100))"); + message.send("{} If {PRM}SellPrice{} is entered as an untagged value, it is used to calculate {PRM}SalesTax{}."); + message.send("{} {PRM}SalesTax{} is applied after {PRM}PriceFloor{}/{PRM}PriceCeiling{}."); + return true; + } + if (Misc.isEither(thisTag, "sl", "stocklowest")) { + message.send("{CMD} sl:{BKT}|{CMD}StockLowest:{} - Lowest stock level (hard limit)"); + message.send("{} Buying from shop will fail if it would put stock below {PRM}StockLowest{}."); + message.send("{} Set to 0 to to make stock 'finite'."); + message.send("{} Set to -INF or a negative value to use stock level as a 'relative offset'."); + return true; + } + if (Misc.isEither(thisTag, "sh", "stockhighest")) { + message.send("{CMD} sh:{BKT}|{CMD}StockHighest:{} - Highest stock level (hard limit)"); + message.send("{} Selling to shop will fail if it would put stock above {PRM}StockHighest{}."); + message.send("{} Set to +INF to let maximum stock be unlimited."); + return true; + } + if (Misc.isEither(thisTag, "sf", "stockfloor")) { + message.send("{CMD} sf:{BKT}|{CMD}StockFloor:{} - Lowest stock level (soft limit)"); + message.send("{} If {PRM}Stock{} falls below {PRM}StockFloor{}, it will be reset to {PRM}StockFloor{}."); + message.send("{} Further purchases will be at a flat rate, until {PRM}Stock{} rises."); + return true; + } + if (Misc.isEither(thisTag, "sc", "stockceiling")) { + message.send("{CMD} sc:{BKT}|{CMD}StockCeiling:{} - Highest stock level (soft limit)"); + message.send("{} If {PRM}Stock{} rises above {PRM}StockCeiling{}, it will be reset to {PRM}StockCeiling{}."); + message.send("{} Further sales will be at a flat rate, until {PRM}Stock{} falls."); + return true; + } + if (Misc.isEither(thisTag, "pf", "pricefloor")) { + message.send("{CMD} pf:{BKT}|{CMD}PriceFloor:{} - Lowest buy price (soft limit)"); + message.send("{} If {PRM}BuyPrice{} falls below {PRM}PriceFloor{}, it will be cropped at {PRM}PriceFloor{}."); + message.send("{} Buy/sell prices will be at a flat rate, until {PRM}BuyPrice{} rises above {PRM}PriceFloor{}."); + message.send("{} {PRM}PriceFloor{} is applied to {PRM}SellPrice{} before {PRM}SalesTax{}."); + return true; + } + if (Misc.isEither(thisTag, "pc", "priceceiling")) { + message.send("{CMD} pc:{BKT}|{CMD}PriceCeiling:{} - Highest buy price (soft limit)"); + message.send("{} If {PRM}BuyPrice{} rises above {PRM}PriceCeiling{}, it will be cropped at {PRM}PriceCeiling{}."); + message.send("{} Buy/sell prices will be at a flat rate, until {PRM}BuyPrice{} falls below {PRM}PriceCeiling{}."); + message.send("{} {PRM}PriceCeiling{} is applied to {PRM}SellPrice{} before {PRM}SalesTax{}."); + return true; + } + if (thisTag.equalsIgnoreCase("flat")) { + message.send("{CMD} flat{} - Set item with flat pricing."); + message.send("{} Buy/sell prices for this item will not change with stock level."); + message.send("{} Stock level WILL be tracked, and can float freely."); + message.send("{} Equivalent to: {CMD}s:0 sl:-INF sh:+INF sf:-INF sc:+INF v:0 pf:0 pc:+INF"); + return true; + } + if (thisTag.equalsIgnoreCase("fixed")) { + message.send("{CMD} fixed{} - Set item with fixed pricing."); + message.send("{} Buy/sell prices for this item will not change with transactions."); + message.send("{} Stock level WILL NOT be tracked, and {PRM}Stock{} will remain at 0."); + message.send("{} Equivalent to: {CMD}s:0 sl:-INF sh:+INF sf:0 sc:0 v:0 pf:0 pc:+INF"); + return true; + } + if (thisTag.equalsIgnoreCase("float")) { + message.send("{CMD} float{} - Set item with floating pricing."); + message.send("{} Buy/sell prices for this item will vary by stock level."); + message.send("{} If {PRM}Vol{}=0, {PRM}Vol{} will be set to a default of 100."); + message.send("{} (For finer control, set {PRM}Volatility{} to an appropriate value.)"); + message.send("{} Stock level can float freely above and below 0 with transactions."); + message.send("{} Equivalent to: {CMD}sl:-INF sh:+INF sf:-INF sc:+INF {BKT}({CMD}v:100{BKT}){CMD} pf:0 pc:+INF"); + return true; + } + if (thisTag.equalsIgnoreCase("finite")) { + message.send("{CMD} finite{} - Set item with finite stock."); + message.send("{} Buying from shop will fail if it would make {PRM}Stock{} < 0."); + message.send("{} Any number of items can be sold to the shop."); + message.send("{} Equivalent to: {CMD}sl:0 sh:+INF sf:-INF sc:+INF"); + return true; + } + if (thisTag.equalsIgnoreCase("renorm")) { + message.send("{CMD} renorm{BKT}({CMD}:{PRM}{BKT}){} - Renormalize an item's price."); + message.send("{} Resets an item's {PRM}Stock{}, while preserving its current price."); + message.send("{} Sets an item's {PRM}BasePrice{} to its current {PRM}BuyPrice{},"); + message.send("{} then sets {PRM}Stock{} to {PRM}{} (0 if blank or missing)."); + return true; + } + message.send("{ERR} Unknown tag {PRM}" + thisTag + "{ERR}."); + message.send("{ERR} Use {CMD}/shop help tags{ERR} to list tags."); + return false; + } else { + message.send("{} Tag format: {PRM}{BKT}({CMD}:{PRM}{BKT}) ({PRM}{BKT}({CMD}:{PRM}{BKT}))..."); + message.send("{} Available tags: {CMD} Name: BasePrice: SalesTax: Stock: CanBuy: CanSell: Vol: IVol:"); + message.send("{CMD} StockLowest: StockHighest: StockFloor: StockCeiling: PriceFloor: PriceCeiling:"); + message.send("{} Available preset tags: {CMD}Fixed Flat Float Finite Renorm:"); + message.send("{} Use {CMD}/shop help tag {PRM}{} for tag descriptions."); + return true; + } + } + if (topic.equalsIgnoreCase("about")) { + message.send("{} " + plugin.name + " " + plugin.version + " written by HaloInverse."); + message.send("{} Original structure and portions of code are from SimpleShop 1.1 by Nijikokun."); + return true; + } + message.send("{}Unknown help topic:{CMD} " + topic); + message.send("{}Use {CMD}/shop help{} to list topics."); + return false; + } + + private int get_balance(String name) { + if (!plugin.econLoaded) { + return 0; + } + + if ((name != null) && (!name.isEmpty())) { + if (plugin.econType == EconType.ICONOMY4) { + return (int) DynamicMarket.iConomy.getBank().getAccount(name).getBalance(); + } + } + + return 0; + } + + private void show_balance(Player player, Messaging message) { + //plugin.iC.l.showBalance(player.getName(), player, true); + int thisBalance = get_balance(player.getName()); + message.send("{} Balance: {PRM}" + thisBalance + " " + getCurrencyName(thisBalance) + (Math.abs(thisBalance) == 1 ? "" : "s")); + } + + private void delta_balance(String name, int amount) //throws InvalidTransactionException + { + if (!plugin.econLoaded) { + return; + } + if ((name != null) && (!name.isEmpty())) { + if (plugin.econType == EconType.ICONOMY4) { + Account thisAccount = DynamicMarket.iConomy.getBank().getAccount(name); + thisAccount.add(amount); + thisAccount.save(); + } + } + } + + private boolean shopShowItemInfo(String itemString, Messaging message, boolean fullInfo, String shopLabel) { + ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); + + if (!requested.isValid()) { + message.send(plugin.shop_tag + "{ERR}Unrecognized or invalid item or command."); + return false; + } + + MarketItem data = plugin.db.data(requested, shopLabel); + + if (data == null) { + message.send(plugin.shop_tag + "{ERR}Item currently not traded in shop."); + return false; + } + + message.send(plugin.shop_tag + "{}Item {PRM}" + data.getName() + "{BKT}[{PRM}" + data.idString() + "{BKT}]{} info:"); + if (fullInfo) { + ArrayList thisList = data.infoStringFull(); + for (String thisLine : thisList) { + message.send(thisLine); + } + } else { + message.send(data.infoStringBuy(requested.count)); + message.send(data.infoStringSell(requested.count)); + } + return true; + } + + private boolean shopBuyItem(Player player, String itemString, String shopLabel, String accountName) { + //TODO: Check for sufficient inventory space for received items. + ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); + Messaging message = new Messaging(player); + + int balance = get_balance(player.getName()); + + int transValue; + + if (!requested.isValid()) { + message.send(plugin.shop_tag + "{ERR}Invalid item."); + message.send("Use: {CMD}/shop buy {PRM}{BKT}({CMD}:{PRM}{BKT})"); + return false; + } + + MarketItem data = plugin.db.data(requested, shopLabel); + + if ((data == null) || !data.isValid()) { + message.send(plugin.shop_tag + "{ERR}Unrecognized item name, or not in shop."); + return false; + } + + if (data.isDefault()) { + message.send(plugin.shop_tag + "{ERR}The default item template is not buyable."); + return false; + } + + if (!data.canBuy) { + message.send(plugin.shop_tag + "{ERR}" + data.getName() + " currently not purchaseable from shop."); + return false; + } + + if (!data.getCanBuy(requested.count)) { + message.send(plugin.shop_tag + "{ERR}" + data.getName() + " understocked: only " + data.formatBundleCount(data.leftToBuy()) + " left."); + return false; + } + + if ((requested.count < 1) || (requested.count * data.count > plugin.max_per_purchase)) { + message.send(plugin.shop_tag + "{ERR}Amount over max items per purchase."); + return false; + } + + transValue = data.getBuyPrice(requested.count); + + if (balance < transValue) { + message.send(plugin.shop_tag + "{ERR}You do not have enough " + getCurrencyNamePlural() + " to do this."); + message.send(data.infoStringBuy(requested.count)); + return false; + } + + delta_balance(player.getName(), -transValue); + delta_balance(accountName, transValue); + + player.getInventory().addItem(new ItemStack[]{new ItemStack(data.itemId, requested.count * data.count, (short) 0, (byte) requested.subType)}); + + plugin.db.removeStock(requested, shopLabel); + + message.send(plugin.shop_tag + "Purchased {BKT}[{PRM}" + data.formatBundleCount(requested.count) + "{BKT}]{PRM} " + data.getName() + "{} for {PRM}" + transValue + " " + getCurrencyName(transValue)); + show_balance(player, message); + + if (plugin.transLog.isOK) { + plugin.transLog.logTransaction(player.getName() + ", Buy, " + (-requested.count) + ", " + data.count + ", " + data.getName() + ", " + + data.itemId + ", " + data.subType + ", " + transValue + ", " + (shopLabel == null ? "" : shopLabel) + ", " + (accountName == null ? "" : accountName)); + } + + return true; + } + + private boolean shopSellItem(Player player, String itemString, String shopLabel, String accountName, boolean freeAccount) { + ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); + Messaging message = new Messaging(player); + + int transValue; + + if (!requested.isValid()) { + message.send(plugin.shop_tag + "{ERR}Invalid item."); + message.send("Use: {CMD}/shop sell {PRM}{BKT}({CMD}:{PRM}{BKT})"); + return false; + } + + MarketItem data = plugin.db.data(requested, shopLabel); + + if ((data == null) || !data.isValid()) { + message.send(plugin.shop_tag + "{ERR}Unrecognized item name, or not in shop."); + return false; + } + + if (data.isDefault()) { + message.send(plugin.shop_tag + "{ERR}The default template is not sellable."); + return false; + } + + if (data.canSell == false) { + message.send(plugin.shop_tag + "{ERR}" + data.getName() + " currently not sellable to shop."); + return false; + } + + if ((requested.count < 1) || (requested.count * data.count > plugin.max_per_sale)) { + message.send(plugin.shop_tag + "{ERR}Amount over max items per sale."); + return false; + } + + if (!data.getCanSell(requested.count)) { + message.send(plugin.shop_tag + "{ERR}" + data.getName() + " overstocked: only " + data.formatBundleCount(data.leftToSell()) + " can be sold."); + return false; + } + + if (!(Items.has(player, data, requested.count))) { + message.send(plugin.shop_tag + "{ERR}You do not have enough " + data.getName() + " to do this."); + return false; + } + + transValue = data.getSellPrice(requested.count); + + if (!freeAccount) { + if (get_balance(accountName) < transValue) { + message.send(plugin.shop_tag + "{ERR}Shop account does not have enough " + getCurrencyNamePlural() + " to pay for " + data.formatBundleCount(requested.count) + " " + data.getName() + "."); + return false; + } + } + + plugin.items.remove(player, data, requested.count); + + delta_balance(player.getName(), transValue); + delta_balance(accountName, -transValue); + plugin.db.addStock(requested, shopLabel); + message.send(plugin.shop_tag + "Sold {BKT}[{PRM}" + data.formatBundleCount(requested.count) + "{BKT}]{PRM} " + data.getName() + "{} for {PRM}" + transValue + " " + getCurrencyName(transValue)); + show_balance(player, message); + + if (plugin.transLog.isOK) { + plugin.transLog.logTransaction(player.getName() + ", Sell, " + requested.count + ", " + data.count + ", " + data.getName() + ", " + + data.itemId + ", " + data.subType + ", " + (-transValue) + ", " + (shopLabel == null ? "" : shopLabel) + ", " + (accountName == null ? "" : accountName)); + } + + return true; + } + + private boolean shopAddItem(String itemString, Messaging message, String shopLabel) { + MarketItem newItem = new MarketItem(itemString, plugin.db.getDefault(shopLabel), plugin.db, shopLabel); + + if (!newItem.isValid()) { + message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); + return false; + } + + if (plugin.db.hasRecord(newItem)) { + message.send(plugin.shop_tag + "{ERR}" + newItem.getName() + " is already in the market list."); + message.send(plugin.shop_tag + "{ERR}Use {CMD}/shop update{ERR} instead."); + return false; + } + + if ((newItem.count < 1) || (newItem.count > plugin.max_per_sale)) { + message.send(plugin.shop_tag + "{ERR}Invalid amount. (Range: 1.." + plugin.max_per_sale + ")"); + return false; + } + + if (plugin.db.add(newItem)) { + message.send(plugin.shop_tag + "Item {PRM}" + newItem.getName() + "{} added:"); + //message.send(newItem.infoStringBuy()); + //message.send(newItem.infoStringSell()); + ArrayList thisList = newItem.infoStringFull(); + for (String thisLine : thisList) { + message.send(thisLine); + } + return true; + } else { + message.send(plugin.shop_tag + "{ERR}Item {PRM}" + newItem.getName() + "{ERR} could not be added."); + return false; + } + } + + private boolean shopUpdateItem(String itemStringIn, Messaging message, String shopLabel) { + // Make a copy of itemStringIn, in case modification is needed. + String itemString = new String(itemStringIn); + + // Check if the item name is "all". + String firstItem = itemString.split(" ", 2)[0]; + String thisName = firstItem.split(":", 2)[0]; + if (thisName.equalsIgnoreCase("all")) { + // Update-all requested. + // Check bundle size first. + try { + if (firstItem.contains(":")) { + if (Integer.valueOf(firstItem.split(":", 2)[1]) > plugin.max_per_sale) { + message.send(plugin.shop_tag + "{ERR}Invalid bundle size [" + firstItem.split(":", 2)[1] + "]. (Range: 1.." + plugin.max_per_sale + ")"); + return false; + } + } + } catch (NumberFormatException ex) { + message.send(plugin.shop_tag + "{ERR}Invalid bundle size [" + firstItem.split(":", 2)[1] + "]. (Range: 1.." + plugin.max_per_sale + ")"); + return false; + } + + if (plugin.db.updateAllFromTags(itemStringIn, shopLabel)) { + message.send(plugin.shop_tag + " All shop items updated."); + return true; + } else { + message.send(plugin.shop_tag + " {ERR}All shop items update failed."); + return false; + } + } + // End of update-all subsection + + // Fetch the previous record and use it as the default for parsing these string tags. + + ItemClump requested = new ItemClump(itemString, plugin.db, shopLabel); + + if (requested == null) { + message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); + return false; + } + + MarketItem prevData = plugin.db.data(requested, shopLabel); + + if (prevData == null) { + message.send(plugin.shop_tag + "{ERR}" + itemString.split(" ", 2)[0] + " not found in market."); + message.send(plugin.shop_tag + "{ERR}Use {CMD}/shop add{ERR} instead."); + return false; + } + + // If no :count is input, insert it into itemString. + if (!(itemString.split(" ")[0].contains(":"))) { + String[] itemSubStrings = itemString.split(" ", 2); + itemSubStrings[0] += ":" + prevData.count; + if (itemSubStrings.length > 1) { + itemString = itemSubStrings[0] + " " + itemSubStrings[1]; + } else { + itemString = itemSubStrings[0]; + } + } + + MarketItem updated = new MarketItem(itemString, prevData, plugin.db, shopLabel); + + if ((updated.count < 1) || (updated.count > plugin.max_per_sale)) { + message.send(plugin.shop_tag + "{ERR}Invalid bundle size. (Range: 1.." + plugin.max_per_sale + ")"); + return false; + } + + if (plugin.db.update(updated)) { + message.send(plugin.shop_tag + "Item {PRM}" + updated.getName() + "{} updated:"); + //message.send(updated.infoStringBuy()); + //message.send(updated.infoStringSell()); + ArrayList thisList = updated.infoStringFull(); + for (String thisLine : thisList) { + message.send(thisLine); + } + return true; + } else { + message.send(plugin.shop_tag + "Item {PRM}" + updated.getName() + "{} update {ERR}failed."); + return false; + } + } + + private boolean shopRemoveItem(String itemString, Messaging message, String shopLabel) { + ItemClump removed = new ItemClump(itemString, plugin.db, shopLabel); + String removedItemName = null; + + if (removed.itemId == -1) { + message.send(plugin.shop_tag + "{ERR}Unrecognized item name or ID."); + return false; + } + + MarketItem itemToRemove = plugin.db.data(removed, shopLabel); + + if (itemToRemove == null) { + message.send(plugin.shop_tag + "{ERR}Item {PRM}" + removed.getName(plugin.db, shopLabel) + "{ERR} not found in market."); + return false; + } + + removedItemName = itemToRemove.getName(); + if (removedItemName == null) { + removedItemName = ""; + } + + if (plugin.db.remove(removed, shopLabel)) { + message.send(plugin.shop_tag + "Item " + removedItemName + " was removed."); + return true; + } else { + message.send(plugin.shop_tag + "Item " + removedItemName + " {ERR}could not be removed."); + return false; + } + } + + public boolean shopReset(CommandSender sender, String confirmString, String shopLabel) { + Messaging message = new Messaging(sender); + if (confirmString.isEmpty()) { + message.send("{ERR} Warning!{} This will DELETE AND REBUILD the shop DB."); + message.send("{} If you're sure, type: {CMD}/shop reset confirm"); + return true; + } + if (confirmString.equalsIgnoreCase("confirm")) { + if (plugin.db.resetDatabase(shopLabel)) { + message.send("{} Database successfully reset."); + return true; + } else { + message.send("{} Database {ERR}not{} successfully reset."); + return false; + } + } + message.send("{ERR} Incorrect confirmation keyword."); + return false; + } + + public void onPlayerCommand(PlayerChatEvent event) { + String base; + String[] args; + String[] msg = event.getMessage().split(" ", 2); + if (msg.length > 0) { + base = msg[0]; + if (base.startsWith("/")) { + base = base.substring(1); + } + } else { + return; + } + if (msg.length > 1) { + args = msg[1].split(" "); + } else { + args = new String[]{}; + } + + Player player = event.getPlayer(); + + if (!onCommand(player, base, "", args, "")) { + // event.setCancelled(true)? + } + } + + public boolean onCommand(CommandSender sender, String cmd, String commandLabel, String[] args, String shopLabel) { + return parseCommand(sender, cmd, args, shopLabel, "", true); + } + + public boolean parseCommand(CommandSender sender, String cmd, String[] args, String shopLabel, String accountName, boolean freeAccount) { + //String commandName = cmd.getName().toLowerCase(); + + //TODO: Show helpful errors for inappropriate numbers of arguments. + //accountName: iConomy account which receives/provides the money from/to transactions. + //freeAccount: If true, account is not checked for debt. + + //Player player = (Player) sender; + Messaging message = new Messaging(sender); + + //if (commandName.equals("shop")) { + //if (cmd.getName().toLowerCase().equals("shop")) { + if (cmd.toLowerCase().equals("shop")) { + + if (!hasPermission(sender, "access")) { + message.send("{ERR}You do not have permission to access the shop."); + return false; + } + + if (args.length == 0) { + showHelp(sender, ""); + return true; + } + + String subCommand = args[0]; + + if ((args.length == 1) && (!(Misc.isAny(subCommand, new String[]{"list", "-l", "help", "-?", "idata", "reset", "reload", "exportdb", "importdb"})))) { + return shopShowItemInfo(args[0], message, false, shopLabel); + } + + if ((Misc.isEither(subCommand, "info", "-i")) && (args.length <= 2)) { + if (args.length == 2) { + return (shopShowItemInfo(args[1], message, true, shopLabel)); + } + } + + if ((Misc.isEither(subCommand, "help", "-?")) && (args.length <= 3)) { + if (args.length == 3) { + return showHelp(sender, args[1] + " " + args[2]); + } + //else + if (args.length == 2) { + return showHelp(sender, args[1]); + } + //else + return showHelp(sender, ""); + } + + if ((Misc.isEither(subCommand, "buy", "-b")) && (args.length >= 2)) { + if (!message.isPlayer()) { + message.send("{ERR}Cannot purchase items without being logged in."); + return false; + } + if (!(hasPermission(sender, "buy"))) { + message.send("{ERR}You do not have permission to buy from the shop."); + return false; + } + return shopBuyItem((Player) sender, args[1], shopLabel, accountName); + } + + if ((Misc.isEither(subCommand, "sell", "-s")) && (args.length >= 2)) { + if (!message.isPlayer()) { + message.send("{ERR}Cannot sell items without being logged in."); + return false; + } + if (!(hasPermission(sender, "sell"))) { + message.send("{ERR}You do not have permission to sell to the shop."); + return false; + } + return shopSellItem((Player) sender, args[1], shopLabel, accountName, freeAccount); + } + + if (subCommand.equalsIgnoreCase("reload")) { + if (!(hasPermission(sender, "admin"))) { + message.send("{ERR}You do not have permission to reload the shop plugin."); + return false; + } + // CHANGED: Call onDisable before calling onEnable, in case important stuff gets added to onDisable later. + plugin.onDisable(); + plugin.onEnable(); + return true; + //TODO: Make this return a more sensible success value than blind-true. + } + + if (subCommand.equalsIgnoreCase("reset")) { + if (!(hasPermission(sender, "admin"))) { + message.send("{ERR}You do not have permission to reset the shop DB."); + return false; + } + if (args.length >= 2) { + return shopReset(sender, args[1], shopLabel); + } else { + return shopReset(sender, "", shopLabel); + } + } + + if (subCommand.equalsIgnoreCase("exportDB")) { + if (!(hasPermission(sender, "admin"))) { + message.send("{ERR}You do not have permission to export the shop DB."); + return false; + } + if (plugin.db.dumpToCSV(DynamicMarket.csvFilePath + shopLabel + DynamicMarket.csvFileName, shopLabel)) { + message.send("{} Database export to {PRM}" + shopLabel + DynamicMarket.csvFileName + "{} successful."); + return true; + } else { + message.send("{ERR} Database export to {PRM}" + shopLabel + DynamicMarket.csvFileName + "{ERR} NOT successful."); + message.send("{ERR} See Bukkit console for details."); + return false; + } + } + + if (subCommand.equalsIgnoreCase("importDB")) { + if (!(hasPermission(sender, "admin"))) { + message.send("{ERR}You do not have permission to import the shop DB."); + return false; + } + if (plugin.db.inhaleFromCSV(DynamicMarket.csvFilePath + shopLabel + DynamicMarket.csvFileName, shopLabel)) { + message.send("{} Database import from {PRM}" + shopLabel + DynamicMarket.csvFileName + "{} successful."); + return true; + } else { + message.send("{ERR} Database import from {PRM}" + shopLabel + DynamicMarket.csvFileName + "{ERR} NOT successful."); + message.send("{ERR} See Bukkit console for details."); + return false; + } + } + + if ((Misc.isEither(subCommand, "add", "-a")) && (args.length > 2)) { + // /shop add [id](:count) [buy] [sell] + if (!(hasPermission(sender, "items.add"))) { + message.send("{ERR}You do not have permission to add items to the shop."); + return false; + } + return shopAddItem(Misc.combineSplit(1, args, " "), message, shopLabel); + } + + if ((Misc.isEither(subCommand, "update", "-u")) && (args.length >= 2)) { + if (!(hasPermission(sender, "items.update"))) { + message.send("{ERR}You do not have permission to update shop items."); + return false; + } + return shopUpdateItem(Misc.combineSplit(1, args, " "), message, shopLabel); + } + + if ((Misc.isEither(subCommand, "remove", "-r")) && (args.length == 2)) { + if (!(hasPermission(sender, "items.remove"))) { + message.send("{ERR}You do not have permission to remove shop items."); + return false; + } + return shopRemoveItem(args[1], message, shopLabel); + } + + if (Misc.isEither(subCommand, "list", "-l")) { + int pageSelect = 1; + String nameFilter = null; + if (args.length == 2) { + try { + pageSelect = Integer.valueOf(args[1]).intValue(); + } catch (NumberFormatException ex) { + nameFilter = args[1]; + } + } + if (args.length == 3) { + nameFilter = args[1]; + try { + pageSelect = Integer.valueOf(args[2]).intValue(); + } catch (NumberFormatException ex) { + pageSelect = 1; + } + } + ArrayList list = plugin.db.list(pageSelect, nameFilter, shopLabel); + ArrayList listToCount = plugin.db.list(0, nameFilter, shopLabel); + int numPages = (listToCount.size() / 8 + (listToCount.size() % 8 > 0 ? 1 : 0)); + if (listToCount.isEmpty()) { + message.send(plugin.shop_tag + "{ERR}No items are set up in the shop yet..."); + return false; + } + if (pageSelect > numPages) { + message.send(plugin.shop_tag + "{ERR}The shop only has " + numPages + " pages of items."); + return false; + } + if (list.isEmpty()) { + message.send(plugin.shop_tag + "{ERR}Horrors! The page calculation made a mistake!"); + return false; + } else { + message.send("{}Shop Items: Page {BKT}[{PRM}" + pageSelect + "{BKT}]{} of {BKT}[{PRM}" + numPages + "{BKT}]"); + for (MarketItem data : list) { + message.send(data.infoStringShort()); + } + } + return true; + } + + // If this point is reached, no subcommand was matched... + message.send("{ERR}Unknown or mangled shop command. Try {CMD}/shop help{ERR}."); + return false; + } + + // "/shop" not matched. + return false; + } + + public String getCurrencyName() { + if (plugin.econType == EconType.ICONOMY4) { + return plugin.currency; + } else { + return ""; + } + } + + public String getCurrencyNamePlural() { + if (plugin.econType == EconType.ICONOMY4) { + return plugin.currency + "s"; + } else { + return ""; + } + } + + public String getCurrencyName(int amountOfCurrency) { + // Switches pluralization depending on quantity. + return (Math.abs(amountOfCurrency) == 1 ? getCurrencyName() : getCurrencyNamePlural()); + } } diff --git a/src/com/gmail/haloinverse/DynamicMarket/iProperty.java b/src/com/gmail/haloinverse/DynamicMarket/iProperty.java index 5e72f63..079675a 100644 --- a/src/com/gmail/haloinverse/DynamicMarket/iProperty.java +++ b/src/com/gmail/haloinverse/DynamicMarket/iProperty.java @@ -1,197 +1,186 @@ package com.gmail.haloinverse.DynamicMarket; -/* */ //package com.nijikokun.bukkit.SimpleShop; -/* */ -/* */ import java.io.BufferedReader; -/* */ import java.io.File; -/* */ import java.io.FileInputStream; -/* */ import java.io.FileOutputStream; -/* */ import java.io.FileReader; -/* */ import java.io.IOException; -/* */ import java.util.HashMap; -/* */ import java.util.Map; -/* */ import java.util.Properties; -/* */ import java.util.logging.Level; - import java.util.logging.Logger; -/* */ -/* */ public final class iProperty -/* */ { -/* 42 */ private static final Logger log = Logger.getLogger("Minecraft"); -/* */ private Properties properties; -/* */ private String fileName; -/* */ -/* */ public iProperty(String fileName) -/* */ { -/* 47 */ this.fileName = fileName; -/* 48 */ this.properties = new Properties(); -/* 49 */ File file = new File(fileName); -/* */ -/* 51 */ if (file.exists()) -/* 52 */ load(); -/* */ else -/* 54 */ save(); -/* */ } -/* */ -/* */ public void load() -/* */ { -/* */ try { -/* 60 */ this.properties.load(new FileInputStream(this.fileName)); -/* */ } catch (IOException ex) { -/* 62 */ log.log(Level.SEVERE, "Unable to load " + this.fileName, ex); -/* */ } -/* */ } -/* */ -/* */ public void save() { -/* */ try { -/* 68 */ this.properties.store(new FileOutputStream(this.fileName), "Minecraft Properties File"); -/* */ } catch (IOException ex) { -/* 70 */ log.log(Level.SEVERE, "Unable to save " + this.fileName, ex); -/* */ } -/* */ } -/* */ -/* */ public Map returnMap() throws Exception { -/* 75 */ Map map = new HashMap(); -/* 76 */ BufferedReader reader = new BufferedReader(new FileReader(this.fileName)); -/* */ -/* */ String line; -/* 78 */ while ((line = reader.readLine()) != null) -/* */ { -/* 79 */ if (line.trim().length() == 0) { -/* */ continue; -/* */ } -/* 82 */ if (line.charAt(0) == '#') { -/* */ continue; -/* */ } -/* 85 */ int delimPosition = line.indexOf(61); // '=' -/* 86 */ String key = line.substring(0, delimPosition).trim(); -/* 87 */ String value = line.substring(delimPosition + 1).trim(); -/* 88 */ map.put(key, value); -/* */ } -/* 90 */ reader.close(); -/* 91 */ return map; -/* */ } -/* */ -/* */ public void removeKey(String key) { -/* 95 */ this.properties.remove(key); -/* 96 */ save(); -/* */ } -/* */ -/* */ public boolean keyExists(String key) { -/* 100 */ return this.properties.containsKey(key); -/* */ } -/* */ -/* */ public String getString(String key) { -/* 104 */ if (this.properties.containsKey(key)) { -/* 105 */ return this.properties.getProperty(key); -/* */ } -/* */ -/* 108 */ return ""; -/* */ } -/* */ -/* */ public String getString(String key, String value) { -/* 112 */ if (this.properties.containsKey(key)) { -/* 113 */ return this.properties.getProperty(key); -/* */ } -/* 115 */ setString(key, value); -/* 116 */ return value; -/* */ } -/* */ -/* */ public void setString(String key, String value) { -/* 120 */ this.properties.setProperty(key, value); -/* 121 */ save(); -/* */ } -/* */ -/* */ public int getInt(String key) { -/* 125 */ if (this.properties.containsKey(key)) { -/* 126 */ return Integer.parseInt(this.properties.getProperty(key)); -/* */ } -/* */ -/* 129 */ return 0; -/* */ } -/* */ -/* */ public int getInt(String key, int value) { -/* 133 */ if (this.properties.containsKey(key)) { -/* 134 */ return Integer.parseInt(this.properties.getProperty(key)); -/* */ } -/* */ -/* 137 */ setInt(key, value); -/* 138 */ return value; -/* */ } -/* */ -/* */ public void setInt(String key, int value) { -/* 142 */ this.properties.setProperty(key, String.valueOf(value)); -/* 143 */ save(); -/* */ } -/* */ -/* */ public double getDouble(String key) { -/* 147 */ if (this.properties.containsKey(key)) { -/* 148 */ return Double.parseDouble(this.properties.getProperty(key)); -/* */ } -/* */ -/* 151 */ return 0.0D; -/* */ } -/* */ -/* */ public double getDouble(String key, double value) { -/* 155 */ if (this.properties.containsKey(key)) { -/* 156 */ return Double.parseDouble(this.properties.getProperty(key)); -/* */ } -/* */ -/* 159 */ setDouble(key, value); -/* 160 */ return value; -/* */ } -/* */ -/* */ public void setDouble(String key, double value) { -/* 164 */ this.properties.setProperty(key, String.valueOf(value)); -/* 165 */ save(); -/* */ } -/* */ -/* */ public long getLong(String key) { -/* 169 */ if (this.properties.containsKey(key)) { -/* 170 */ return Long.parseLong(this.properties.getProperty(key)); -/* */ } -/* */ -/* 173 */ return 0L; -/* */ } -/* */ -/* */ public long getLong(String key, long value) { -/* 177 */ if (this.properties.containsKey(key)) { -/* 178 */ return Long.parseLong(this.properties.getProperty(key)); -/* */ } -/* */ -/* 181 */ setLong(key, value); -/* 182 */ return value; -/* */ } -/* */ -/* */ public void setLong(String key, long value) { -/* 186 */ this.properties.setProperty(key, String.valueOf(value)); -/* 187 */ save(); -/* */ } -/* */ -/* */ public boolean getBoolean(String key) { -/* 191 */ if (this.properties.containsKey(key)) { -/* 192 */ return Boolean.parseBoolean(this.properties.getProperty(key)); -/* */ } -/* */ -/* 195 */ return false; -/* */ } -/* */ -/* */ public boolean getBoolean(String key, boolean value) { -/* 199 */ if (this.properties.containsKey(key)) { -/* 200 */ return Boolean.parseBoolean(this.properties.getProperty(key)); -/* */ } -/* */ -/* 203 */ setBoolean(key, value); -/* 204 */ return value; -/* */ } -/* */ -/* */ public void setBoolean(String key, boolean value) { -/* 208 */ this.properties.setProperty(key, String.valueOf(value)); -/* 209 */ save(); -/* */ } -/* */ } - -/* Location: C:\Program Files\eclipse\Bukkit\SimpleShop.jar - * Qualified Name: com.nijikokun.bukkit.SimpleShop.iProperty - * Java Class Version: 5 (49.0) - * JD-Core Version: 0.5.3 - */ \ No newline at end of file +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class iProperty { + + private static final Logger log = Logger.getLogger("Minecraft"); + private Properties properties; + private String fileName; + + public iProperty(String fileName) { + this.fileName = fileName; + this.properties = new Properties(); + File file = new File(fileName); + + if (file.exists()) { + load(); + } else { + save(); + } + } + + public void load() { + try { + this.properties.load(new FileInputStream(this.fileName)); + } catch (IOException ex) { + log.log(Level.SEVERE, "Unable to load " + this.fileName, ex); + } + } + + public void save() { + try { + this.properties.store(new FileOutputStream(this.fileName), "Minecraft Properties File"); + } catch (IOException ex) { + log.log(Level.SEVERE, "Unable to save " + this.fileName, ex); + } + } + + public Map returnMap() throws Exception { + Map map = new HashMap(); + BufferedReader reader = new BufferedReader(new FileReader(this.fileName)); + String line; + while ((line = reader.readLine()) != null) { + if (line.trim().length() == 0) { + continue; + } + if (line.charAt(0) == '#') { + continue; + } + int delimPosition = line.indexOf('='); + String key = line.substring(0, delimPosition).trim(); + String value = line.substring(delimPosition + 1).trim(); + map.put(key, value); + } + reader.close(); + return map; + } + + public void removeKey(String key) { + this.properties.remove(key); + save(); + } + + public boolean keyExists(String key) { + return this.properties.containsKey(key); + } + + public String getString(String key) { + if (this.properties.containsKey(key)) { + return this.properties.getProperty(key); + } + + return ""; + } + + public String getString(String key, String value) { + if (this.properties.containsKey(key)) { + return this.properties.getProperty(key); + } + setString(key, value); + return value; + } + + public void setString(String key, String value) { + this.properties.setProperty(key, value); + save(); + } + + public int getInt(String key) { + if (this.properties.containsKey(key)) { + return Integer.parseInt(this.properties.getProperty(key)); + } + + return 0; + } + + public int getInt(String key, int value) { + if (this.properties.containsKey(key)) { + return Integer.parseInt(this.properties.getProperty(key)); + } + + setInt(key, value); + return value; + } + + public void setInt(String key, int value) { + this.properties.setProperty(key, String.valueOf(value)); + save(); + } + + public double getDouble(String key) { + if (this.properties.containsKey(key)) { + return Double.parseDouble(this.properties.getProperty(key)); + } + + return 0; + } + + public double getDouble(String key, double value) { + if (this.properties.containsKey(key)) { + return Double.parseDouble(this.properties.getProperty(key)); + } + + setDouble(key, value); + return value; + } + + public void setDouble(String key, double value) { + this.properties.setProperty(key, String.valueOf(value)); + save(); + } + + public long getLong(String key) { + if (this.properties.containsKey(key)) { + return Long.parseLong(this.properties.getProperty(key)); + } + + return 0; + } + + public long getLong(String key, long value) { + if (this.properties.containsKey(key)) { + return Long.parseLong(this.properties.getProperty(key)); + } + + setLong(key, value); + return value; + } + + public void setLong(String key, long value) { + this.properties.setProperty(key, String.valueOf(value)); + save(); + } + + public boolean getBoolean(String key) { + if (this.properties.containsKey(key)) { + return Boolean.parseBoolean(this.properties.getProperty(key)); + } + + return false; + } + + public boolean getBoolean(String key, boolean value) { + if (this.properties.containsKey(key)) { + return Boolean.parseBoolean(this.properties.getProperty(key)); + } + + setBoolean(key, value); + return value; + } + + public void setBoolean(String key, boolean value) { + this.properties.setProperty(key, String.valueOf(value)); + save(); + } +}