*
Disclaimer
This replaces the addHpOrb() addPrayerOrb() addRunOrb() add4thOrb(), all the hardcoded menus and client side button (toggle) management.
The outcome is the same as the old system with slightly better performance.
For anyone who asks or questions why, this was a challenge from myself to see if it could be done.
I released this for anyone who may be interested to see/learn how more complex interfaces could be created.
If you read this, thank you. If not, I wouldn't bother scrolling down any further.
Sprites
Sprite class:
Code:
public void flipHorizontally() {
int[] des = new int[myWidth * myHeight];
int pos = 0;
for (int h = 0; h < myHeight; h++) {
for (int w = myWidth - 1; w >= 0; w--)
des[pos++] = myPixels[w + h * myWidth];
}
myPixels = des;
drawOffsetX = maxWidth - myWidth - drawOffsetX;
}
Client class:
Code:
public Sprite flippedOrb, flippedOrbH;
Code:
flippedOrb = null;
flippedOrbH = null;
Code:
flippedOrb = new Sprite(mediaArchive, "orbicons", 1);
flippedOrb.flipHorizontally();
flippedOrbH = new Sprite(mediaArchive, "orbicons", 2);
flippedOrbH.flipHorizontally();
Code:
public final int orbColor(Widget widget, String text) {
int index = widget.contentType;
if(index == 675) {
switch(widget.id) {
case 10298:
case 10302:
case 10306:
case 10310:
return calcOrbValue(widget, text);
}
}
return 0x0;
}
public int currentOrbValue;
public int maximumOrbValue;
public int valueToPercent;
public final int calcOrbValue(Widget widget, String text) {
currentOrbValue = Integer.parseInt(text);
maximumOrbValue = executeScript(widget.interfaceCache[widget.id], 1);
valueToPercent = (int) (((double) currentOrbValue / (double) maximumOrbValue) * 100D);
return (valueToPercent >= 75 && valueToPercent <= Integer.MAX_VALUE ? 65280
: valueToPercent < 75 && valueToPercent >= 50 ? 0xFFFF00
: valueToPercent < 50 && valueToPercent >= 25 ? 0xFCA607 : 0xF50D0D);
}
public final int calcDrainRate(Widget widget) {
currentOrbValue = executeScript(widget.interfaceCache[widget.id + (widget.hoverType == 52 ? 1 : 3)], 0);
maximumOrbValue = executeScript(widget.interfaceCache[widget.id + (widget.hoverType == 52 ? 1 : 3)], 1);
valueToPercent = (int) (((double) currentOrbValue / (double) maximumOrbValue) * 100D);
return widget.defaultOrb.myHeight - (int) ((double) widget.defaultOrb.myHeight * ((double) valueToPercent / 100D));
}
public final boolean calcPercent(Widget widget) {
currentOrbValue = executeScript(widget.interfaceCache[widget.id + (widget.hoverType == 52 ? 1 : 3)], 0);
maximumOrbValue = executeScript(widget.interfaceCache[widget.id + (widget.hoverType == 52 ? 1 : 3)], 1);
valueToPercent = (int) (((double) currentOrbValue / (double) maximumOrbValue) * 100D);
return valueToPercent < 25 ? true : false;
}
After this loop,
Code:
for (int l6 = _y + textDrawingArea.anInt1497; text.length() > 0; l6 += textDrawingArea.anInt1497) {
Code:
if(childInterface.enableOrbs) {
if(childInterface.contentType > 0)
colour = orbColor(childInterface, text);
if(childInterface.flipOrb) {
_x = _x + 27;
} else
_x = _x;
}
Code:
else if (childInterface.type == Widget.TYPE_SPRITE) {
Sprite sprite = (interfaceIsSelected(childInterface) ? childInterface.enabledSprite : childInterface.disabledSprite);
//sprite outlining
if (spellSelected == 1 && childInterface.id == spellId && spellId != 0 && sprite != null) {
sprite.drawSprite(_x, _y, 0xffffff);
}
//sprite drawing
if (sprite != null && !childInterface.enableOrbs) {
if (childInterface.drawsTransparent) {
sprite.drawTransparentSprite(_x, _y, alpha);
} else {
sprite.drawSprite(_x, _y);
}
}
//autocast
if (autocast && childInterface.id == autoCastId)
cacheSprite[43].drawSprite(_x - 3, _y - 3);
//orbs
if (!childInterface.enableOrbs) {
if(sprite != null)
if (childInterface.drawsTransparent)
sprite.drawTransparentSprite(_x, _y, alpha);
else
sprite.drawSprite(_x, _y);
} else {
if(sprite != null) {
if(childInterface.flipOrb)
if(childInterface.flipState > 0)
sprite = (childInterface.flipState == 1 ? flippedOrb : flippedOrbH);
sprite.drawSprite(_x, _y);
}
Sprite orb = (interfaceIsSelected(childInterface) ? childInterface.alternateOrb : childInterface.defaultOrb);
Sprite icon = (interfaceIsSelected(childInterface) ? childInterface.alternateIcon : childInterface.defaultIcon);
Sprite drain = childInterface.drain;
if(childInterface.id == 10295) {
if(localPlayer.poisonState == 1)
orb = childInterface.alternateOrb;
childInterface.optionType = (localPlayer.poisonState == 1 ? 4 : 0);
}
if(orb != null && icon != null && drain != null) {
if(childInterface.contentType > 0) {
if(childInterface.contentType == 676) {
switch(childInterface.parent) {
case 10295:
case 10299:
case 10303:
case 10307:
if(childInterface.parent == 10299)
childInterface.opacity = (byte) (calcPercent(childInterface) ? (((loopCycle % 26) / 6) * 50) : 0);
childInterface.drainRate = calcDrainRate(childInterface);
break;
}
}
}
drain.myHeight = childInterface.drainRate;
orb.drawSprite(_x + (childInterface.flipOrb ? 4 : 27), _y + 4);
drain.drawSprite(_x + (childInterface.flipOrb ? 4 : 27), _y + 4);
int offsetx = orb.myWidth / 2 - icon.myWidth / 2;
int offsety = orb.myHeight / 2 - icon.myHeight / 2;
icon.drawTransparentSprite(_x + (childInterface.flipOrb ? 4 : 27) + offsetx, _y + 4 + offsety, 256 - (childInterface.opacity & 0xff));
}
}
In
Code:
executeScript(Widget widget, int id)
Code:
/*if(instruction == 21)//special attack
value = specialAttack;*///get from the server
if(instruction == 22)
value = 100;
In drawMinimap, add
Code:
if(displayOrbs)
drawInterface(0, frameMode == ScreenMode.FIXED ? 0 : frameWidth - 217, Widget.interfaceCache[10294], 0);
In buildInterfaceMenu(),
Code:
if (childInterface.optionType == Widget.OPTION_TOGGLE_SETTING
&& k >= i2 && i1 >= j2 && k < i2 + childInterface.width
&& i1 < j2 + childInterface.height) {
if(childInterface.doActionType != 315) {//childInterface.tooltip != null || childInterface.tooltip.length() > 0 && childInterface.tooltip != ""
if(childInterface.actions != null) {
if (childInterface.type == 5) {
if(childInterface.id == 10299)
childInterface.actions[0] = (interfaceIsSelected(childInterface) ? "Deactivate Quick-prayers" : "Activate Quick-prayers");
for(int actionIndex = childInterface.actions.length - 1; actionIndex >= 0; actionIndex--) {
String actionName = childInterface.actions[actionIndex];
if(actionName != null) {
menuActionText[menuActionRow] = actionName;
menuActionTypes[menuActionRow] = childInterface.doActionType + actionIndex;
secondMenuAction[menuActionRow] = childInterface.id;
firstMenuAction[menuActionRow] = actionIndex;
menuActionRow++;
}
}
}
}
} else {
menuActionText[menuActionRow] = childInterface.tooltip;
menuActionTypes[menuActionRow] = 169;
secondMenuAction[menuActionRow] = childInterface.id;
menuActionRow++;
}
}
In processRightClick(), below
Code:
menuActionText[0] = "Cancel";
menuActionTypes[0] = 1107;
menuActionRow = 1;
if (showChatComponents) {
buildSplitPrivateChatMenu();
}
hoverSupportId = 0;
tooltipSupportId = 0;
Add
Code:
if(displayOrbs) {
if (super.mouseX > 516 && super.mouseY > 0 && super.mouseX < 765 && super.mouseY < 168) {
buildInterfaceMenu(516, Widget.interfaceCache[10294], super.mouseX, 0, super.mouseY, 0);
}
}
if (hoverSupportId != mapHoverSupportId) {
mapHoverSupportId = hoverSupportId;
}
if (tooltipSupportId != mapTooltipSupportId) {
mapTooltipSupportId = tooltipSupportId;
}
hoverSupportId = 0;
tooltipSupportId = 0;
Find,
and add
Code:
|| action == 1001 || action == 1002 || action == 1005 || action == 1006) {
//poison, prayer (add 1003 for select quick), run, special button action ids
Finally, a toggle
Code:
public boolean displayOrbs = true;
In your Interface class:
Code:
public int drainRate;
public int flipState;
public boolean flipOrb;
public boolean enableOrbs;
public Sprite defaultOrb, defaultIcon, alternateOrb, alternateIcon, drain;
public static void addOrbButton(int id, int actionId, String[] actions, int[] imageId, int buttonSettingId, boolean hover, boolean flip, int[] textSettingId, GameFont[] font) {
String directory = "orbicons";
int baseId = imageId[0];
int defaultOrbId = imageId[1];
int defaultIconId = imageId[2];
int alternateOrbId = imageId[3];
int alternateIconId = imageId[4];
Widget button = interfaceCache[id] = new Widget();
button.id = id;
button.parent = id;
button.type = 5;
button.optionType = (actions[0].length() > 0 ? 4 : 0);
button.contentType = 676;
button.hoverType = id + 1;
button.enableOrbs = true;
button.opacity = 0;
button.disabledSprite = getImage(baseId, directory);
button.enabledSprite = getImage(baseId, directory);
if(flip) {
button.flipOrb = flip;
if(button.flipOrb)
button.flipState = 1;
}
button.defaultOrb = getImage(defaultOrbId, directory);
button.drain = getImage(0, directory);
button.defaultIcon = getImage(defaultIconId, directory);
button.alternateOrb = getImage(alternateOrbId, directory);
button.alternateIcon = getImage(alternateIconId, directory);
button.width = getDimensions(baseId, directory, 0);
button.height = getDimensions(baseId, directory, 1);
if(actions != null && actions[0].length() > 0) {
button.scriptOperators = new int[1];
button.scriptDefaults = new int[1];
button.scriptOperators[0] = 1;
button.scriptDefaults[0] = 1;
button.scripts = new int[1][3];
button.scripts[0][0] = 5;
button.scripts[0][1] = buttonSettingId;
button.scripts[0][2] = 0;
button.actions = actions;
button.doActionType = actionId;//change to something more understandable and flexible please:TODO
}
if(hover) {
Widget placeholder = interfaceCache[id + 1] = new Widget();
placeholder.id = id + 1;
placeholder.parent = id;
placeholder.type = 0;
placeholder.optionType = 0;
placeholder.width = getDimensions(baseId, directory, 0);
placeholder.height = getDimensions(baseId, directory, 1);
placeholder.hoverOnly = true;
placeholder.hoverType = -1;
placeholder.enableOrbs = true;
setIndex(1, placeholder);
setChild(id + 2, 0, 0, 0, placeholder);
Widget buttonh = interfaceCache[id + 2] = new Widget();
buttonh.id = id + 2;
buttonh.parent = id;
buttonh.type = 5;
buttonh.optionType = 4;
buttonh.enableOrbs = true;
buttonh.contentType = 676;
buttonh.hoverType = 52;
buttonh.opacity = 0;
buttonh.disabledSprite = getImage(2, directory);
buttonh.enabledSprite = getImage(2, directory);
if(flip) {
buttonh.flipOrb = flip;
if(buttonh.flipOrb)
buttonh.flipState = 2;
}
buttonh.defaultOrb = getImage(defaultOrbId, directory);
buttonh.drain = getImage(0, directory);
buttonh.defaultIcon = getImage(defaultIconId, directory);
buttonh.alternateOrb = getImage(alternateOrbId, directory);
buttonh.alternateIcon = getImage(alternateIconId, directory);
buttonh.width = getDimensions(baseId, directory, 0);
buttonh.height = getDimensions(baseId, directory, 1);
buttonh.scriptOperators = new int[1];
buttonh.scriptDefaults = new int[1];
buttonh.scriptOperators[0] = 1;
buttonh.scriptDefaults[0] = 1;
buttonh.scripts = new int[1][3];
buttonh.scripts[0][0] = 5;
buttonh.scripts[0][1] = buttonSettingId;
buttonh.scripts[0][2] = 0;
}
Widget text = interfaceCache[id + 3] = new Widget();
text.id = id + 3;
text.parent = id;
text.type = 4;
text.contentType = 675;
text.drawCenteredString = true;
text.textShadow = true;
text.textDrawingAreas = font[FontType.SMALL.getId()];
text.defaultText = "%1";
text.textColor = 0x00000;
text.enableOrbs = true;
text.flipOrb = flip;
text.scripts = new int[2][textSettingId.length];
text.scripts[0][0] = textSettingId[0];
text.scripts[0][1] = textSettingId[1];
text.scripts[0][2] = 0;
text.scripts[1][0] = textSettingId[2];
text.scripts[1][1] = textSettingId[1];
text.scripts[1][2] = 0;
}
Code:
public static void build(GameFont[] text) {
Widget map = addInterface(10294, BoundTo.MAP);
setIndex(12, map);
//hp
addOrbButton(10295, 1001, new String[] {"Cure poison"}, new int[] {1, 3, 10, 4, 10}, 709, false, false, new int[] {1, 3, 2}, text);
setChild(10295, 0, 40, 0, map);
setChild(10296, 0, 40, 1, map);
setChild(10298, 4 + (21 / 2), 57, 2, map);
//prayer
addOrbButton(10299, 1002, new String[] {"Activate Quick-prayers", "Setup Quick-prayers"}, new int[] {1, 5, 11, 6, 12}, 710, true, false, new int[] {1, 5, 2}, text);
setChild(10299, 1, 84, 3, map);
setChild(10300, 1, 84, 4, map);
setChild(10302, 5 + (21 / 2), 101, 5, map);
//run
addOrbButton(10303, 1005, new String[] {"Toggle run"}, new int[] {1, 7, 13, 8, 14}, 429, true, false, new int[] {11, 0, 22}, text);
setChild(10303, 25, 120, 6, map);
setChild(10304, 25, 120, 7, map);
setChild(10306, 29 + (21 / 2), 137, 8, map);
//special
addOrbButton(10307, 1006, new String[] {"Use special attack"}, new int[] {1, 8, 15, 8, 15}, 711, true, true, new int[] {21, 0, 22}, text);
setChild(10307, 170, 120, 9, map);
setChild(10308, 170, 120, 10, map);
setChild(10310, 174 + (21 / 2), 137, 11, map);
}
If you use the values for the interface that I used, add this to your interface class, and call it before the build method for orbs.
Code:
public static void removeGamesRoomGameSelectionInterface() {
for(int id = 10294; id <= 10379; id++)
remove(id);
}
Player class:
Code:
public int poisonState;
In updatePlayer,
Code:
poisonState = stream.readUnsignedByte();
*Need to add to your server a poison state check, 0 or 1, 1 being poisoned.
**Special attack bar percent should be sent from the server to the client so the orb has a value, example:
Edit: Server portion, if interested
Code:
case 40059://orb button click
Code:
if (quicks == 0) {
player.send(new SendMessage("You have not set any quick prayers."));
player.getClient().queueOutgoingPacket(new SendConfig(710, 0));//disable the prayer button
return true;
}
(on login you should set the prayer orb button config to 0 by default)
Code:
public class SendSpecialAttack extends OutgoingPacket {
private final int special;
private final int SPECIAL_ATTACK_PACKET = ;//get an unused packet id
public SendSpecialAttack(int special) {
super();
this.special = special;
}
@Override
public void execute(Client client) {
StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(3);
out.writeHeader(client.getEncryptor(), SPECIAL_ATTACK_PACKET);
out.writeShort(special);
client.send(out.getBuffer());
}
@Override
public int getOpcode() {
return SPECIAL_ATTACK_PACKET;
}
}
Code:
if (opcode == PacketConstants.SEND_SPECIAL_ATTACK) {
int special = incoming.readUShort();
specialAttack = special;
System.out.println("special: " + specialAttack);
opcode = -1;
return true;
}
Code:
public int specialAttack;
Don't forget to change the incoming packet size to 2 for the id you choose in the client.
And that's it