Hello, everyone! You may have seen a showcase of this auction system a few months ago when I had developed it for a server, but I ended up losing the code with no one else having it, so I decided to rewrite it and release it. Upon rewriting it, I have made it
a lot more efficient than it once was. However, nothing is perfect, and this is no exception, but I've decided to release it anyway. As a warning, most of the code will have to be refactored to be compatible with your base, so I highly recommend using an IDE such as Eclipse or Intellij to work with.
Old Showcase:
http://www.rune-server.org/runescape...ng-system.html
Sprite Needed:
http://i.imgur.com/29vl5cM.png
Client Sided
Add these methods into RSInterface.java:
Code:
public static void auctionSystem(TextDrawingArea[] tda) {
RSInterface rsinterface = addTabInterface(12002);
setChildren(30, rsinterface);
for (int i = 0; i < 25; i += 6) {
addTransparentSprite(12003 + i, 0, PATH_TO_SPRITE, 150);
addText(12004 + i, "A: ", tda, 0, 0xFFFFFF, false, true);
addText(12005 + i, "B: ", tda, 0, 0xFFFFFF, false, true);
addText(12006 + i, "Bid: ", tda, 0, 0xFFFFFF, false, true);
addText(12007 + i, "Time Left ", tda, 0, 0xFFFFFF, false, true);
addItemOnInterface(12008 + i, 12003 + i, new String[] { null });
setBounds(12003 + i, 2, 267 - ((int) (i * 11) + 1), 0 + i, rsinterface);
setBounds(12004 + i, 59, 277 - ((int) (i * 11) + 1), 1 + i, rsinterface);
setBounds(12005 + i, 59, 289 - ((int) (i * 11) + 1), 2 + i, rsinterface);
setBounds(12006 + i, 59, 301 - ((int) (i * 11) + 1), 3 + i, rsinterface);
setBounds(12007 + i, 59, 313 - ((int) (i * 11) + 1), 4 + i, rsinterface);
setBounds(12008 + i, 16, 284 - ((int) (i * 11) + 1), 5 + i, rsinterface);
}
}
public static void addTransparentSprite(int id, int spriteId, String spriteName, int opacity) {
RSInterface tab = interfaceCache[id] = new RSInterface();
tab.id = id;
tab.parentID = id;
tab.type = 5;
tab.atActionType = 0;
tab.contentType = 0;
tab.aByte254 = (byte) 0;
tab.mOverInterToTrigger = 52;
tab.sprite1 = imageLoader(spriteId, spriteName);
tab.sprite2 = imageLoader(spriteId, spriteName);
tab.width = 512;
tab.height = 334;
tab.opacity = (byte) opacity;
tab.drawsTransparent = true;
}
public static void addItemOnInterface(int childId, int interfaceId, String[] options) {
RSInterface rsi = interfaceCache[childId] = new RSInterface();
rsi.actions = new String[10];
rsi.spritesX = new int[20];
rsi.inv = new int[30];
rsi.invStackSizes = new int[25];
rsi.spritesY = new int[20];
rsi.children = new int[0];
rsi.childX = new int[0];
rsi.childY = new int[0];
for (int i = 0; i < rsi.actions.length; i++) {
if (i < options.length) {
if (options[i] != null) {
rsi.actions[i] = options[i];
}
}
}
rsi.centerText = true;
rsi.drawsTransparent = false;
rsi.usableItemInterface = false;
rsi.isInventoryInterface = false;
rsi.invSpritePadX = 23;
rsi.invSpritePadY = 22;
rsi.height = 5;
rsi.width = 6;
rsi.parentID = childId;
rsi.id = interfaceId;
rsi.type = 2;
}
Then add the following to the bottom of the unpack() method in RSInterface.java:
Code:
auctionSystem(textDrawingAreas);
You can now close RSInterface.java and move over to (c/C)lient.java and declare these variables:
Code:
public boolean isActive[] = new boolean[5];
public int auctionNumber = -1;
public int auctionInterfaces[] = new int[5];
After, navigate to your drawInterface() method and find this or something similar to it:
Code:
for (int r = 0; r < runeChildren.length; r++)
if (class9_1.id == runeChildren[r])
class9_1.modelZoom = 775;
Directly below that ^, add the following:
Code:
boolean allow = true;
for (int i = 0; i < 5; i++) {
if (class9_1.id != auctionInterfaces[i]) {
continue;
}
if (!isActive[i]) {
allow = false;
break;
}
}
if (!allow) {
continue;
}
Then, find "case 126:" in the parsePacket() method in the same class, and add the following:
Code:
if (frame == 69) {
try {
String[] args = text.split(":");
auctionNumber = Integer.parseInt(args[0]) - 1;
auctionInterfaces[auctionNumber] = Integer.parseInt(args[1]);
isActive[auctionNumber] = Boolean.parseBoolean(args[2]);
if (!isActive[auctionNumber]) {
for (int i2 = 0; i2 < 4; i2++) {
RSInterface.interfaceCache[auctionInterfaces[auctionNumber] + i2 + 1].message = "";
}
}
} catch (Exception e) {
e.printStackTrace();
}
pktType = -1;
return true;
}
You're now done with the client-sided code
Server Sided
Add the following classes anywhere, but make sure you change the package names accordingly:
Code:
package game.player.content.auction;
/**
*
* @author Jacob | 3clipse
*
*/
public class Auction {
/**
* Holds the current (in)active auctions.
*/
public static AuctionItem[] auctions = new AuctionItem[5];
/**
* Initializes the auctions when the server starts.
*/
public static void initialize() {
for (int i = 0; i < 25; i += 6) {
auctions[i / 6] = new AuctionItem(i / 6 + 1, null, null, 0, 12003 + i, false);
}
}
/**
* Returns the amount of running auctions created by a specific player.
*
* @param playerName
* @return
*/
public static int getActiveAuctions(String playerName) {
int counter = 0;
for (AuctionItem a : auctions) {
if (a.getAuctioneer() == null || !a.isActive()) {
continue;
}
if (a.getAuctioneer().playerName.equals(playerName)) {
counter++;
}
}
return counter;
}
/**
* Returns the maximum amount of auctions a player can create.
*
* @param playerRights
* @return
*/
public static int getMaximumAuctions(int playerRights) {
switch (playerRights) {
case 8:
return 2;
case 5:
return 3;
case 7:
return 4;
case 6:
default:
return 5;
}
}
}
Code:
package game.player.content.auction;
import java.util.Stack;
import game.item.GameItem;
import game.player.Client;
/**
*
* @author Jacob | 3clipse
*
*/
public class AuctionItem {
/**
* The number of the auction.
*/
private int auctionNumber;
/**
* The player holding the auction.
*/
private Client auctioneer;
/**
* The item being auctioned.
*/
private GameItem item;
/**
* Seconds the auction lasts.
*/
private int time;
/**
* The interfaceID of the auction.
*/
private int interfaceID;
/**
* Whether or not the auction is active.
*/
private boolean isActive;
/**
* The wait time of the auction's time decrementing.
*/
private long waitTime;
/**
* A stack holding the bidders on the auction.
*/
private Stack<Bid> bidders = new Stack<Bid>();
/**
* The constructor for an individual auction.
*
* @param player
* @param item
*/
public AuctionItem(int auctionNumber, Client auctioneer, GameItem item, int startingBid, int interfaceID, boolean isActive) {
this.auctionNumber = auctionNumber;
this.auctioneer = auctioneer;
this.item = item;
this.time = 180;
this.bidders.push(new Bid(auctioneer, startingBid));
this.interfaceID = interfaceID;
this.isActive = isActive;
}
/**
* Returns the auction number.
*
* @return
*/
public int getAuctionNumber() {
return this.auctionNumber;
}
/**
* Returns the player hosting the auction.
*
* @return
*/
public Client getAuctioneer() {
return this.auctioneer;
}
/**
* Returns the item being auctioned.
*
* @return
*/
public GameItem getItem() {
return this.item;
}
/**
* Returns the time left in the auction.
*
* @return
*/
public int getTime() {
return this.time;
}
/**
* Returns the formatted time left in the auction.
*
* @return
*/
public String getFormattedTime() {
return "@gre@" + this.time / 60 + "@whi@:@gre@" + (this.time % 60 < 10 ? "0" : "") + this.time % 60;
}
/**
* Returns the interface ID of the auction.
*
* @return
*/
public int getInterfaceID() {
return this.interfaceID;
}
/**
* Returns whether the auction is active or not.
*
* @return
*/
public boolean isActive() {
return this.isActive;
}
/**
* Returns the wait time for the auction's time to decrement.
*
* @return
*/
public long getWaitTime() {
return this.waitTime;
}
/**
* Returns the stack of bidders on the auction.
*
* @return
*/
public Stack<Bid> getBidders() {
return this.bidders;
}
/**
* Sets the time for the auction.
*
* @param time
*/
public void setTime(int time) {
this.time = time;
}
/**
* Sets the auction to (in)active.
*
* @param isActive
*/
public void setActive(boolean isActive) {
this.isActive = isActive;
}
/**
* Sets the wait time for the auction's time to decrement.
*
* @return
*/
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
}
}
Code:
package game.player.content.auction;
import game.player.Client;
/**
*
* @author Jacob | 3clipse
*
*/
public class Bid {
/**
* Represents the bidder.
*/
private Client bidder;
/**
* Represents the bid.
*/
private int bid;
public Bid(Client bidder, int bid) {
this.bidder = bidder;
this.bid = bid;
}
/**
* Returns the bidder.
*
* @return
*/
public Client getBidder() {
return this.bidder;
}
/**
* Returns the bid.
*
* @return
*/
public int getBid() {
return this.bid;
}
}
In your server's main class, add the following in it's tick method:
Code:
try {
for (Player p : PlayerHandler.players) {
if (p == null) {
continue;
}
Client player = (Client) p;
for (int i = 0; i < Auction.auctions.length; i++) {
AuctionItem a = Auction.auctions[i];
if (a.isActive()) {
if (System.currentTimeMillis() - a.getWaitTime() >= 1000) {
a.setWaitTime(System.currentTimeMillis());
a.setTime(a.getTime() - 1);
}
int interfaceID = a.getInterfaceID() + 1;
player.getPA().sendFrame126("Auction #@gre@" + a.getAuctionNumber(), interfaceID++);
player.getPA().sendFrame126("Bidder: @gre@" + a.getBidders().peek().getBidder().playerName, interfaceID++);
player.getPA().sendFrame126("Bid: @gre@" + a.getBidders().peek().getBid() + " @whi@GP", interfaceID++);
player.getPA().sendFrame126("Time Left " + a.getFormattedTime(), interfaceID++);
player.getPA().sendFrame34a(interfaceID++, a.getItem().id, 0, a.getItem().amount);
if (a.getTime() == 0) {
a.setActive(false);
interfaceID = a.getInterfaceID() + 1;
for (int j = 0; j < 3; j++) {
player.getPA().sendFrame126("", interfaceID++);
}
while (!a.getBidders().empty() && a.getBidders().peek() == null) {
for (Player p2 : PlayerHandler.players) {
if (p2 == null) {
continue;
}
((Client) p2).sendMessage("Because <col=255>" + a.getBidders().pop().getBidder().playerName + " <col=0>has " +
"disconnected, <col=255>" + a.getBidders().peek().getBidder().playerName + " <col=0>is now the highest " +
"bidder!");
}
}
if (a.getBidders().peek().getBidder() == a.getAuctioneer()) {
a.getAuctioneer().sendMessage("Unfortunately no one has bid on your item(s)!");
if (!ItemAssistant.addItem(a.getAuctioneer(), a.getItem().id, a.getItem().amount)) {
ItemAssistant.addItemToBank(a.getAuctioneer(), a.getItem().id, a.getItem().amount);
a.getAuctioneer().sendMessage("Your item(s) have been added into your bank!");
} else {
a.getAuctioneer().sendMessage("Your item(s) have been added back into your inventory!");
}
} else {
for (Player p2 : PlayerHandler.players) {
if (p2 == null) {
continue;
}
((Client) p2).sendMessage("<col=255>" + a.getBidders().peek().getBidder().playerName + " <col=0>has won <col=255>" +
a.getAuctioneer().playerName + "'s <col=0>auction!");
}
if (!ItemAssistant.addItem(a.getBidders().peek().getBidder(), a.getItem().id, a.getItem().amount)) {
ItemAssistant.addItemToBank(a.getBidders().peek().getBidder(), a.getItem().id, a.getItem().amount);
a.getBidders().peek().getBidder().sendMessage("Your item(s) have been added into your bank!");
} else {
a.getBidders().peek().getBidder().sendMessage("Your item(s) have been added back into your inventory!");
}
if (ItemAssistant.freeSlots(a.getAuctioneer()) > 0 || ItemAssistant.hasItemInInventory(a.getAuctioneer(), 5021)) {
ItemAssistant.addItem(a.getAuctioneer(), 995, a.getBidders().peek().getBid());
a.getAuctioneer().sendMessage("Your GP has been sent to your inventory!");
} else {
ItemAssistant.addItemToBank(a.getAuctioneer(), 995, a.getBidders().peek().getBid());
a.getAuctioneer().sendMessage("Your GP has been sent to your bank!");
}
}
a = new AuctionItem(a.getAuctionNumber(), null, null, 0, a.getInterfaceID(), false);
}
}
player.getPA().sendFrame126(a.getAuctionNumber() + ":" + a.getInterfaceID() + ":" + a.isActive(), 69);
}
if (!player.inWilderness() && player.getGameFrame().isVisible(-1)) {
player.getPA().walkableInterface(12002);
}
}
} catch (Exception e) {
e.printStackTrace();
}
In the same class, add this line where the server starts up:
Code:
Auction.initialize();
For the next part, you'll need to find something similar to the following in your PlayerAssistant class:
Code:
player.getPA().walkableInterface(-1);
And replace it with the following:
Code:
int counter = 0;
for (AuctionItem a : Auction.auctions) {
if (a.isActive()) {
counter++;
}
}
if (counter == 0) {
player.getPA().walkableInterface(-1);
}
Finally, add the following commands:
Code:
if (playerCommand.startsWith("auction")) {
try {
if (player.playerRights == 0) {
player.sendMessage("You must donate to be able to start auctions!");
return;
}
String[] args = playerCommand.split(" ");
if (args.length != 4) {
player.sendMessage("Usage -> ::auction item_id item_amount start_bid");
return;
}
if (Auction.getActiveAuctions(player.playerName) == Auction.getMaximumAuctions(player.playerRights)) {
player.sendMessage("You aren't allowed to create any more auctions at the moment!");
return;
}
int itemID = 0;
int amount = Integer.parseInt(args[2]);
if (amount <= 0 || amount > Integer.MAX_VALUE) {
player.sendMessage("You can't auction off that amount!");
return;
}
if (Misc.isNumber(args[1])) {
itemID = Integer.parseInt(args[1]);
} else {
for (ItemList i : Server.itemHandler.ItemList) {
if (i == null) {
continue;
}
if (i.itemName.replaceAll("_", " ").equalsIgnoreCase(args[1].replaceAll("_", " "))) {
itemID = i.itemId;
break;
}
}
}
if (itemID <= 0 || itemID > ServerConstants.MAX_ITEM_ID) {
player.sendMessage("It seems that you've entered the item name incorrectly.");
return;
}
final GameItem item = new GameItem(itemID, Integer.parseInt(args[2]));
if (!ItemAssistant.playerHasItem(player, item.id, item.amount)) {
player.sendMessage("You don't have that item or amount of that item in your inventory!");
return;
}
final int startingBid = Integer.parseInt(args[3]);
if (item.stackable) {
ItemAssistant.deleteStackableItemFromInventory(player, item.id, item.amount);
} else {
ItemAssistant.deleteNonStackableItemFromInventory(player, item.id, item.amount);
}
for (int i = 0; i < Auction.auctions.length; i++) {
if (!Auction.auctions[i].isActive()) {
Auction.auctions[i] = new AuctionItem(Auction.auctions[i].getAuctionNumber(), player, item, startingBid, Auction.auctions[i].getInterfaceID(), true);
final AuctionItem a = Auction.auctions[i];
player.getPA().sendFrame126((i + 1) + ":" + a.getInterfaceID() + ":" + a.isActive(), 69);
break;
}
}
} catch (Exception e) {
player.sendMessage("Usage -> ::auction item_id item_amount start_bid");
}
}
if (playerCommand.startsWith("bid")) {
try {
String[] args = playerCommand.split(" ");
if (args.length != 3) {
player.sendMessage("Usage -> ::bid auction_# bid_amount");
return;
}
final int auctionNumber = Integer.parseInt(args[1]);
if (auctionNumber <= 0 || auctionNumber > 5) {
player.sendMessage("Please enter an Auction # between 1 and 5");
return;
}
final AuctionItem a = Auction.auctions[auctionNumber];
if (!a.isActive()) {
player.sendMessage("The auction you are attempting to bid on is not active!");
return;
}
if (a.getAuctioneer() == player) {
player.sendMessage("You can't bid on an auction you created!");
return;
}
if (a.getBidders().empty()) {
player.sendMessage("You are already the highest bidder on that auction!");
return;
}
final int newBid = Integer.parseInt(args[2]);
if (newBid <= a.getBidders().peek().getBid()) {
player.sendMessage("Your bid must be higher than the current bid!");
return;
}
if (!ItemAssistant.playerHasItem(player, 995, newBid)) {
player.sendMessage("You don't have enough GP to bid that amount!");
return;
}
ItemAssistant.checkAndDeleteFromInventory(player, 995, newBid);
a.getBidders().push(new Bid(player, newBid));
} catch (Exception e) {
player.sendMessage("Usage -> ::bid auction_# bid_amount");
}
}
If you've added everything and refactored to your base correctly, you should now have the picture shown below after starting 5 separate auctions.
If you don't know how to start or bid on an auction, do either ::auction or ::bid respectively.
If I have forgotten something, please don't hesitate to either post below or PM me.
NOTE: This
does support item names and IDs, but the space characters in the name (" ") need to be replaced with ("_").