Merge branch 'flatpacks' into 'master'

Implemented flatpacks

See merge request 2009scape/2009scape!2495
This commit is contained in:
Bishop 2026-08-01 17:24:31 +00:00
commit 4f5cfebb92
12 changed files with 685 additions and 217 deletions

View file

@ -65,14 +65,16 @@ public enum BuildHotspot {
* Low-level Work shop hotspots.
*/
REPAIR(15448, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.REPAIR_BENCH, Decoration.WHETSTONE, Decoration.ARMOUR_STAND),
WORKBENCH(15439, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKBENCH_WOODEN, Decoration.WORKBENCH_OAK,Decoration.WORKBENCH_STEEL_FRAME, Decoration.WORKBENCH_WITH_VICE,Decoration.WORKBENCH_WITH_LATHE),
CRAFTING(15441, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRAFTING_TABLE_1, Decoration.CRAFTING_TABLE_2,Decoration.CRAFTING_TABLE_3, Decoration.CRAFTING_TABLE_4),
WORKBENCH(15439, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKBENCH_WOODEN, Decoration.WORKBENCH_OAK,Decoration.WORKBENCH_STEEL_FRAME, Decoration.WORKBENCH_WITH_VICE, Decoration.WORKBENCH_WITH_LATHE),
CRAFTING(15441, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.CRAFTING_TABLE_1, Decoration.CRAFTING_TABLE_2,Decoration.CRAFTING_TABLE_3, Decoration.CRAFTING_TABLE_4),
TOOL1(15443, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2, Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4, Decoration.TOOL_STORE_5),
TOOL2(15444, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL3(15445, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL4(15446, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
TOOL5(15447, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.TOOL_STORE_1, Decoration.TOOL_STORE_2,Decoration.TOOL_STORE_3, Decoration.TOOL_STORE_4,Decoration.TOOL_STORE_5),
HERALDRY(15450, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PLUMING_STAND, Decoration.SHIELD_EASEL,Decoration.BANNER_EASEL),
WORKBENCH_STOOL(15440, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL,Decoration.WORKSHOP_STOOL_OAK, Decoration.WORKSHOP_STOOL_OAK,Decoration.WORKSHOP_STOOL_OAK),
CRAFTING_STOOL(15442, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL,Decoration.WORKSHOP_STOOL, Decoration.WORKSHOP_STOOL),
/**
* Bedroom hotspots.
@ -386,6 +388,8 @@ public enum BuildHotspot {
linkedHotspots.add(new BuildHotspot[] { DUNGEON_DOOR_LEFT2, DUNGEON_DOOR_RIGHT2 });
linkedHotspots.add(new BuildHotspot[] { SMALL_PLANT_1, SMALL_PLANT1 });
linkedHotspots.add(new BuildHotspot[] { SHELVES, SHELVES_2 });
linkedHotspots.add(new BuildHotspot[] { WORKBENCH, WORKBENCH_STOOL });
linkedHotspots.add(new BuildHotspot[] { CRAFTING, CRAFTING_STOOL });
}
/**

View file

@ -9,13 +9,14 @@ import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.RegionManager;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.Log;
import core.tools.SystemLogger;
import core.plugin.ClassScanner;
import static core.api.ContentAPIKt.log;
import static core.api.ContentAPIKt.setAttribute;
/**
* The build option handling plugin.
@ -48,7 +49,7 @@ public final class BuildOptionPlugin extends OptionHandler {
player.getDialogueInterpreter().open("con:removedec", object);
return true;
}
player.setAttribute("con:hsobject", node);
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, node);
if (BuildingUtils.isDoorHotspot(object)) {
int[] pos = BuildingUtils.roomExists(player, object);
if (pos != null) {
@ -71,7 +72,27 @@ public final class BuildOptionPlugin extends OptionHandler {
return true;
}
player.setAttribute("con:hotspot", hotspot);
BuildHotspot[] linked = BuildHotspot.getLinkedHotspots(hotspot.getHotspot());
if (linked != null && linked[0] != hotspot.getHotspot()) {
Room room = player.getHouseManager().getRoom(object.getLocation());
if (room == null) return true;
for (Hotspot h : room.getHotspots()) {
if (h.getHotspot() == linked[0]) {
int dx = h.getCurrentX() - object.getLocation().getChunkOffsetX();
int dy = h.getCurrentY() - object.getLocation().getChunkOffsetY();
Scenery primaryObj = RegionManager.getObject(object.getLocation().transform(dx, dy, 0));
if (primaryObj != null) {
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, primaryObj);
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT, h);
BuildingUtils.openBuildInterface(player, linked[0]);
}
return true;
}
}
return true;
}
setAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT, hotspot);
BuildingUtils.openBuildInterface(player, hotspot.getHotspot());
return true;
}

View file

@ -18,6 +18,8 @@ import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import static core.api.ContentAPIKt.getAttribute;
/**
* Handles the building a room dialogue.
* @author Emperor
@ -105,7 +107,7 @@ public final class BuildRoomDialogue extends DialoguePlugin {
stage = 2;
return true;
}
this.door = (Scenery) player.getAttribute("con:hsobject");
this.door = (Scenery) getAttribute(player, ConstructionInterface.ATTRIBUTE_HOTSPOT_OBJ, null);
int[] pos = BuildingUtils.getRoomPosition(player, door);
roomX = pos[0];
roomY = pos[1];

View file

@ -139,9 +139,13 @@ public final class BuildingUtils {
* @param object The object.
*/
public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object) {
buildDecoration(player, hotspot, deco, object, false, false);
}
public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object, final boolean bypassCost, final boolean bypassXp) {
final int nailAmount = deco.getNailAmount();
final NailType type = nailAmount > 0 ? NailType.get(player, nailAmount) : null;
if (nailAmount > 0 && type == null) {
if (nailAmount > 0 && type == null && !bypassCost) {
player.getPacketDispatch().sendMessage("You don't have the right materials.");
return;
}
@ -165,7 +169,7 @@ public final class BuildingUtils {
NailType nail = type;
@Override
public boolean pulse() {
if (nails > 0) {
if (nails > 0 && !bypassCost) {
if (!type.isBend()) {
player.getPacketDispatch().sendMessage("You use a nail.");
nails--;
@ -189,12 +193,14 @@ public final class BuildingUtils {
}
}
}
if (player.getInventory().remove(deco.getItems()) || player.isAdmin()) {
if (player.getInventory().remove(deco.getItems()) || bypassCost || player.isAdmin()) {
setDecoration(player, r, room, hotspot, object, deco);
player.getSkills().addExperience(Skills.CONSTRUCTION, deco.getExperience(), true);
if (!bypassXp) {
player.getSkills().addExperience(Skills.CONSTRUCTION, deco.getExperience(), true);
if (getObjectIdsThatGiveFarmingExperience().contains(deco.getObjectId())) {
player.getSkills().addExperience(Skills.FARMING, deco.getExperience(), true);
if (getObjectIdsThatGiveFarmingExperience().contains(deco.getObjectId())) {
player.getSkills().addExperience(Skills.FARMING, deco.getExperience(), true);
}
}
player.unlock();
}
@ -439,7 +445,7 @@ public final class BuildingUtils {
for (int y = 0; y < 8; y++) {
for (BuildHotspot bh : linkedHotspots) {
Hotspot h = room.getHotspot(bh, x, y);
if (h != null) {
if (h != null && h.getDecorationIndex() >= 0) {
int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
h.setDecorationIndex(-1);

View file

@ -1,120 +0,0 @@
package content.global.skill.construction;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
import core.game.node.scenery.Scenery;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.Log;
import core.tools.SystemLogger;
import static core.api.ContentAPIKt.log;
/**
* Handles the creating of a decoration object.
* @author Emperor
*
*/
@Initializable
public final class ConstructionInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) {
ComponentDefinition.put(396, this);
ComponentDefinition.put(398, this);
ComponentDefinition.put(402, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 396:
switch (button) {
case 132:
player.getInterfaceManager().close();
Hotspot hotspot = player.getAttribute("con:hotspot");
Scenery object = player.getAttribute("con:hsobject");
if (hotspot == null || object == null) {
log(this.getClass(), Log.ERR, "Failed building decoration " + hotspot + " : " + object);
break;
}
slot = ((slot % 2 != 0) ? 4 : 0) + (slot >> 1);
if (slot >= hotspot.getHotspot().getDecorations().length) {
log(this.getClass(), Log.ERR, "Failed building decoration " + slot + "/" + hotspot.getHotspot().getDecorations().length);
break;
}
boolean debug = player.isStaff();
Decoration deco = hotspot.getHotspot().getDecorations()[slot];
if (!debug) {
if (player.getSkills().getLevel(Skills.CONSTRUCTION) < deco.getLevel()) {
player.sendMessage("You need to have a Construction level of " + deco.getLevel() + " to build that.");
return true;
}
if (!player.getInventory().containsItems(deco.getItems())) {
player.sendMessage("You don't have the right materials.");
return true;
}
for (int tool : deco.getTools()) {
if (tool == BuildingUtils.WATERING_CAN) {
boolean hasWateringCan = false;
for (int i = 0; i < 8; i++) {
if (player.getInventory().contains(tool - i, 1)) {
hasWateringCan = true;
break;
}
}
if (!hasWateringCan) {
player.sendMessage("You need a watering can to plant this.");
return true;
}
continue;
}
if (!player.getInventory().contains(tool, 1)) {
player.sendMessage("You need a " + ItemDefinition.forId(tool).getName() + " to build this.");
return true;
}
}
}
BuildingUtils.buildDecoration(player, hotspot, deco, object);
return true;
}
break;
case 398:
switch (button) {
case 14:
player.getHouseManager().toggleBuildingMode(player, true);
return true;
case 1:
player.getHouseManager().toggleBuildingMode(player, false);
return true;
case 15:
player.getHouseManager().expelGuests(player);
return true;
case 13:
if (!player.getHouseManager().isInHouse(player)) {
player.sendMessage("You can't do this outside of your house.");
return true;
}
HouseManager.leave(player);
return true;
}
break;
case 402:
int index = button - 160;
log(this.getClass(), Log.FINE, "BuildRoom Interface Index: " + index);
if (index > -1 && index < RoomProperties.values().length) {
player.getDialogueInterpreter().open("con:room", RoomProperties.values()[index]);
return true;
}
break;
}
return false;
}
}

View file

@ -0,0 +1,161 @@
package content.global.skill.construction
import content.global.skill.construction.decoration.workshop.WorkbenchListeners
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.game.interaction.InterfaceListener
import core.game.node.entity.skill.Skills
import core.game.node.scenery.Scenery
import core.tools.Log
import org.rs09.consts.Components
/**
* Handles three interfaces related to the Construction skill, namely those which allow a player to build decorations,
* toggle building mode/expel guests, and select a room to add to the POH.
* @author Bishop
*/
class ConstructionInterface : InterfaceListener {
companion object {
const val ATTRIBUTE_HOTSPOT = "con:hotspot"
const val ATTRIBUTE_HOTSPOT_OBJ = "con:hsobject"
private const val DECO_BUTTON_BUILD = 132
private const val HOUSE_BUTTON_BUILDMODE_ON = 14
private const val HOUSE_BUTTON_BUILDMODE_OFF = 1
private const val HOUSE_BUTTON_EXPEL_GUESTS = 15
private const val HOUSE_BUTTON_LEAVE_HOUSE = 13
// Register furniture here when it is only obtainable by upgrading, to send the correct rejection message.
private val upgradeOnly = arrayOf(
Decoration.WORKBENCH_WITH_VICE,
Decoration.WORKBENCH_WITH_LATHE,
)
}
override fun defineInterfaceListeners() {
/**
* Handles the interface for selecting a decoration to build.
*/
on(Components.POH_DECORATION_396) { player, _, _, buttonID, slot, _ ->
when (buttonID) {
DECO_BUTTON_BUILD -> {
val hotspot = getAttribute<Hotspot?>(player, ATTRIBUTE_HOTSPOT, null)
val hotspotObj = getAttribute<Scenery?>(player, ATTRIBUTE_HOTSPOT_OBJ, null)
val flatpackMode = getAttribute(player, WorkbenchListeners.ATTRIBUTE_FLATPACK_MODE, false)
if (!flatpackMode) {
closeInterface(player)
}
if ((hotspot == null || hotspotObj == null) && !flatpackMode) {
log(this.javaClass, Log.ERR, "Failed building decoration $hotspot : $hotspotObj")
return@on false
}
val decoIndex = (if (slot % 2 != 0) 4 else 0) + (slot shr 1)
val buildHotspot = if (flatpackMode) {
getAttribute<BuildHotspot?>(player, WorkbenchListeners.ATTRIBUTE_WORKBENCH_SELECTION, null)?: return@on false
} else {
hotspot!!.hotspot
}
if (decoIndex >= buildHotspot.decorations.size) {
log(this.javaClass, Log.ERR, "Failed building decoration $decoIndex/${buildHotspot.decorations.size}")
return@on false
}
val deco = buildHotspot.decorations[decoIndex]
if (!player.isAdmin) {
if (getDynLevel(player, Skills.CONSTRUCTION) < deco.level) {
closeInterface(player)
sendMessage(player, "You need to have a Construction level of ${deco.level} to build that.")
return@on true
}
if (deco in upgradeOnly) {
closeInterface(player)
sendMessage(player, "That can only be built by upgrading the previous piece of furniture.")
return@on true
}
if (!player.inventory.containsItems(*deco.items)) { // No clean ContentAPI substitute for this
closeInterface(player)
sendMessage(player, "You don't have the right materials.")
return@on true
}
for (tool in deco.tools) {
if (tool == BuildingUtils.WATERING_CAN) {
var hasWateringCan = false
var i = 0
while (i < 8) {
if (inInventory(player, tool - i)) {
hasWateringCan = true
break
}
i++
}
if (!hasWateringCan) {
sendMessage(player, "You need a watering can to plant this.")
return@on true
}
continue
}
if (!inInventory(player, tool)) {
closeInterface(player)
sendMessage(player, "You need a ${ItemDefinition.forId(tool).name} to build this.")
return@on true
}
}
if (flatpackMode && WorkbenchListeners.getBenchLevel(getAttribute(player, WorkbenchListeners.ATTRIBUTE_WORKBENCH_ID, 20)) < deco.level) {
closeInterface(player)
sendMessage(player, "You cannot make this with this workbench.") // Placeholder
return@on true
}
}
if (flatpackMode) {
WorkbenchListeners.produceFlatpack(player, deco)
} else {
BuildingUtils.buildDecoration(player, hotspot, deco, hotspotObj)
}
return@on true
}
else -> return@on false
}
}
/**
* Handles the interface for managing building mode and POH guests.
*/
on(Components.POH_HOUSE_OPTIONS_398) { player, _, _, buttonID, _, _ ->
when (buttonID) {
HOUSE_BUTTON_BUILDMODE_ON -> {
player.houseManager.toggleBuildingMode(player, true)
return@on true
}
HOUSE_BUTTON_BUILDMODE_OFF -> {
player.houseManager.toggleBuildingMode(player, false)
return@on true
}
HOUSE_BUTTON_EXPEL_GUESTS -> {
player.houseManager.expelGuests(player)
return@on true
}
HOUSE_BUTTON_LEAVE_HOUSE -> {
if (!player.houseManager.isInHouse(player)) {
sendMessage(player, "You can't do this outside of your house.")
return@on true
}
HouseManager.leave(player)
return@on true
}
else -> return@on false
}
}
/**
* Handles the interface for selecting a new room to add to a POH.
*/
on(Components.POH_ROOMS_402) { player, _, _, buttonID, _, _ ->
val index = buttonID - 160
log(this.javaClass, Log.FINE, "BuildRoom Interface Index: $index")
if (index > -1 && index < RoomProperties.values().size) {
player.dialogueInterpreter.open("con:room", RoomProperties.values()[index]) // ContentAPI impl won't work for this
}
return@on true
}
}
}

View file

@ -74,13 +74,13 @@ public enum Decoration {
/**
* Parlour chair spot
*/
CRUDE_CHAIR (13581, 8309, 1, 58, new Item[] { new Item(Items.PLANK_960, 2) }),
WOODEN_CHAIR (13582, 8310, 8, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
ROCKING_CHAIR (13583, 8311, 14, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
OAK_CHAIR (13584, 8312, 19, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
OAK_ARMCHAIR (13585, 8313, 26, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_ARMCHAIR (13586, 8314, 35, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_ARMCHAIR(13587, 8315, 50, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
CRUDE_CHAIR (13581, 8309, 1, 58, new Item[] { new Item(Items.PLANK_960, 2) }, Items.CRUDE_WOODEN_CHAIR_8496),
WOODEN_CHAIR (13582, 8310, 8, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.WOODEN_CHAIR_8498),
ROCKING_CHAIR (13583, 8311, 14, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.ROCKING_CHAIR_8500),
OAK_CHAIR (13584, 8312, 19, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_CHAIR_8502),
OAK_ARMCHAIR (13585, 8313, 26, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_ARMCHAIR_8504),
TEAK_ARMCHAIR (13586, 8314, 35, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_ARMCHAIR_8506),
MAHOGANY_ARMCHAIR(13587, 8315, 50, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_ARMCHAIR_8508),
/**
* Rugs rugs rugs
@ -112,9 +112,9 @@ public enum Decoration {
/**
* Bookcases
*/
WOODEN_BOOKCASE (13597, 8319, 4, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
OAK_BOOKCASE (13598, 8320, 29, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
MAHOGANY_BOOKCASE(13599, 8321, 40, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }),
WOODEN_BOOKCASE (13597, 8319, 4, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOODEN_BOOKCASE_8510),
OAK_BOOKCASE (13598, 8320, 29, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_BOOKCASE_8512),
MAHOGANY_BOOKCASE(13599, 8321, 40, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }, Items.MAHOGANY_BKCASE_8514),
/**
* Kitchen Beer Barrels
@ -122,19 +122,19 @@ public enum Decoration {
* Basic: 1, Cider: 14, Asgarnian: 24, Greenman's: 29, D.Bitter: 39, Chef's: 54
*
*/
BASIC_BEER_BARREL (13568, 8239, 7, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
CIDER_BARREL (13569, 8240, 12, 91, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.CIDER_5763, 8) }),
ASGARNIAN_ALE_BARREL(13570, 8241, 18, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.ASGARNIAN_ALE_1905, 8) }),
GREENMANS_ALE_BARREL(13571, 8242, 26, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.GREENMANS_ALE_1909, 8) }),
DRAGON_BITTER_BARREL(13572, 8243, 36, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.DRAGON_BITTER_1911, 8), new Item(Items.STEEL_BAR_2353, 2) }),
CHEFS_DELIGHT_BARREL(13573, 8244, 48, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.CHEFS_DELIGHT_5755, 8), new Item(Items.STEEL_BAR_2353, 2) }),
BASIC_BEER_BARREL (13568, 8239, 7, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.BEER_BARREL_8516),
CIDER_BARREL (13569, 8240, 12, 91, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.CIDER_5763, 8) }, Items.CIDER_BARREL_8518),
ASGARNIAN_ALE_BARREL(13570, 8241, 18, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.ASGARNIAN_ALE_1905, 8) }, Items.ASGARNIAN_ALE_8520),
GREENMANS_ALE_BARREL(13571, 8242, 26, 184, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.GREENMANS_ALE_1909, 8) }, Items.GREENMANS_ALE_8522),
DRAGON_BITTER_BARREL(13572, 8243, 36, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.DRAGON_BITTER_1911, 8), new Item(Items.STEEL_BAR_2353, 2) }, Items.DRAGON_BITTER_8524),
CHEFS_DELIGHT_BARREL(13573, 8244, 48, 224, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.CHEFS_DELIGHT_5755, 8), new Item(Items.STEEL_BAR_2353, 2) }, Items.CHEFS_DELIGHT_8526),
/**
* Kitchen Tables!
*/
KITCHEN_WOODEN_TABLE(13577, 8246, 12, 87, new Item[] { new Item(Items.PLANK_960, 3) }),
KITCHEN_OAK_TABLE (13578, 8247, 32, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
KITCHEN_TEAK_TABLE (13579, 8248, 52, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
KITCHEN_WOODEN_TABLE(13577, 8246, 12, 87, new Item[] { new Item(Items.PLANK_960, 3) }, Items.WOOD_KITCHEN_TABLE_8528),
KITCHEN_OAK_TABLE (13578, 8247, 32, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_KITCHEN_TABLE_8530),
KITCHEN_TEAK_TABLE (13579, 8248, 52, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_KITCHEN_TABLE_8532),
/**
* Kitchen Stoves
@ -182,24 +182,24 @@ public enum Decoration {
/**
* Dining room tables
*/
DINING_TABLE_WOOD (13293, 8246, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
DINING_TABLE_OAK (13294, 8247, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
DINING_TABLE_CARVED_OAK (13295, 8247, 31, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }),
DINING_TABLE_TEAK (13296, 8248, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
DINING_TABLE_CARVED_TEAK(13297, 8248, 45, 600, new Item[] { new Item(Items.TEAK_PLANK_8780, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4) }),
DINING_TABLE_MAHOGANY (13298, 8120, 52, 840, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }),
DINING_TABLE_OPULENT (13299, 8121, 72, 3100, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4), new Item(Items.GOLD_LEAF_8784, 4), new Item(Items.MARBLE_BLOCK_8786, 2) }),
DINING_TABLE_WOOD (13293, 8246, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOOD_DINING_TABLE_8548),
DINING_TABLE_OAK (13294, 8247, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_DINING_TABLE_8550),
DINING_TABLE_CARVED_OAK (13295, 8247, 31, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }, Items.CARVED_OAK_TABLE_8552),
DINING_TABLE_TEAK (13296, 8248, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_TABLE_8554),
DINING_TABLE_CARVED_TEAK(13297, 8248, 45, 600, new Item[] { new Item(Items.TEAK_PLANK_8780, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4) }, Items.CARVED_TEAK_TABLE_8556),
DINING_TABLE_MAHOGANY (13298, 8120, 52, 840, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }, Items.MAHOGANY_TABLE_8558),
DINING_TABLE_OPULENT (13299, 8121, 72, 3100, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6), new Item(Items.BOLT_OF_CLOTH_8790, 4), new Item(Items.GOLD_LEAF_8784, 4), new Item(Items.MARBLE_BLOCK_8786, 2) }, Items.OPULENT_TABLE_8560),
/**
* Dining room benches
*/
BENCH_WOODEN (13300, 8108, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }),
BENCH_OAK (13301, 8109, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
BENCH_CARVED_OAK (13302, 8110, 31, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
BENCH_TEAK (13303, 8111, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
BENCH_CARVED_TEAK(13304, 8112, 44, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
BENCH_MAHOGANY (13305, 8113, 52, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }),
BENCH_GILDED (13306, 8114, 61, 1760, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784, 4) }),
BENCH_WOODEN (13300, 8108, 10, 115, new Item[] { new Item(Items.PLANK_960, 4) }, Items.WOODEN_BENCH_8562),
BENCH_OAK (13301, 8109, 22, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_BENCH_8564),
BENCH_CARVED_OAK (13302, 8110, 31, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.CARVED_OAK_BENCH_8566),
BENCH_TEAK (13303, 8111, 38, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_DINING_BENCH_8568),
BENCH_CARVED_TEAK(13304, 8112, 44, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.CARVED_TEAK_BENCH_8570),
BENCH_MAHOGANY (13305, 8113, 52, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 6) }, Items.MAHOGANY_BENCH_8572),
BENCH_GILDED (13306, 8114, 61, 1760, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784, 4) }, Items.GILDED_BENCH_8574),
/**
* Dining room bell-pulls
@ -209,7 +209,7 @@ public enum Decoration {
FANCY_BELL_PULL(13309, 8101, 33, 58, new Item[] { new Item(Items.TEAK_PLANK_8780), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784) }),
/**
* Workshop workbench
* Workshop workbenches
*/
WORKBENCH_WOODEN (13704, 8375, 17, 143, new Item[] { new Item(Items.PLANK_960, 5) }),
WORKBENCH_OAK (13705, 8376, 32, 300, new Item[] { new Item(Items.OAK_PLANK_8778, 5) }),
@ -217,6 +217,12 @@ public enum Decoration {
WORKBENCH_WITH_VICE (13707, 8378, 62, 750, new Item[] { new Item(Items.STEEL_FRAMED_BENCH_8377), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }),
WORKBENCH_WITH_LATHE (13708, 8379, 77, 1000, new Item[] { new Item(Items.OAK_WORKBENCH_8376), new Item(Items.OAK_PLANK_8778, 2), new Item(Items.STEEL_BAR_2353) }),
/**
* Workshop stools (linked to workbench/crafting table hotspots)
*/
WORKSHOP_STOOL (13719, -1, 1, 0),
WORKSHOP_STOOL_OAK(13720, -1, 1, 0),
/**
* Workshop repair benches/stands
*/
@ -425,30 +431,30 @@ public enum Decoration {
/**
* Bedroom decorations.
*/
WOODEN_BED (13148, 8031, 20, 117, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
OAK_BED (13149, 8032, 30, 210, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
LARGE_OAK_BED (13150, 8033, 34, 330, new Item[] { new Item(Items.OAK_PLANK_8778, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
TEAK_BED (13151, 8034, 40, 300, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
LARGE_TEAK_BED (13152, 8035, 45, 480, new Item[] { new Item(Items.TEAK_PLANK_8780, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
FOUR_POSTER (13153, 8036, 53, 450, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }),
GILDED_FOUR_POSTER(13154, 8037, 60, 1330, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784, 2) }),
OAK_CLOCK (13169, 8052, 25, 142, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.CLOCKWORK_8792) }),
TEAK_CLOCK (13170, 8053, 55, 202, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.CLOCKWORK_8792) }),
GILDED_CLOCK (13171, 8054, 85, 602, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.CLOCKWORK_8792), new Item(Items.GOLD_LEAF_8784) }),
SHAVING_STAND (13162, 8045, 21, 30, new Item[] { new Item(Items.PLANK_960), new Item(Items.MOLTEN_GLASS_1775) }),
OAK_SHAVING_STAND (13163, 8046, 29, 61, new Item[] { new Item(Items.OAK_PLANK_8778), new Item(Items.MOLTEN_GLASS_1775) }),
OAK_DRESSER (13164, 8047, 37, 121, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.MOLTEN_GLASS_1775) }),
TEAK_DRESSER (13165, 8048, 46, 181, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775) }),
FANCY_TEAK_DRESSER(13166, 8049, 56, 182, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775, 2) }),
MAHOGANY_DRESSER (13167, 8050, 64, 281, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775) }),
GILDED_DRESSER (13168, 8051, 74, 582, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775, 2), new Item(Items.GOLD_LEAF_8784) }),
SHOE_BOX (13155, 8038, 20, 58, new Item[] { new Item(Items.PLANK_960, 2) }),
OAK_DRAWERS (13156, 8039, 27, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
OAK_WARDROBE (13157, 8040, 39, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_DRAWERS (13158, 8041, 51, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
TEAK_WARDROBE (13159, 8042, 63, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
MAHOGANY_WARDROBE (13160, 8043, 75, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
GILDED_WARDROBE (13161, 8044, 87, 720, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.GOLD_LEAF_8784) }),
WOODEN_BED (13148, 8031, 20, 117, new Item[] { new Item(Items.PLANK_960, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.WOODEN_BED_8576),
OAK_BED (13149, 8032, 30, 210, new Item[] { new Item(Items.OAK_PLANK_8778, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.OAK_BED_8578),
LARGE_OAK_BED (13150, 8033, 34, 330, new Item[] { new Item(Items.OAK_PLANK_8778, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.LARGE_OAK_BED_8580),
TEAK_BED (13151, 8034, 40, 300, new Item[] { new Item(Items.TEAK_PLANK_8780, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.TEAK_BED_8582),
LARGE_TEAK_BED (13152, 8035, 45, 480, new Item[] { new Item(Items.TEAK_PLANK_8780, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.LARGE_TEAK_BED_8584),
FOUR_POSTER (13153, 8036, 53, 450, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3), new Item(Items.BOLT_OF_CLOTH_8790, 2) }, Items.FOUR_POSTER_8586),
GILDED_FOUR_POSTER(13154, 8037, 60, 1330, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 5), new Item(Items.BOLT_OF_CLOTH_8790, 2), new Item(Items.GOLD_LEAF_8784, 2) }, Items.GILDED_4_POSTER_8588),
OAK_CLOCK (13169, 8052, 25, 142, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.CLOCKWORK_8792) }, Items.OAK_CLOCK_8590),
TEAK_CLOCK (13170, 8053, 55, 202, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.CLOCKWORK_8792) }, Items.TEAK_CLOCK_8592),
GILDED_CLOCK (13171, 8054, 85, 602, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.CLOCKWORK_8792), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_CLOCK_8594),
SHAVING_STAND (13162, 8045, 21, 30, new Item[] { new Item(Items.PLANK_960), new Item(Items.MOLTEN_GLASS_1775) }, Items.SHAVING_STAND_8596),
OAK_SHAVING_STAND (13163, 8046, 29, 61, new Item[] { new Item(Items.OAK_PLANK_8778), new Item(Items.MOLTEN_GLASS_1775) }, Items.OAK_SHAVING_STAND_8598),
OAK_DRESSER (13164, 8047, 37, 121, new Item[] { new Item(Items.OAK_PLANK_8778, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.OAK_DRESSER_8600),
TEAK_DRESSER (13165, 8048, 46, 181, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.TEAK_DRESSER_8602),
FANCY_TEAK_DRESSER(13166, 8049, 56, 182, new Item[] { new Item(Items.TEAK_PLANK_8780, 2), new Item(Items.MOLTEN_GLASS_1775, 2) }, Items.FANCY_TEAK_DRESSER_8604),
MAHOGANY_DRESSER (13167, 8050, 64, 281, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775) }, Items.MAHOGANY_DRESSER_8606),
GILDED_DRESSER (13168, 8051, 74, 582, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.MOLTEN_GLASS_1775, 2), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_DRESSER_8608),
SHOE_BOX (13155, 8038, 20, 58, new Item[] { new Item(Items.PLANK_960, 2) }, Items.SHOE_BOX_8610),
OAK_DRAWERS (13156, 8039, 27, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_DRAWERS_8612),
OAK_WARDROBE (13157, 8040, 39, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_WARDROBE_8614),
TEAK_DRAWERS (13158, 8041, 51, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_DRAWERS_8616),
TEAK_WARDROBE (13159, 8042, 63, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_WARDROBE_8618),
MAHOGANY_WARDROBE (13160, 8043, 75, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_DROBE_8620),
GILDED_WARDROBE (13161, 8044, 87, 720, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_WARDROBE_8622),
/**
* Quest hall decorations.
@ -502,31 +508,31 @@ public enum Decoration {
/**
* Costume room decorations.
*/
OAK_TREASURE_CHEST (18804, 9839, 48, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_TREASURE_CHEST (18806, 9840, 66, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_TREASURE_CHEST(18808, 9841, 84, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
OAK_ARMOUR_CASE (18778, 9826, 46, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }),
TEAK_ARMOUR_CASE (18780, 9827, 64, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }),
MGANY_ARMOUR_CASE (18782, 9828, 82, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }),
OAK_MAGIC_WARDROBE (18784, 9829, 42, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
C_OAK_MAGIC_WARDROBE (18786, 9830, 51, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }),
TEAK_MAGIC_WARDROBE (18788, 9831, 60, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
C_TEAK_MAGIC_WARDROBE (18790, 9832, 69, 540, new Item[] { new Item(Items.TEAK_PLANK_8780, 6) }),
MGANY_MAGIC_WARDROBE (18792, 9833, 78, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }),
GILDED_MAGIC_WARDROBE (18794, 9834, 87, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }),
MARBLE_MAGIC_WARDROBE (18796, 9835, 96, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }),
OAK_CAPE_RACK (18766, 9817, 54, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }),
TEAK_CAPE_RACK (18767, 9818, 63, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }),
MGANY_CAPE_RACK (18768, 9819, 72, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }),
GILDED_CAPE_RACK (18769, 9820, 81, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }),
MARBLE_CAPE_RACK (18770, 9821, 90, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }),
MAGIC_CAPE_RACK (18771, 9822, 99, 1000, new Item[] { new Item(Items.MAGIC_STONE_8788) }),
OAK_TOY_BOX (18798, 9836, 50, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_TOY_BOX (18800, 9837, 68, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_TOY_BOX (18802, 9838, 86, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
OAK_COSTUME_BOX (18772, 9823, 44, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_COSTUME_BOX (18774, 9824, 62, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
MAHOGANY_COSTUME_BOX (18776, 9825, 80, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }),
OAK_TREASURE_CHEST (18804, 9839, 48, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_TREASURE_CHEST_9862),
TEAK_TREASURE_CHEST (18806, 9840, 66, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_TREAS_CHEST_9863),
MAHOGANY_TREASURE_CHEST(18808, 9841, 84, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MGANY_TREAS_CHEST_9864),
OAK_ARMOUR_CASE (18778, 9826, 46, 180, new Item[] { new Item(Items.OAK_PLANK_8778, 3) }, Items.OAK_ARMOUR_CASE_9859),
TEAK_ARMOUR_CASE (18780, 9827, 64, 270, new Item[] { new Item(Items.TEAK_PLANK_8780, 3) }, Items.TEAK_ARMOUR_CASE_9860),
MGANY_ARMOUR_CASE (18782, 9828, 82, 420, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3) }, Items.MGANY_ARMR_CASE_9861),
OAK_MAGIC_WARDROBE (18784, 9829, 42, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_MAGIC_WARDROBE_9852),
C_OAK_MAGIC_WARDROBE (18786, 9830, 51, 360, new Item[] { new Item(Items.OAK_PLANK_8778, 6) }, Items.CARVED_OAK_MAGIC_WARDROBE_9853),
TEAK_MAGIC_WARDROBE (18788, 9831, 60, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_MAGIC_WARDROBE_9854),
C_TEAK_MAGIC_WARDROBE (18790, 9832, 69, 540, new Item[] { new Item(Items.TEAK_PLANK_8780, 6) }, Items.CARVED_TEAK_MAGIC_WARDROBE_9855),
MGANY_MAGIC_WARDROBE (18792, 9833, 78, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }, Items.MAHOGANY_MAGIC_WARDROBE_9856),
GILDED_MAGIC_WARDROBE (18794, 9834, 87, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_MAGIC_WARDROBE_9857),
MARBLE_MAGIC_WARDROBE (18796, 9835, 96, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }, Items.MARBLE_MAGIC_WARDROBE_9858),
OAK_CAPE_RACK (18766, 9817, 54, 240, new Item[] { new Item(Items.OAK_PLANK_8778, 4) }, Items.OAK_CAPE_RACK_9843),
TEAK_CAPE_RACK (18767, 9818, 63, 360, new Item[] { new Item(Items.TEAK_PLANK_8780, 4) }, Items.TEAK_CAPE_RACK_9844),
MGANY_CAPE_RACK (18768, 9819, 72, 560, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4) }, Items.MGANY_CAPE_RACK_9845),
GILDED_CAPE_RACK (18769, 9820, 81, 860, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 4), new Item(Items.GOLD_LEAF_8784) }, Items.GILDED_CAPE_RACK_9846),
MARBLE_CAPE_RACK (18770, 9821, 90, 500, new Item[] { new Item(Items.MARBLE_BLOCK_8786) }, Items.MARBLE_CAPE_RACK_9847),
MAGIC_CAPE_RACK (18771, 9822, 99, 1000, new Item[] { new Item(Items.MAGIC_STONE_8788) }, Items.MAGICAL_CAPE_RACK_9848),
OAK_TOY_BOX (18798, 9836, 50, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_TOY_BOX_9849),
TEAK_TOY_BOX (18800, 9837, 68, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_TOY_BOX_9850),
MAHOGANY_TOY_BOX (18802, 9838, 86, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_TOY_BOX_9851),
OAK_COSTUME_BOX (18772, 9823, 44, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }, Items.OAK_COSTUME_BOX_9865),
TEAK_COSTUME_BOX (18774, 9824, 62, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }, Items.TEAK_COSTUME_BOX_9866),
MAHOGANY_COSTUME_BOX (18776, 9825, 80, 280, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 2) }, Items.MAHOGANY_COS_BOX_9867),
/**
* Chapel decorations.
@ -684,6 +690,11 @@ public enum Decoration {
FREMENNIK_WINDOW (13112, -1, 1, 0),
TROPICAL_WOOD_WINDOW (10816, -1, 1, 0),
FANCY_STONE_WINDOW (13117, -1, 1, 0),
/**
* Flatpack deco for filling the flatpack hotspot.
*/
FLATPACK(-1, -1, 1, 0),
;
/**
@ -716,6 +727,11 @@ public enum Decoration {
*/
private final Item[] refundItems;
/**
* The item id of the flatpack.
*/
private final int flatpackItemId;
/**
* The tools required.
*/
@ -774,6 +790,11 @@ public enum Decoration {
this.reqsText = generateDefaultReqsText(items, getNailAmount());
}
Decoration(int objectId, int interfaceItem, int level, int experience, Item[] items, int flatpackItemId) {
this(objectId, interfaceItem, level, experience, new int[] { Items.HAMMER_2347, Items.SAW_8794 }, items, new Item[] {}, new String[] {}, flatpackItemId);
this.reqsText = generateDefaultReqsText(items, getNailAmount());
}
/**
* Constructs a new object, default refund items, default requirements text.
* @param objectId The object id.
@ -827,6 +848,10 @@ public enum Decoration {
* @param reqsText The requirements text to be shown in the interface.
*/
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems, String[] reqsText) {
this(objectId, interfaceItem, level, experience, tools, items, refundItems, reqsText, -1);
}
Decoration(int objectId, int interfaceItem, int level, int experience, int[] tools, Item[] items, Item[] refundItems, String[] reqsText, int flatpackItemId) {
this.objectId = objectId;
this.objectIds = null;
this.interfaceItem = interfaceItem;
@ -835,6 +860,7 @@ public enum Decoration {
this.tools = tools;
this.items = items;
this.refundItems = refundItems;
this.flatpackItemId = flatpackItemId;
if (reqsText.length > 0) {
System.arraycopy(reqsText, 0, this.reqsText, 0, reqsText.length);
}
@ -881,6 +907,7 @@ public enum Decoration {
this.tools = tools;
this.items = items;
this.refundItems = refundItems;
this.flatpackItemId = -1;
}
/**
@ -931,6 +958,15 @@ public enum Decoration {
return null;
}
public static Decoration forFlatpackItemId(int flatpackId) {
for (Decoration d : Decoration.values()) {
if (d.getFlatpackItemID() == flatpackId) {
return d;
}
}
return null;
}
/**
* Gets the amount of nails required for this hotspot.
* @return The amount of nails.
@ -1020,6 +1056,14 @@ public enum Decoration {
return objectIds;
}
/**
* Gets the flatpack item ID if it exists.
* @return the int ID.
*/
public int getFlatpackItemID() {
return flatpackItemId;
}
/**
* If this node should be invisible to user build options
* @return true if so.

View file

@ -0,0 +1,48 @@
package content.global.skill.construction
import core.api.*
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.node.scenery.Scenery
import org.rs09.consts.Items
/**
* Handles building furniture using flatpacks
* @author Roderik
* @author Bishop
*/
class FlatpackListener : InteractionListener {
val flatpacks = Decoration.values().map { it.flatpackItemID }.filter { it != -1 }.toIntArray()
val hotspots = BuildHotspot.values().map { it.objectId }.toIntArray()
override fun defineListeners() {
for (hotspot in hotspots) {
onUseWith(IntType.SCENERY, flatpacks, hotspot) { player, used, with ->
return@onUseWith buildFlatpackOnHotspot(player, used.asItem(), with as Scenery)
}
}
}
private fun buildFlatpackOnHotspot(player: Player, used: Item, with: Scenery): Boolean {
val hotspotUsed = player.houseManager.getHotspot(with)
val decorationUsed = Decoration.forFlatpackItemId(used.id)
if (!hotspotUsed.hotspot.decorations.contains(decorationUsed)) {
sendMessage(player, "You can't build that here.")
return false
}
if (!inInventory(player, Items.HAMMER_2347) || !inInventory(player, Items.SAW_8794)) {
sendMessage(player, "You need a hammer and a saw to build this.")
return false
}
if (removeItem(player, used)) {
BuildingUtils.buildDecoration(player, hotspotUsed, decorationUsed, with.asScenery(), true, true)
return true
} else {
return false
}
}
}

View file

@ -1,8 +1,12 @@
package content.global.skill.construction;
import content.global.skill.construction.decoration.workshop.WorkbenchListeners;
import core.api.Container;
import core.game.world.map.Location;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import org.rs09.consts.Items;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
@ -80,6 +84,23 @@ public final class HouseZone extends MapZone {
return super.enter(e);
}
@Override
public boolean move(Entity e, Location from, Location to) {
if (e instanceof Player) {
Player p = (Player) e;
if (getAttribute(p, WorkbenchListeners.ATTRIBUTE_WORKBENCH_SEATED, false)) {
p.getPulseManager().clear();
p.getWalkingQueue().reset();
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(p));
if (!getAttribute(p, WorkbenchListeners.ATTRIBUTE_WORKBENCH_STANDING_UP, false)) {
WorkbenchListeners.standUpFromWorkbench(p);
}
return false;
}
}
return super.move(e, from, to);
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {

View file

@ -135,7 +135,9 @@ public enum RoomProperties {
new Hotspot(BuildHotspot.TOOL2, 6, 0),
new Hotspot(BuildHotspot.TOOL1, 1, 0),
new Hotspot(BuildHotspot.TOOL3, 0, 1),
new Hotspot(BuildHotspot.TOOL5, 0, 6)),
new Hotspot(BuildHotspot.TOOL5, 0, 6),
new Hotspot(BuildHotspot.CRAFTING_STOOL, 1, 3),
new Hotspot(BuildHotspot.WORKBENCH_STOOL, 3, 3)),
/**
* Bedroom.

View file

@ -0,0 +1,51 @@
package content.global.skill.construction.decoration
import core.api.animate
import core.api.getScenery
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.system.timer.PersistTimer
import core.game.system.timer.RSTimer
import org.rs09.consts.Animations
import org.rs09.consts.Scenery
import kotlin.collections.get
/**
* Makes a player stay seated by reapplying the current animation occasionally.
* An alternative to some features of ChairBenchPlugin.
* Written with workbench stools in mind.
* @author Bishop
*/
class StaySeated : PersistTimer(10 /*ticks*/, "con:sitting", isSoft = true) {
lateinit var player: Player
private val standAnim = 808 // Same as AppearanceCache.STAND_ANIM
// Register new chairs and animations here
private val sittables = mapOf(
Scenery.STOOL_13719 to Animations.HUMAN_SEATED_POH_STOOL_4107,
Scenery.STOOL_13720 to Animations.HUMAN_SEATED_POH_OAK_STOOL_4108,
)
override fun run(entity: Entity): Boolean {
player = entity as Player
val localObj = getScenery(player.location)?.id
// Don't interrupt a player doing a different animation unless it's the idle animation
val currentAnimId = player.animator.animation?.id ?: -1
if (localObj in sittables) {
if (currentAnimId != sittables[localObj] &&
currentAnimId != standAnim &&
currentAnimId != -1) {
return true
}
animate(player, sittables[localObj])
return true
}
return false
}
override fun getTimer(vararg args: Any): RSTimer {
return StaySeated()
}
}

View file

@ -0,0 +1,228 @@
package content.global.skill.construction.decoration.workshop
import content.global.skill.construction.*
import content.global.skill.construction.decoration.StaySeated
import core.api.*
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.interaction.QueueStrength
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.world.map.Direction
import core.tools.ticksToCycles
import org.rs09.consts.Animations
import org.rs09.consts.Components
import org.rs09.consts.Items
import org.rs09.consts.Scenery
/**
* Handles usage of the workbench, which allows construction of flatpacks.
* @author Bishop
*/
class WorkbenchListeners : InteractionListener, InterfaceListener {
companion object {
const val ATTRIBUTE_FLATPACK_MODE = "con:workbench:active"
const val ATTRIBUTE_WORKBENCH_ID = "con:workbench:id"
const val ATTRIBUTE_WORKBENCH_SELECTION = "con:workbench:hotspot"
const val ATTRIBUTE_WORKBENCH_SEATED = "con:workbench:sitting"
const val ATTRIBUTE_WORKBENCH_STANDING_UP = "con:workbench:standing"
private const val ATTRIBUTE_DIRECTIONS = "con:workbench:directions"
private val workbenches = intArrayOf(
Scenery.WORKBENCH_13704, // lv20, wooden
Scenery.WORKBENCH_13705, // lv40, oak
Scenery.WORKBENCH_13706, // lv60, steel framed
Scenery.WORKBENCH_13707, // lv80, with vice
Scenery.WORKBENCH_13708, // lv99, with lathe
)
private val stools = intArrayOf(
Scenery.STOOL_13719, // wooden stool, bottom 2 tiers
Scenery.STOOL_13720, // oak stool, top 3 tiers
)
private val decoCategories = arrayOf(
BuildHotspot.CHAIRS_1, // ButtonID 111
BuildHotspot.BOOKCASE, // ButtonID 112
BuildHotspot.BARRELS, // ButtonID 113
BuildHotspot.KITCHEN_TABLE, // ButtonID 114
BuildHotspot.DINING_TABLE, // ButtonID 115
BuildHotspot.DINING_BENCH_1, // ButtonID 116
BuildHotspot.BED, // ButtonID 117
BuildHotspot.DRESSER, // ButtonID 118
BuildHotspot.DRAWERS, // ButtonID 119
BuildHotspot.CLOCK, // ButtonID 120
BuildHotspot.CAPE_RACK, // ButtonID 121
BuildHotspot.MAGIC_WARDROBE, // ButtonID 122
BuildHotspot.ARMOUR_CASE, // ButtonID 123
BuildHotspot.TREASURE_CHEST, // ButtonID 124
BuildHotspot.COSTUME_BOX, // ButtonID 125
BuildHotspot.TOY_BOX, // ButtonID 126
)
/**
* Returns the maximum construction level of decoration that can be built at a given workbench by id.
*/
fun getBenchLevel(workbenchId: Int): Int {
return ((workbenches.indexOf(workbenchId) + 1) * 20)
}
/**
* Animates the player crafting a flatpack, and exchanges its materials for the flatpack item.
* Flatpacks are free to produce for players with admin rights.
*/
fun produceFlatpack(player: Player, deco: Decoration) {
val reward = deco.flatpackItemID
val animation = if (getScenery(player.location)?.id == Scenery.STOOL_13720) { Animations.HUMAN_CRAFT_POH_OAK_STOOL_4110 } else { Animations.HUMAN_CRAFT_POH_STOOL_4109 }
if (reward == -1) return
if (removeItemsIfPlayerHasEnough(player, *deco.items) || player.isAdmin) {
closeInterface(player)
lock(player, getAnimation(animation).duration)
animate(player, animation)
rewardXP(player, Skills.CONSTRUCTION, deco.experience.toDouble())
addItemOrDrop(player, reward)
}
}
/**
* Animates the player getting up from the workbench's stool.
* This occurs on the player's first attempt at movement off of the workbench.
*/
@JvmStatic
fun standUpFromWorkbench(player: Player) {
val directions = getAttribute(player, ATTRIBUTE_DIRECTIONS, arrayOf(Direction.WEST, Direction.NORTH, Direction.EAST))
val animation = if (getScenery(player.location)?.id == Scenery.STOOL_13720) { Animations.HUMAN_SEATED_POH_OAK_STOOL_4108 } else { Animations.HUMAN_SEATED_POH_STOOL_4107 }
setAttribute(player, ATTRIBUTE_WORKBENCH_STANDING_UP, true)
lock(player, 1)
animate(player, animation)
queueScript(player, 0, QueueStrength.SOFT) {
forceMove(player, player.location, player.location.transform(directions[2], 1),
0, ticksToCycles(1), directions[2], Animations.HUMAN_STAND_POH_STOOL_4105) {
removeAttributes(player, ATTRIBUTE_DIRECTIONS, ATTRIBUTE_WORKBENCH_SEATED, ATTRIBUTE_WORKBENCH_STANDING_UP)
removeTimer<StaySeated>(player)
}
return@queueScript stopExecuting(player)
}
}
}
override fun defineListeners() {
/**
* Animates the player sitting down at the workbench, and opens the workbench interface.
*/
on(workbenches, IntType.SCENERY, "work-at") { player, node ->
setAttribute(player, ATTRIBUTE_WORKBENCH_ID, node.id)
// Skips the animation if the player is already sitting down.
if (getAttribute(player, ATTRIBUTE_WORKBENCH_SEATED, false)) {
val animation = if (getScenery(player.location)?.id == Scenery.STOOL_13720) { Animations.HUMAN_SEATED_POH_OAK_STOOL_4108 } else { Animations.HUMAN_SEATED_POH_STOOL_4107 }
animate(player, animation)
openInterface(player, Components.POH_WORKBENCH_397)
return@on true
}
// Ascertains the room rotation from where the stool is, to coordinate animations
val baseX = node.location.x - node.location.chunkOffsetX
val baseY = node.location.y - node.location.chunkOffsetY
for (x in 3..4) {
for (y in 3..4) {
val obj = getScenery(baseX + x, baseY + y, node.location.z) ?: continue
if (obj.id in stools) {
val directions = when (Pair(x,y)) {
Pair(3,3) -> arrayOf(Direction.WEST, Direction.NORTH, Direction.EAST)
Pair(3,4) -> arrayOf(Direction.NORTH, Direction.EAST, Direction.SOUTH)
Pair(4,3) -> arrayOf(Direction.SOUTH, Direction.WEST, Direction.NORTH)
else -> arrayOf(Direction.EAST, Direction.SOUTH, Direction.WEST)
}
setAttribute(player, ATTRIBUTE_DIRECTIONS, directions)
forceMove(player, player.location, player.location.transform(directions[0], 1),
0, ticksToCycles(1), directions[1], Animations.HUMAN_SIT_POH_STOOL_4103) {
val animation = if (obj.id == Scenery.STOOL_13720) { Animations.HUMAN_SEATED_POH_OAK_STOOL_4108 } else { Animations.HUMAN_SEATED_POH_STOOL_4107 }
animate(player, animation)
setAttribute(player, ATTRIBUTE_WORKBENCH_SEATED, true)
registerTimer(player, StaySeated())
openInterface(player, Components.POH_WORKBENCH_397)
}
return@on true
}
}
}
return@on true
}
/**
* Handles upgrading a workbench with the minimenu option.
*/
on(workbenches, IntType.SCENERY, "upgrade") { player, node ->
// I could not find any video of how this looks or what the messages are, so all messages in this listener are placeholders.
val hotspot = Hotspot(BuildHotspot.WORKBENCH, 3, 4, 4, 4)
val nodeObj = node as core.game.node.scenery.Scenery
val resultDeco = Decoration.forObjectId(node.id + 1)
if (!player.houseManager.isBuildingMode) {
sendMessage(player, "You have to be in building mode to do this.") // I don't actually know if this is true but better safe than sorry.
return@on true
}
if (getDynLevel(player, Skills.CONSTRUCTION) < resultDeco.level) {
sendMessage(player, "You need a Construction level of ${resultDeco.level} to upgrade this.")
return@on true
}
if (!inInventory(player, Items.OAK_PLANK_8778, 2) || !inInventory(player, Items.STEEL_BAR_2353)) {
sendMessage(player, "You need two oak planks and a steel bar to upgrade this.")
return@on true
}
if (!inInventory(player, Items.HAMMER_2347) || !inInventory(player, Items.SAW_8794)) {
sendMessage(player, "You need a hammer and a saw to upgrade this.")
return@on true
}
if (removeItemsIfPlayerHasEnough(player, Item(Items.OAK_PLANK_8778, 2), Item(Items.STEEL_BAR_2353))) {
queueScript(player, 0, QueueStrength.SOFT) { stage ->
when (stage) {
0 -> {
lock(player, BuildingUtils.BUILD_MID_ANIM.duration)
// Replaces the workbench with the upgraded form in HouseManager but not immediately in the instance
BuildingUtils.buildDecoration(player, hotspot, resultDeco, nodeObj, true, false)
return@queueScript delayScript(player, BuildingUtils.BUILD_MID_ANIM.duration)
}
1 -> {
// Temporary replacement until POH can rebuild on next entrance with the correct workbench
replaceScenery(nodeObj, resultDeco.objectId, -1)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
return@on true
}
}
override fun defineInterfaceListeners() {
/**
* Directs the player to the appropriate decoration building interface.
*/
on(Components.POH_WORKBENCH_397) { player, _, _, buttonID, _, _ ->
val index = buttonID - 111
if (index < 0 || index >= decoCategories.size) return@on false
val hotspot = decoCategories[index]
setAttribute(player, ATTRIBUTE_WORKBENCH_SELECTION, hotspot)
setAttribute(player, ATTRIBUTE_FLATPACK_MODE, true)
BuildingUtils.openBuildInterface(player, hotspot)
return@on true
}
onClose(Components.POH_WORKBENCH_397) { player, _ ->
if (!getAttribute(player, ATTRIBUTE_FLATPACK_MODE, false)) {
removeAttributes(player, ATTRIBUTE_FLATPACK_MODE, ATTRIBUTE_WORKBENCH_SELECTION, ATTRIBUTE_WORKBENCH_ID)
}
return@onClose true
}
onClose(Components.POH_DECORATION_396) { player, _ ->
removeAttributes(player, ATTRIBUTE_FLATPACK_MODE, ATTRIBUTE_WORKBENCH_SELECTION, ATTRIBUTE_WORKBENCH_ID)
return@onClose true
}
}
}