Repository reorganisation

Unified kotlin and java into just src/main
Unified the rs09 and core packages
Took all content out of the core package, and placed it into the new content package
Reorganised all source code relating to content to be easier to find and explore
This commit is contained in:
Ceikry
2023-01-26 13:59:28 +00:00
committed by Ryan
parent e4b799c44a
commit a100affda2
3156 changed files with 24205 additions and 30585 deletions
@@ -0,0 +1,187 @@
package content.global.handlers.scenery
import core.api.*
import core.game.node.Node
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.IronmanMode
import core.game.node.item.Item
import core.game.world.map.Direction
import core.game.world.map.Location
import org.rs09.consts.NPCs
import org.rs09.consts.Scenery
import core.ServerConstants
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import content.global.handlers.npc.BankerNPC
import core.game.world.repository.Repository
/**
* Allows the user to interact with bank booths.
*
* @author vddCore
*/
class BankBoothListener : InteractionListener {
companion object {
val INOPERABLE_BANK_BOOTHS = intArrayOf(
Scenery.BANK_BOOTH_12800, Scenery.BANK_BOOTH_12801, Scenery.BANK_BOOTH_36262, Scenery.BANK_BOOTH_35648
)
val BANK_BOOTHS = intArrayOf(
Scenery.BANK_BOOTH_2213, Scenery.BANK_BOOTH_2214, Scenery.BANK_BOOTH_3045, Scenery.BANK_BOOTH_5276,
Scenery.BANK_BOOTH_6084, Scenery.BANK_BOOTH_10517, Scenery.BANK_BOOTH_11338, Scenery.BANK_BOOTH_11402,
Scenery.BANK_BOOTH_11758, Scenery.BANK_BOOTH_12798, Scenery.BANK_BOOTH_12799, Scenery.BANK_BOOTH_14367,
Scenery.BANK_BOOTH_14368, Scenery.BANK_BOOTH_16700, Scenery.BANK_BOOTH_18491, Scenery.BANK_BOOTH_19230,
Scenery.BANK_BOOTH_20325, Scenery.BANK_BOOTH_20326, Scenery.BANK_BOOTH_20327, Scenery.BANK_BOOTH_20328,
Scenery.BANK_BOOTH_22819, Scenery.BANK_BOOTH_24914, Scenery.BANK_BOOTH_25808, Scenery.BANK_BOOTH_26972,
Scenery.BANK_BOOTH_29085, Scenery.BANK_BOOTH_30015, Scenery.BANK_BOOTH_30016, Scenery.BANK_BOOTH_34205,
Scenery.BANK_BOOTH_34752, Scenery.BANK_BOOTH_35647, Scenery.BANK_BOOTH_36786, Scenery.BANK_BOOTH_37474
)
}
/**
* Searches an area in the order described
* by each number with X being the location
* of node being interacted with.
*
* [1]
* [4][X][2]
* [3]
*/
private fun locateAdjacentBankerLinear(node: Node): NPC? {
for (dir in arrayOf(Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST)) {
Repository.findNPC(node.location.transform(dir))?.let { return it as? BankerNPC }
}
return null
}
/**
* If size is 1 then the following method
* searches a square area in the following
* order with X being the location of node
* that was interacted with.
*
* ->[ ]
* [ X ]
* [ ]->
*
*/
private fun locateAdjacentBankerSquare(node: Node, size: Int = 1): NPC? {
for (y in (node.location.y - size)..(node.location.y + size)) {
for (x in (node.location.x - size)..(node.location.x + size)) {
Repository.findNPC(Location(x, y))?.let { return it as? BankerNPC }
}
}
return null
}
private fun tryInvokeBankerDialogue(player: Player, node: Node) {
/**
* First, we look for regular bankers that neatly stand in front of the bank booth.
* If that fails, we expand the search to a larger area.
*/
(locateAdjacentBankerLinear(node) ?: locateAdjacentBankerSquare(node, 2))?.let {
if (core.game.dialogue.DialogueInterpreter.contains(it.id)) {
it.faceLocation(node.location)
openDialogue(player, it.id, NPC(it.id, it.location))
} else {
openDialogue(player, NPCs.BANKER_494)
}
}
}
private fun quickBankBoothUse(player: Player, node: Node): Boolean {
if (player.ironmanManager.checkRestriction(IronmanMode.ULTIMATE)) {
return true
}
if (BankerNPC.checkLunarIsleRestriction(player, node)) {
tryInvokeBankerDialogue(player, node)
return true
}
openBankAccount(player)
return true
}
private fun regularBankBoothUse(player: Player, node: Node): Boolean {
if (player.ironmanManager.checkRestriction(IronmanMode.ULTIMATE)) {
return true
}
if (ServerConstants.BANK_BOOTH_QUICK_OPEN) {
return quickBankBoothUse(player, node)
}
tryInvokeBankerDialogue(player, node)
return true
}
private fun collectBankBoothUse(player: Player, node: Node): Boolean {
if (BankerNPC.checkLunarIsleRestriction(player, node)) {
tryInvokeBankerDialogue(player, node)
return true
}
openGrandExchangeCollectionBox(player)
return true
}
private fun attemptToConvertItems(player: Player, used: Node, with: Node): Boolean {
if (!hasOption(with, "use")) {
sendMessage(player, "You shouldn't be able to do that with object ${with.id}.")
sendMessage(player, "Please screenshot this and report to the developers.")
return true
}
if (!ServerConstants.BANK_BOOTH_NOTE_UIM && player.ironmanManager.checkRestriction(IronmanMode.ULTIMATE)) {
return true
}
if (BankerNPC.checkLunarIsleRestriction(player, with)) {
tryInvokeBankerDialogue(player, with)
return true
}
val item = used as Item
if (item.noteChange != item.id) {
if (item.definition.isUnnoted) {
val amount = amountInInventory(player, item.id)
if (removeItem(player, Item(item.id, amount))) {
addItem(player, item.noteChange, amount)
}
} else {
var amount = item.amount
val freeSlotCount = freeSlots(player)
if (amount > freeSlotCount) {
amount = freeSlotCount
}
if (removeItem(player, Item(item.id, amount))) {
addItem(player, item.noteChange, amount)
}
}
return true
}
sendMessage(player, "This item can't be noted.")
return true
}
override fun defineListeners() {
on(BANK_BOOTHS, IntType.SCENERY, "use-quickly", "bank", handler = ::quickBankBoothUse)
on(BANK_BOOTHS, IntType.SCENERY, "use", handler = ::regularBankBoothUse)
on(BANK_BOOTHS, IntType.SCENERY, "collect", handler = ::collectBankBoothUse)
if (ServerConstants.BANK_BOOTH_NOTE_ENABLED) {
onUseAnyWith(IntType.SCENERY, *BANK_BOOTHS, handler = ::attemptToConvertItems)
}
}
}
@@ -0,0 +1,28 @@
package content.global.handlers.scenery
import core.api.openBankAccount
import org.rs09.consts.Scenery
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
private val BANK_CHESTS = intArrayOf(
Scenery.BANK_CHEST_3194, Scenery.BANK_CHEST_4483,
Scenery.BANK_CHEST_10562, Scenery.BANK_CHEST_14382,
Scenery.BANK_CHEST_16695, Scenery.BANK_CHEST_16696,
Scenery.BANK_CHEST_21301, Scenery.BANK_CHEST_27662,
Scenery.BANK_CHEST_27663
)
/**
* Allows the user to interact with Bank Chests.
*
* @author vddCore
*/
class BankChestListener : InteractionListener {
override fun defineListeners() {
on(BANK_CHESTS, IntType.SCENERY, "bank", "use") { player, node ->
openBankAccount(player)
return@on true
}
}
}
@@ -0,0 +1,60 @@
package content.global.handlers.scenery
import core.api.restrictForIronman
import core.game.component.CloseEvent
import core.game.component.Component
import core.game.container.access.InterfaceContainer
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.IronmanMode
import org.rs09.consts.Components
import org.rs09.consts.Scenery
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
private val BANK_DEPOSIT_BOXES = intArrayOf(
Scenery.BANK_DEPOSIT_BOX_9398,
Scenery.BANK_DEPOSIT_BOX_20228,
Scenery.BANK_DEPOSIT_BOX_25937,
Scenery.BANK_DEPOSIT_BOX_26969,
Scenery.BANK_DEPOSIT_BOX_34755,
Scenery.BANK_DEPOSIT_BOX_36788,
Scenery.BANK_DEPOSIT_BOX_39830
)
/**
* Allows the user to interact with bank deposit boxes.
*
* @author vddCore
*/
class BankDepositBoxListener : InteractionListener {
private fun openDepositBox(player: Player, node: Node) : Boolean {
restrictForIronman(player, IronmanMode.ULTIMATE) {
player.interfaceManager.open(Component(Components.BANK_DEPOSIT_BOX_11)).closeEvent = CloseEvent { p, _ ->
p.interfaceManager.openDefaultTabs()
return@CloseEvent true
}
player.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6)
InterfaceContainer.generateItems(
player,
player.inventory.toArray(),
arrayOf(
"Examine",
"Deposit-X",
"Deposit-All",
"Deposit-10",
"Deposit-5",
"Deposit-1"
), 11, 15, 5, 7
)
}
return true
}
override fun defineListeners() {
on(BANK_DEPOSIT_BOXES, IntType.SCENERY, "deposit", handler = ::openDepositBox)
}
}
@@ -0,0 +1,40 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the doogle leaf plugin for this object.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public class DoogleLeafPlugin extends OptionHandler {
/**
* Represents the leaf item.
*/
private static final Item LEAF = new Item(1573, 1);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(31155).getHandlers().put("option:pick-leaf", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
if (!player.getInventory().add(LEAF)) {
player.getPacketDispatch().sendMessage("You don't have have enough space in your inventory.");
} else {
player.getPacketDispatch().sendMessage("You pick some doogle leaves.");
}
return true;
}
}
@@ -0,0 +1,82 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.global.action.DoorActionHandler;
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.node.scenery.SceneryBuilder;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Plugin used for handling the opening/closing of (double)
* doors/gates/fences/...
* @author Emperor
*/
@Initializable
public final class DoorManagingPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.setOptionHandler("open", this);
SceneryDefinition.setOptionHandler("close", this);
SceneryDefinition.setOptionHandler("shut", this);
SceneryDefinition.setOptionHandler("go-through", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Scenery object = (Scenery) node;
if (object.getType() != 9 && !player.getLocation().equals(node.getLocation()) && !player.getLocation().isNextTo(object) && object.getName().contains("cupboard")) {
return true;
}
String name = object.getName().toLowerCase();
if (name.contains("drawers") || name.contains("wardrobe") || name.contains("cupboard")) {
switch(option) {
case "open":
case "go-through":
if (object.isActive()) {
SceneryBuilder.replace(object, object.transform(object.getId() + 1), 80);
}
return true;
case "close":
case "shut":
SceneryBuilder.replace(object, object.transform(object.getId() - 1));
return true;
}
return true;
}
if (name.contains("trapdoor") || name.contains("trap door")) {
Location destination = object.getLocation().transform(0, 6400, 0);
if (!RegionManager.isTeleportPermitted(destination)) {
player.getPacketDispatch().sendMessage("This doesn't seem to go anywhere.");
return true;
}
player.getProperties().setTeleportLocation(destination);
return true;
}
if (node.asScenery().getId() == 25341) {// Mithril door
return false;
}
if (!name.contains("door") && !name.contains("gate") && !name.contains("fence") && !name.contains("wall") && !name.contains("exit") && !name.contains("entrance")) {
return false;
}
DoorActionHandler.handleDoor(player, object);
return true;
}
@Override
public Location getDestination(Node n, Node node) {
Scenery o = (Scenery) node;
if (o.getType() < 4 || o.getType() == 9) {
return DoorActionHandler.getDestination((Player) n, o);
}
return null;
}
}
@@ -0,0 +1,259 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.container.impl.EquipmentContainer;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.plugin.Initializable;
import core.tools.RandomFunction;
/**
* Handles the pick option of interactive scenery (non-farming cabbages,
* potatoes, bananas, etc)
* @author Emperor
* @version 1.0
*/
@Initializable
public final class FieldPickingPlugin extends OptionHandler {
/**
* The picking animation to use.
*/
private static final Animation ANIMATION = new Animation(827);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for(PickingPlant p : PickingPlant.values()){
SceneryDefinition.forId(p.objectId).getHandlers().put("option:pick",this);
}
SceneryDefinition.forId(3511).getHandlers().put("option:take-cutting",this);
return this;
}
@Override
public boolean handle(final Player player, Node node, String option) {
if (player.getAttribute("delay:picking", -1) > GameWorld.getTicks()) {
return true;
}
final Scenery object = (Scenery) node;
final PickingPlant plant = PickingPlant.forId(object.getId());
if (plant == null) {
return false;
}
if (!object.isActive()) {
return true;
}
final Item reward = new Item(plant == PickingPlant.POTATO && RandomFunction.random(10) == 0 ? 5318 : plant.reward);
if (!player.getInventory().hasSpaceFor(reward)) {
player.getPacketDispatch().sendMessage("Not enough space in your inventory!");
return true;
}
if (player.getInventory().freeSlot() == -1) {
return true;
}
player.lock(1);
player.setAttribute("delay:picking", GameWorld.getTicks() + (plant == PickingPlant.FLAX ? 2 : 3));
player.animate(ANIMATION);
if (plant.name().startsWith("NETTLES") && (player.getEquipment().get(EquipmentContainer.SLOT_HANDS) == null || player.getEquipment().get(EquipmentContainer.SLOT_HANDS) != null && !player.getEquipment().get(EquipmentContainer.SLOT_HANDS).getName().contains("glove"))) {
player.getPacketDispatch().sendMessage("You have been stung by the nettles!");
player.getImpactHandler().manualHit(player, 2, HitsplatType.POISON);
return true;
}
if (plant.respawn != -1 && plant != PickingPlant.FLAX) {
object.setActive(false);
}
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
if (!player.getInventory().add(reward)) {
player.getPacketDispatch().sendMessage("Not enough space in your inventory!");
return true;
}
if (plant == PickingPlant.FLAX) {
handleFlaxPick(player, object, plant);
return true;
}
boolean banana = plant.name().startsWith("BANANA");
Scenery full = null;
if (plant == PickingPlant.BANANA_TREE_4) {
full = object.transform(2073);
SceneryBuilder.replace(object, full);
}
boolean isBloomPlant = plant == PickingPlant.FUNGI_ON_LOG
|| plant == PickingPlant.BUDDING_BRANCH
|| plant == PickingPlant.GOLDEN_PEAR_BUSH;
if (isBloomPlant) {
full = object.transform(object.getId() - 1);
SceneryBuilder.replace(object, full);
}
if (!isBloomPlant) {
SceneryBuilder.replace(plant == PickingPlant.BANANA_TREE_4 ? full : object, object.transform(banana ? plant.respawn : 0), banana ? 300 : plant.respawn);
}
if (!plant.name().startsWith("NETTLES")) {
player.getPacketDispatch().sendMessage("You pick a " + reward.getName().toLowerCase() + ".");
} else {
player.getPacketDispatch().sendMessage("You pick a handful of nettles.");
}
if (banana && !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.KARAMJA, 0, 0)) {
int picked = player.getAttribute("b-picked", 0);
picked++;
player.setAttribute("b-picked", picked);
player.getAchievementDiaryManager().updateTask(player, DiaryType.KARAMJA, 0, 0, picked == 5);
}
return true;
}
});
return true;
}
/**
* Method used to handle the flax picking.
* @param player the player.
* @param object the object.
* @param plant the plank.
*/
private void handleFlaxPick(final Player player, final Scenery object, final PickingPlant plant) {
int charge = object.getCharge();
player.getAudioManager().send(2581);
player.getPacketDispatch().sendMessage("You pick some flax.");
// Seers achievement diary
if (player.getViewport().getRegion().getId() == 10805
&& !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(0,0)) {
if (player.getAttribute("diary:seers:flax-picked", 0) >= 4) {
player.setAttribute("/save:diary:seers:flax-picked", 5);
player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).updateTask(player,0,0,true);
} else {
player.setAttribute("/save:diary:seers:flax-picked", player.getAttribute("diary:seers:flax-picked", 0) + 1);
}
}
if (charge > 1000 + RandomFunction.random(2, 8)) {
object.setActive(false);
object.setCharge(1000);
SceneryBuilder.replace(object, object.transform(0), plant.respawn);
return;
}
object.setCharge(charge + 1);
}
/**
* Represents a plant to be picked.
* @author Emperor
*/
private static enum PickingPlant {
POTATO(312, 1942, 30),
WHEAT_0(313, 1947, 30),
WHEAT_1(5583, 1947, 30),
WHEAT_2(5584, 1947, 30),
WHEAT_3(5585, 1947, 30),
WHEAT_4(15506, 1947, 30),
WHEAT_5(15507, 1947, 30),
WHEAT_6(15508, 1947, 30),
WHEAT_7(22300, 1947, 30),
WHEAT_8(22473, 1947, 30),
WHEAT_9(22474, 1947, 30),
WHEAT_10(22475, 1947, 30),
WHEAT_11(22476, 1947, 30),
CABBAGE_0(1161, 1965, 30),
CABBAGE_1(11494, 1967, 30),
CABBAGE_2(22301, 1965, 30),
NETTLES_0(1181, 4241, 30),
NETTLES_1(5253, 4241, 30),
NETTLES_2(5254, 4241, 30),
NETTLES_3(5255, 4241, 30),
NETTLES_4(5256, 4241, 30),
NETTLES_5(5257, 4241, 30),
NETTLES_6(5258, 4241, 30),
PINEAPPLE_PLANT_0(1408, 2114, 30),
PINEAPPLE_PLANT_1(1409, 2114, 30),
PINEAPPLE_PLANT_2(1410, 2114, 30),
PINEAPPLE_PLANT_3(1411, 2114, 30),
PINEAPPLE_PLANT_4(1412, 2114, 30),
PINEAPPLE_PLANT_5(1413, 2114, 30),
PINEAPPLE_PLANT_6(4827, 2114, 30),
BANANA_TREE_0(2073, 1963, 2074),
BANANA_TREE_1(2074, 1963, 2075),
BANANA_TREE_2(2075, 1963, 2076),
BANANA_TREE_3(2076, 1963, 2077),
BANANA_TREE_4(2077, 1963, 2078),
BANANA_TREE_5(12606, 1963, 2079),
BANANA_TREE_6(12607, 1963, 2080),
FLAX(2646, 1779, 30),
ONION_0(3366, 1957, 30),
ONION_1(5538, 1957, 30),
FUNGI_ON_LOG(3509, 2970, -1),
BUDDING_BRANCH(3511, 2972, -1),
GOLDEN_PEAR_BUSH(3513, 2974, -1),
GLOWING_FUNGUS_0(4932, 4075, 30),
GLOWING_FUNGUS_1(4933, 4075, 30),
RARE_FLOWERS(5006, 2460, 30),
BLACK_MUSHROOMS(6311, 4620, 30),
KELP(12478, 7516, 30),
RED_BANANA_TREE(12609, 7572, 30),
BUSH(12615, 7573, 30),
RED_FLOWERS(15846, 8938, 30),
BLUE_FLOWERS(15872, 8936, 30),
HARDY_GOUTWEED(18855, 3261, 30),
HERBS_0(21668, 199, 30),
HERBS_1(21669, 201, 30),
HERBS_2(21670, 203, 30),
HERBS_3(21671, 205, 30),
FEVER_GRASS(29113, 12574, 30),
LAVENDER(29114, 12572, 30),
TANSYMUM(29115, 12576, 30),
PRIMWEED(29116, 12588, 30),
STINKBLOOM(29117, 12590, 30),
TROLLWEISS_FLOWERS(37328, 4086, 30),
HOLLOW_LOG(37830, 10968, 30);
/**
* The object id.
*/
final int objectId;
/**
* The reward item id.
*/
final int reward;
/**
* The respawn duration.
*/
final int respawn;
/**
* Constructs a new {@code FieldPickingPlugin {@code Object}.
* @param objectId the object id.
* @param reward the reward.
* @param respawn the resapwn.
*/
private PickingPlant(int objectId, int reward, int respawn) {
this.objectId = objectId;
this.reward = reward;
this.respawn = respawn;
}
/**
* Gets the picking plant by the id.
* @param objectId the id.
* @return the picking plant.
*/
static PickingPlant forId(int objectId) {
for (PickingPlant plant : values())
if (plant.objectId == objectId)
return plant;
return null;
}
}
}
@@ -0,0 +1,66 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.game.dialogue.FacialExpression;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Represents the haystack plugin.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class HaystackPlugin extends OptionHandler {
/**
* Represents the needle to give.
*/
private static final Item NEEDLE = new Item(1733);
/**
* Represents the animation.
*/
private static final Animation ANIMATION = new Animation(827);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(298).getHandlers().put("option:search", this);
SceneryDefinition.forId(299).getHandlers().put("option:search", this);
SceneryDefinition.forId(300).getHandlers().put("option:search", this);
SceneryDefinition.forId(304).getHandlers().put("option:search", this);
SceneryDefinition.forId(36892).getHandlers().put("option:search", this);
SceneryDefinition.forId(36893).getHandlers().put("option:search", this);
SceneryDefinition.forId(36894).getHandlers().put("option:search", this);
SceneryDefinition.forId(36895).getHandlers().put("option:search", this);
SceneryDefinition.forId(36896).getHandlers().put("option:search", this);
SceneryDefinition.forId(36897).getHandlers().put("option:search", this);
SceneryDefinition.forId(36898).getHandlers().put("option:search", this);
SceneryDefinition.forId(36899).getHandlers().put("option:search", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
final Scenery object = ((Scenery) node);
final int rand = RandomFunction.random(50);
player.lock(2);
player.animate(ANIMATION);
player.getPacketDispatch().sendMessage("You search the " + object.getName().toLowerCase() + "...");
if (rand == 1 && player.getInventory().freeSlots() > 0 || player.getInventory().containsItem(NEEDLE)) {
player.getInventory().add(NEEDLE);
player.getDialogueInterpreter().sendDialogues(player, FacialExpression.HALF_GUILTY, "Wow! A needle!", "Now what are the chances of finding that?");
return true;
}
player.getPacketDispatch().sendMessage("You find nothing of interest.");
return true;
}
}
@@ -0,0 +1,63 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import content.global.skill.agility.AgilityHandler;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.OptionHandler;
import core.game.interaction.UseWithHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
/**
* Handles the janger berry plugin.
* @author Vexia
*/
@Initializable
public class JangerBerryPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
UseWithHandler.addHandler(2326, UseWithHandler.OBJECT_TYPE, new UseWithHandler(954) {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
Scenery object = event.getUsedWith().asScenery();
if (object.isActive())
SceneryBuilder.replace(object, object.transform(2325));
event.getPlayer().getInventory().remove(event.getUsedItem());
return true;
}
});
SceneryDefinition.forId(2325).getHandlers().put("option:swing-on", this);
SceneryDefinition.forId(2324).getHandlers().put("option:swing-on", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
if (!player.getLocation().withinDistance(node.getLocation(), 2)) {
player.sendMessage("I can't reach that.");
return true;
}
Location end = node.getId() == 2325 ? new Location(2505, 3087, 0) : new Location(2511, 3096, 0);
player.getPacketDispatch().sendSceneryAnimation(node.asScenery(), Animation.create(497), true);
AgilityHandler.forceWalk(player, 0, player.getLocation(), end, Animation.create(751), 50, 22, "You skillfully swing across.", 1);
return true;
}
@Override
public Location getDestination(Node node, Node n) {
return n.getId() == 2324 ? new Location(2511, 3092, 0) : new Location(2501, 3087, 0);
}
}
@@ -0,0 +1,40 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.global.action.ClimbActionHandler;
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.Location;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used for managing ladders.
* @author Emperor
* @version 2.0
*/
@Initializable
public final class LadderManagingPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.setOptionHandler("climb-up", this);
SceneryDefinition.setOptionHandler("climb-down", this);
SceneryDefinition.setOptionHandler("climb", this);
return this;
}
@Override
public boolean handle(final Player player, Node node, final String option) {
ClimbActionHandler.climbLadder(player, (Scenery) node, option);
return true;
}
@Override
public Location getDestination(Node n, Node object) {
return ClimbActionHandler.getDestination((Scenery) object);
}
}
@@ -0,0 +1,27 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
@Initializable
public class LookAtOptionPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (int i = 18877; i <= 18900; i++)
{
SceneryDefinition.forId(i).getHandlers().put("option:look at", this);
}
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getPacketDispatch().sendMessage("The " + node.getName().toLowerCase() + " seem to be going south-west.");
return true;
}
}
@@ -0,0 +1,100 @@
package content.global.handlers.scenery
import core.api.*
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.audio.Audio
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import org.rs09.consts.Scenery
private const val GRAIN = Items.GRAIN_1947
private const val SWEETCORN = Items.SWEETCORN_5986
private const val EMPTY_POT = Items.EMPTY_POT_1931
private const val POT_OF_FLOUR = Items.POT_OF_FLOUR_1933
private const val POT_OF_CORNFLOUR = Items.POT_OF_CORNFLOUR_7468
private val HOPPERS = intArrayOf(Scenery.HOPPER_36881, Scenery.HOPPER_2717, Scenery.HOPPER_24071, Scenery.HOPPER_2716, Scenery.HOPPER_22422)
private val HOPPER_CONTROLS = intArrayOf(Scenery.HOPPER_CONTROLS_2718, Scenery.HOPPER_CONTROLS_2721, Scenery.HOPPER_CONTROLS_24072, Scenery.HOPPER_CONTROLS_2720, Scenery.LEVER_22424)
private val FLOUR_BINS = intArrayOf(Scenery.FLOUR_BIN_1782, Scenery.FLOUR_BIN_5792, Scenery.FLOUR_BIN_22420, Scenery.FLOUR_BIN_22421, Scenery.FLOUR_BIN_24070, Scenery.FLOUR_BIN_36878)
private const val VARP = 695
private val ANIMATION = Animation(3571)
private val SOUND = Audio(3189)
/**
* Handles interactions with windmills
* @author itsmedoggo
*/
class MillingListener : InteractionListener {
override fun defineListeners() {
on(HOPPER_CONTROLS, SCENERY, "operate", "pull") { player, _ ->
useHopperControl(player)
return@on true
}
on(FLOUR_BINS, SCENERY, "empty") { player, _ ->
fillPot(player)
return@on true
}
onUseWith(SCENERY, intArrayOf(GRAIN, SWEETCORN), *HOPPERS) { player, used, _ ->
fillHopper(player, used.asItem())
return@onUseWith true
}
onUseWith(SCENERY, EMPTY_POT, *FLOUR_BINS) { player, _, _ ->
fillPot(player)
return@onUseWith true
}
}
private fun useHopperControl(player: Player) {
animate(player, ANIMATION)
val hopperContents = getAttribute(player, "milling:hopper", 0)
if (hopperContents == 0) {
sendMessage(player, "You operate the empty hopper. Nothing interesting happens.")
return
}
setAttribute(player, "/save:milling:hopper", 0)
when (hopperContents) {
GRAIN -> {
setAttribute(player, "/save:milling:grain", (getAttribute(player, "milling:grain", 0) + 1).coerceAtMost(30 - getAttribute(player, "milling:sweetcorn", 0)))
sendMessage(player, "You operate the hopper. The grain slides down the chute.")
}
SWEETCORN -> {
setAttribute(player, "/save:milling:sweetcorn", (getAttribute(player, "milling:sweetcorn", 0) + 1).coerceAtMost(30 - getAttribute(player, "milling:grain", 0)))
sendMessage(player, "You operate the hopper. The sweetcorn slides down the chute.")
}
}
playAudio(player, SOUND)
setVarbit(player, VARP, 0, 1, true)
}
private fun fillHopper(player: Player, used: Item) {
if (getAttribute(player, "milling:hopper", 0) == 0 && removeItem(player, used)) {
setAttribute(player, "/save:milling:hopper", used.id)
sendMessage(player, "You put the " + used.name.lowercase() + " in the hopper.")
return
}
sendMessage(player, "There is already " + getItemName(getAttribute(player, "milling:hopper", 0)).lowercase() + " in the hopper.")
}
private fun fillPot(player: Player) {
if (!inInventory(player, EMPTY_POT)) {
sendMessage(player, "I need an empty pot to hold the flour in.")
return
}
if (removeItem(player, EMPTY_POT)) {
if (getAttribute(player, "milling:sweetcorn", 0) > 0) {
setAttribute(player, "/save:milling:sweetcorn", (getAttribute(player, "milling:sweetcorn", 0) - 1))
addItem(player, POT_OF_CORNFLOUR)
sendMessage(player, if (player.getAttribute("milling:sweetcorn", 0) > 0) "You fill a pot with cornflour from the bin." else "You fill a pot with the last of the cornflour in the bin.")
}
else if (getAttribute(player, "milling:grain", 0) > 0) {
setAttribute(player, "/save:milling:grain", (getAttribute(player, "milling:grain", 0) - 1))
addItem(player, POT_OF_FLOUR)
sendMessage(player, if (player.getAttribute("milling:grain", 0) > 0) "You fill a pot with flour from the bin." else "You fill a pot with the last of the flour in the bin.")
}
if (getAttribute(player, "milling:sweetcorn", 0) + getAttribute(player, "milling:grain", 0) <= 0) {
setVarbit(player, VARP, 0, 0, true)
}
}
}
}
@@ -0,0 +1,45 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.global.action.ClimbActionHandler;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.Rights;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used for the moderator objects in the p-mod room.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class ModeratorObject extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(26806).getHandlers().put("option:climb-up", this);
SceneryDefinition.forId(26807).getHandlers().put("option:j-mod options", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (option) {
case "climb-up":
ClimbActionHandler.climb(player, new Animation(828), Location.create(3222, 3218, 0));
break;
case "j-mod options":
if (player.getDetails().getRights() == Rights.REGULAR_PLAYER) {
return true;
}
player.sendMessage("Disabled...");
break;
}
return true;
}
}
@@ -0,0 +1,120 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.CloseEvent;
import core.game.component.Component;
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.net.packet.PacketRepository;
import core.net.packet.context.MinimapStateContext;
import core.net.packet.out.MinimapState;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the reading of a sign post.
* @author 'Vexia
*/
@Initializable
public class ReadSignPostPlugin extends OptionHandler {
/**
* Represents the areas on the sign.
* @author 'Vexia
*/
public enum Signs {
NEAR_LUMBRIDGE(18493, "North to farms and<br> Varrock.", "The River Lum lies to<br> the south.", "West to<br>Lumbridge.", "East to Al<br>Kharid - toll<br>gate; bring some<br>money."), NEAR_VARROCK(24263, "Sheep lay this way.", "South through farms<br> to Al Kharid and<br> Lumbridge", "West to Champion's Guild<br> and Varrock south<br> gate.", "East to Al Kharid mine and<br> follow the path north to<br> Varrock east gate.");
public static Signs forId(int id) {
for (Signs sign : Signs.values()) {
if (sign == null) {
continue;
}
if (sign.object == id) {
return sign;
}
}
return null;
}
/**
* The object id.
*/
private int object;
/**
* The directions.
*/
private String directions[];
/**
* Constructs a new {@code ReadSignPostPlugin.java} {@code Object}.
* @param object the object.
* @param directions the directions.
*/
Signs(int object, String... directions) {
this.object = object;
this.directions = directions;
}
}
@Override
public boolean handle(Player player, Node node, String option) {
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
player.getInterfaceManager().open(new Component(135)).setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
return true;
}
});
final Scenery object = (Scenery) node;
Signs sign = Signs.forId(object.getId());
if (sign == null) {
return false;
}
String[] dirs = sign.directions;
if (object.getLocation().getX() == 3107 && object.getLocation().getY() == 3296) {
dirs[0] = "North to Draynor<br> Manor";
dirs[1] = "South to Draynor<br> Village";
dirs[2] = "West to Port<br> Sarim";
dirs[3] = "East to<br> Lumbridge";
}
player.getPacketDispatch().sendString(dirs[0], 135, 3); // North
player.getPacketDispatch().sendString(dirs[1], 135, 9); // South
player.getPacketDispatch().sendString(dirs[2], 135, 12); // West
player.getPacketDispatch().sendString(dirs[3], 135, 8); // East
return true;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(2366).getHandlers().put("option:read", this);
SceneryDefinition.forId(2367).getHandlers().put("option:read", this);
SceneryDefinition.forId(2368).getHandlers().put("option:read", this);
SceneryDefinition.forId(2369).getHandlers().put("option:read", this);
SceneryDefinition.forId(2370).getHandlers().put("option:read", this);
SceneryDefinition.forId(2371).getHandlers().put("option:read", this);
SceneryDefinition.forId(4132).getHandlers().put("option:read", this);
SceneryDefinition.forId(4133).getHandlers().put("option:read", this);
SceneryDefinition.forId(4134).getHandlers().put("option:read", this);
SceneryDefinition.forId(4135).getHandlers().put("option:read", this);
SceneryDefinition.forId(5164).getHandlers().put("option:read", this);
SceneryDefinition.forId(10090).getHandlers().put("option:read", this);
SceneryDefinition.forId(13873).getHandlers().put("option:read", this);
SceneryDefinition.forId(15522).getHandlers().put("option:read", this);
SceneryDefinition.forId(18493).getHandlers().put("option:read", this);
SceneryDefinition.forId(24263).getHandlers().put("option:read", this);
SceneryDefinition.forId(25397).getHandlers().put("option:read", this);
SceneryDefinition.forId(30039).getHandlers().put("option:read", this);
SceneryDefinition.forId(30040).getHandlers().put("option:read", this);
SceneryDefinition.forId(31296).getHandlers().put("option:read", this);
SceneryDefinition.forId(31298).getHandlers().put("option:read", this);
SceneryDefinition.forId(31299).getHandlers().put("option:read", this);
SceneryDefinition.forId(31300).getHandlers().put("option:read", this);
// ObjectDefinition.forId(31301).getConfigurations().put("option:read", this);//goblin village
return this;
}
}
@@ -0,0 +1,92 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the search option.
* @author 'Vexia
*/
@Initializable
public class SearchOptionPlugin extends OptionHandler {
/**
* Represents an object to search.
* @author 'Vexia
*/
public enum Search {
/**
* Represents a search.
*/
DEFAULT(-1, new Item(1059, 1));
public static Search forId(int id) {
for (Search search : Search.values()) {
if (search.getObject() == id) {
return search;
}
}
return null;
}
/**
* The object id.
*/
private int object;
/**
* The item rewarded.
*/
private Item item;
/**
* Constructs a new {@code SearchOptionPlugin.java}
*/
Search(int object, Item item) {
this.object = object;
this.item = item;
}
/**
* @return the item.
*/
public Item getItem() {
return item;
}
/**
* @return the object.
*/
public int getObject() {
return object;
}
}
@Override
public boolean handle(Player player, Node node, String option) {
if (node.getName().equals("Bookcase")) {
player.getPacketDispatch().sendMessage("You search the books...");
player.getPacketDispatch().sendMessage("You find nothing of interest to you.");
return true;
}
if (node.getId() == 14743 && !player.getInventory().containItems(946) && !player.inCombat()) {
player.getPacketDispatch().sendMessage("You mindlessly reach into the sack labeled 'knives'...");
player.getPacketDispatch().sendMessage("Against all odds you pull out a knife without hurting yourself.",2);
player.getInventory().add(new Item(946));
return true;
}
player.getPacketDispatch().sendMessage("You search the " + node.getName().toLowerCase() + " but find nothing.");
return true;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.setOptionHandler("search", this);
return this;
}
}
@@ -0,0 +1,149 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.container.Container;
import core.game.container.impl.EquipmentContainer;
import core.plugin.Initializable;
import org.rs09.consts.Items;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.combat.equipment.WeaponInterface.AttackStyle;
import core.game.node.entity.combat.equipment.WeaponInterface.WeaponInterfaces;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.entity.player.link.audio.Audio;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the slashing of a web object.
* @author Vexia
* @version 2.0
*/
@Initializable
public final class SlashWebPlugin extends OptionHandler {
/**
* Represents the object ids.
*/
private static final int[] IDS = new int[] { 733, 1810, 11400, 33237 };
/**
* Represents the animation of slashing a web.
*/
private static final Animation ANIMATION = new Animation(451);
/**
* Represents the knife animation.
*/
private static final Animation KNIFE_ANIMATION = new Animation(911);
/**
* Represents the knife item.
*/
private static final Item KNIFE = new Item(946);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (int objectId : IDS) {
SceneryDefinition.forId(objectId).getHandlers().put("option:slash", this);
}
SceneryDefinition.forId(27266).getHandlers().put("option:pass", this);
SceneryDefinition.forId(29354).getHandlers().put("option:pass", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
final Scenery object = (Scenery) node;
Item weapon = getWeapon(player, player.getEquipment());
if (weapon == null) {
weapon = getWeapon(player, player.getInventory());
if (weapon == null) {
if (!player.getInventory().containsItem(KNIFE)) {
player.getPacketDispatch().sendMessage("Only a sharp blade can cut through this sticky web.");
return true;
}
weapon = KNIFE;
}
}
final boolean success = RandomFunction.random(2) == 1;
player.lock(2);
player.getAudioManager().send(new Audio(2548));
player.animate(weapon == KNIFE ? KNIFE_ANIMATION : ANIMATION);
if (success) {
player.getPacketDispatch().sendMessage("You slash the web apart.");
SceneryBuilder.replace(object, object.getId() == 27266 || object.getId() == 29354 ? object.transform(734) : object.transform(object.getId() + 1), 100);
// Venture through the cobwebbed corridor in Varrock Sewers
if (object.getId() == 29354) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.VARROCK, 0, 17);
}
// Escape from the spider lair in Varrock Sewers with some red<br><br>spiders eggs
if (object.getId() == 29354 && player.getInventory().containsAtLeastOneItem(Items.RED_SPIDERS_EGGS_223) && player.getLocation().getY() <= 9897) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.VARROCK, 1, 4);
}
} else {
player.getPacketDispatch().sendMessage("You fail to cut through it.");
}
return true;
}
/**
* Gets the slashed weapon item.
* @param player the player.
* @param container the container.
* @return the item.
*/
private Item getWeapon(final Player player, final Container container) {
Item item = container instanceof EquipmentContainer ? container.get(EquipmentContainer.SLOT_WEAPON) : null;
if (container instanceof EquipmentContainer) {
return checkEquipmentWeapon(player, item);
}
for (Item i : container.toArray()) {
if (i == null) {
continue;
}
if (i.getDefinition().hasAction("wield") || i.getDefinition().hasAction("equip")) {
item = checkEquipmentWeapon(player, i);
if (item != null) {
return item;
}
} else {
continue;
}
}
return item;
}
/**
* Checks an equipment weapon.
* @param player the player.
* @param item the item.
* @return {@code Item} the item.
*/
private Item checkEquipmentWeapon(final Player player, final Item item) {
if (item != null) {
WeaponInterfaces inter = WeaponInterface.getWeaponInterface(item);
if (inter == null) {
return null;
}
boolean success = false;
for (AttackStyle style : inter.getAttackStyles()) {
if (style.getBonusType() == WeaponInterface.BONUS_SLASH) {
return item;
}
}
if (!success) {
return null;
}
}
return item;
}
}
@@ -0,0 +1,28 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* @author 'Vexia
*/
@Initializable
public class SlayerDangerSignPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(5127).getHandlers().put("option:read", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getDialogueInterpreter().sendDialogue("<col=FFF0000>WARNING!", "</col>This area contains very dangerous creatures!", "Do not pass unless properly prepared!");
return true;
}
}
@@ -0,0 +1,45 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.Component;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the spining interface open.
* @author Adam
*/
@Initializable
public class SpinSpinningWheelPlugin extends OptionHandler {
@Override
public boolean handle(Player player, Node node, String option) {
player.getInterfaceManager().open(new Component(459));
return true;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(2644).getHandlers().put("option:spin", this);
SceneryDefinition.forId(4309).getHandlers().put("option:spin", this);
SceneryDefinition.forId(8748).getHandlers().put("option:spin", this);
SceneryDefinition.forId(20365).getHandlers().put("option:spin", this);
SceneryDefinition.forId(21304).getHandlers().put("option:spin", this);
SceneryDefinition.forId(25824).getHandlers().put("option:spin", this);
SceneryDefinition.forId(26143).getHandlers().put("option:spin", this);
SceneryDefinition.forId(34497).getHandlers().put("option:spin", this);
SceneryDefinition.forId(36970).getHandlers().put("option:spin", this);
SceneryDefinition.forId(37476).getHandlers().put("option:spin", this);
return this;
}
@Override
public Location getDestination(Node node, Node n) {
return null;
}
}
@@ -0,0 +1,189 @@
package content.global.handlers.scenery;
import core.cache.def.impl.SceneryDefinition;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
import core.game.node.entity.impl.Animator.Priority;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
import core.game.node.item.ChanceItem;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.system.task.Pulse;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import core.game.world.GameWorld;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represents the thieving guide plugin.
* @author 'Vexia
* @date 16/11/2013
*/
@Initializable
public class ThievingGuidePlugin extends OptionHandler {
/**
* The coin looots.
*/
private static final ChanceItem[] COINS = new ChanceItem[] { new ChanceItem(995, 20, 20, 90), new ChanceItem(995, 40, 40, 80) };
/**
* The gem items.
*/
private static final ChanceItem[] GEMS = new ChanceItem[] { new ChanceItem(1623, 1, 1, 80), new ChanceItem(1621, 1, 1, 60), new ChanceItem(1619, 1, 1, 8), new ChanceItem(1617, 1, 1, 7) };
/**
* Represents the stethoscope item.
*/
private static final Item SETHOSCOPE = new Item(5560);
/**
* Represents the required level to crack a safe.
*/
private static final int level = 50;
/**
* Represents the experience gained.
*/
private static final double experience = 70;
/**
* Represents the animations to use.
*/
private static final Animation[] animations = new Animation[] { new Animation(2247), new Animation(2248), new Animation(1113), new Animation(2244) };
/**
* Represents the cracked safe.
*/
private static final int CRACKED_SAFE = 7238;
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(7236).getHandlers().put("option:crack", this);// wall
// safe.
SceneryDefinition.forId(7227).getHandlers().put("option:disarm", this);// trap
SceneryDefinition.forId(7256).getHandlers().put("option:open", this);
return this;
}
@Override
public boolean handle(final Player player, final Node node, String option) {
switch (option) {
case "open":
player.getDialogueInterpreter().sendDialogues(2266, null, "And where do you think you're going? A little too eager", "I think. Come and talk to me before you go wandering", "around in there.");
break;
case "crack":
if (player.getSkills().getLevel(Skills.THIEVING) < 50) {
player.getPacketDispatch().sendMessage("You need to be level " + level + " thief to crack this safe.");
return true;
}
if (player.getInventory().freeSlots() == 0) {
player.getPacketDispatch().sendMessage("Not enough inventory space.");
return true;
}
final boolean success = success(player, Skills.THIEVING);
player.lock(4);
player.getPacketDispatch().sendMessage("You start cracking the safe.");
player.animate(animations[success ? 1 : 0]);
GameWorld.getPulser().submit(new Pulse(3, player) {
@Override
public boolean pulse() {
if (success) {
handleSuccess(player, (Scenery) node);
return true;
}
final boolean trapped = RandomFunction.random(3) == 1;
if (trapped) {
player.getPacketDispatch().sendMessage("You slip and trigger a trap!");
player.animate(animations[2]);
player.getImpactHandler().manualHit(player, RandomFunction.random(2, 6), HitsplatType.NORMAL);
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
player.animate(new Animation(-1, Priority.HIGH));
return true;
}
});
}
return true;
}
});
break;
case "search":
player.animate(animations[3]);
player.getPacketDispatch().sendMessage("You temporarily disarm the trap!");
break;
}
return true;
}
/**
* Handles the success.
* @param player the player.
* @param object the object.
*/
public void handleSuccess(final Player player, final Scenery object) {
SceneryBuilder.replace(object, object.transform(CRACKED_SAFE), 1);
player.getPacketDispatch().sendMessage("You get some loot.");
player.getSkills().addExperience(Skills.THIEVING, experience, true);
addItem(player);
}
/**
* Adds an item.
* @param player the player.
*/
private void addItem(Player player) {
ChanceItem[] l = RandomFunction.random(2) == 1 ? GEMS : COINS;
List<ChanceItem> chances = new ArrayList<>(20);
for (ChanceItem c : l) {
chances.add(c);
}
Collections.shuffle(chances);
int rand = RandomFunction.random(100);
Item item = null;
int tries = 0;
while (item == null) {
ChanceItem i = chances.get(0);
if (rand <= i.getChanceRate()) {
item = i;
break;
}
if (tries > chances.size()) {
if (i.getId() == 1617) {
item = COINS[0];
break;
}
item = i;
break;
}
tries++;
}
player.getInventory().add(item);
}
/**
* Method used to determine the success of a player when thieving.
* @param player the player.
* @return <code>True</code> if succesfull, <code>False</code> if not.
*/
public final boolean success(final Player player, final int skill) {
double level = player.getSkills().getLevel(skill);
double req = 50;
int mod = player.getInventory().containsItem(SETHOSCOPE) ? 8 : 17;
double successChance = Math.ceil((level * 50 - req * mod) / req / 3 * 4);
int roll = RandomFunction.random(99);
if (successChance >= roll) {
return true;
}
return false;
}
}